Windows: SetWindowsHookExの奇妙な動作
受付中
回答 1
投稿
- 評価
- クリップ 3
- VIEW 9,595
Windowsの他のアプリ上でのマウス操作をフックするためにSetWindowsHookExを使用しています。
32bit Windows上では32bit版のDLLを作成し、その中でSetWindowsHookExを呼び出すことで期待した動作をすることができていました。
ところが、64bit Windows上で同様のことをやる場合、32bit版のDLLと64bit版のDLLを用意してそれぞれSetWindowsHookExを呼び出すわけですが、コールバックされた関数でGetCurrentProcessId()を使って確認すると、マウス操作をしているアプリのプロセスではなく、DLLをロードした実行ファイルのプロセスになってしまいます。
試しに64bit版DLLのSetWindowsHookExだけを外すと32bitアプリ上では期待通りの動作をします。
また逆に32bit版DLLのSetWindowsHookExだけを外すと64bitアプリ上では期待通りの動作をします。
つまり、64bit/32bit版それぞれのSetWindowsHookExがお互い干渉して期待した動作をしないような感じです。
それぞれのDLLは独立した実行ファイルからロードしたものなのでSetWindowsHookExが干渉することはありえないはずですが、これ以上どのように調べていったらいいのかお手上げ状態です。
詳しい方がいらっしゃいましたらご指導のほどよろしくお願いします。
32bit Windows上では32bit版のDLLを作成し、その中でSetWindowsHookExを呼び出すことで期待した動作をすることができていました。
ところが、64bit Windows上で同様のことをやる場合、32bit版のDLLと64bit版のDLLを用意してそれぞれSetWindowsHookExを呼び出すわけですが、コールバックされた関数でGetCurrentProcessId()を使って確認すると、マウス操作をしているアプリのプロセスではなく、DLLをロードした実行ファイルのプロセスになってしまいます。
試しに64bit版DLLのSetWindowsHookExだけを外すと32bitアプリ上では期待通りの動作をします。
また逆に32bit版DLLのSetWindowsHookExだけを外すと64bitアプリ上では期待通りの動作をします。
つまり、64bit/32bit版それぞれのSetWindowsHookExがお互い干渉して期待した動作をしないような感じです。
それぞれのDLLは独立した実行ファイルからロードしたものなのでSetWindowsHookExが干渉することはありえないはずですが、これ以上どのように調べていったらいいのかお手上げ状態です。
詳しい方がいらっしゃいましたらご指導のほどよろしくお願いします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+1
英語の方のSetWindowsHookExのRemarksにはまさにそのことが書かれています。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms644990(v=vs.85).aspx
グローバルフックといっても実際には各プロセスにDLLがインジェクションされるため相手のプロセスとフックのあるDLLのビット数が一致する必要があります。しかし、グローバルフックなのに相手都合でインジェクションされなかったらグローバルじゃねえじゃん、ということでビット数が一致しないプロセスの場合、フックをインストールしたスレッド上で実行されます。
相手のコンテキスト上で動く必要がないなら32ビットアプリのみ作ればOK、ただしスレッドのメッセージループ止めるなよ、ということみたいです。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms644990(v=vs.85).aspx
グローバルフックといっても実際には各プロセスにDLLがインジェクションされるため相手のプロセスとフックのあるDLLのビット数が一致する必要があります。しかし、グローバルフックなのに相手都合でインジェクションされなかったらグローバルじゃねえじゃん、ということでビット数が一致しないプロセスの場合、フックをインストールしたスレッド上で実行されます。
相手のコンテキスト上で動く必要がないなら32ビットアプリのみ作ればOK、ただしスレッドのメッセージループ止めるなよ、ということみたいです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.23%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2015/03/26 23:44
ご紹介いただいたURLはすでに確認してありますし、実際そのように実装・動作しています。
ただし、32bit/64bitの双方のDLLでSetWindowsHookExすると、コールバックされた関数ではDLLをロードしたプロセスのコンテキストになってしまいます。(ここだけがRemarksの内容と異なる)
ちなみにですが、
32bitアプリ上でマウス操作:どちらのコールバックもDLLをロードしたプロセスのコンテキスト
64bitアプリ上でマウス操作:64bit DLLのコールバックは対象アプリのコンテキスト、32bit側はDLLをロードしたプロセス
となっており、32bitアプリのときだけ奇妙な動作となってしまいます。
また、フックしたアプリのコンテキスト上で実行する必要があるため、32/64bit両方が必要になっています。
2015/03/27 02:54
32ビット、64ビットともにDLLを名前を変えて2つずつ作成して色々実験してみたら
以下のようなことがわかりました。
1. 32ビットのみ2つ立ち上げ
-> 32ビットアプリ上なら対象プロセス内でそれぞれのフックが呼び出される
-> 64ビットアプリ上ならフックアプリのどれかのプロセスで実行される
これは数を増やしても一緒
2. 64ビットのみ2つ立ち上げ
32ビットの反転バージョンで動作は同じ
3. 32ビットと64ビットを1つずつ立ち上げ
立ち上げる順番によって動作が変わる。
先に立ち上げたほうは常に自身のフックアプリのプロセス
後に立ち上げたほうはビット数のが同じなら対象プロセス内、違う場合はフックアプリ
4. 32ビットと64ビットをそれぞれ2つずつ立ち上げ
3と同じで最後に立ち上げた方のビット数と同じなら対象プロセス内、違う場合は同じビット数のフックアプリ
よって、
対象プロセスと最後に設定したフックのビット数が一致する場合は対象プロセス内で動く、
ですべて辻褄が合うようです。
自身以外のフックで経路が変わるのでグローバルフックで
すべてのコンテキストに、というのは難しそうですね…
2015/03/30 21:49
起動の順序にも依存するようですね。
その線でもう少し詳しく調べてみたいと思います。
ありがとうございます。