B(ug)log

開発とかぼやきとかLINEスタンプとか http://line.me/S/sticker/1245783 職探し中

マルチスレッドでグローバルフックするときの注意

今日のキーワード:

  • SetWindowsHookExWH_KEYBOARD_LL(WH_MOUSE_LL)
  • マルチスレッド
  • グローバルフック

やりたいこと

メインの UI スレッドとは別スレッドでグローバルフックしたい。

例えば、描画の処理が重い場合、UI スレッドがそちらの処理で手間取り、キーボードやマウスの入力を処理できなくなる可能性があります。そういった場合、別スレッドでキーボード等での入力処理を取り扱いたくなります。

結論から

UI スレッド以外で、SetWindowsHookEx を呼び出すときは注意が必要ですよ、というお話。

Why? なぜなのか

This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

LowLevelKeyboardProc callback function (Windows) より

低レベルキーボードフック (WH_KEYBOARD_LL) を使用する場合、SetWindowsHookEx を呼びだすスレッドは、メッセージループを持っていなきゃ駄目という記載が MSDN にあります。

これを忘れていて僕はドハマりしました……。SetWindowsHookEx が失敗する?エラー?なんでだ?で数時間悩みました。

How? どうやって対処するのか

別スレッドにメッセージループを持たせて、別 UI スレッドにしちゃいましょう。C# (というか .NET系)の場合、以下のページが参考になります。

メッセージループをアプリケーション内で複数作ってみる - 亀岡的プログラマ日記

メッセージループを持つスレッドが複数ある状態になりますが、場合によっては効果的だと思います。先程の例であれば、描画に専念する UI スレッドと、入力に対する処理に専念する UI スレッドのように専業化し、そのメリット、デメリットを考えて、有効なら取り入れるという形ですかね。UIAssistant には取り入れて入力のレスポンスをよくする予定です。