LoginSignup
7
13

More than 3 years have passed since last update.

Windowsのフックのはまりどころ備忘録

Last updated at Posted at 2019-09-19

WindowsのHookが不安定になる原因

※勉強中。対策までには至っていないのであしからず。

  1. ローカルHookになっている(DLLにしていない)
    スレッドの管理の問題で、DLLにする必要があるらしい。
    ここもよさそう
    なお、WH_KEYBOARD_LLはDLLにしなくてよいらしい。だたしメッセージループを持つことが必要。
    https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v%3Dvs.85)#remarks
    http://blog.mikage.to/mika/2005/07/windows_3805.html

  2. 32bit 64bitの片方しかhookしていない
    公式による。よく読んでいないが32bitと64bitは別扱いのようです。両方Hookしろということっぽい?
    ここらへんがよさそう ttp://uisteven.blog.fc2.com/blog-entry-3.html左記のサイトの中のリンクがウイルスサイトくさい。

  3. GC(ガベージコレクト)されてしまっている(GCがある言語特有)
    Hookのハンドルと、Hookに登録したProcはGCされないような工夫が必要。
    C#では、とりあえずメンバ宣言しておく。そのインスタンスも何かから参照されている状態にする必要があるかと。
    (Hookのハンドルのほうは、UnHookするのに使うのでうっかりGCされることはないと思うが、Procはやりがち。)

  4. SendKeys, SendInput, SendMessage, PostMessageなどと併用している
    メッセージキューに積みすぎたり、送ったメッセージを再度Hookして無限ループしたり。とりあえずSendKeysタイミングが安定しないと公式が言っているようなのでやめたほうがよさげ。

  5. SetWindowsHookEx に失敗している
    対応としてはまず GetLastError (C#/VB.NET : Marshal.GetLastWin32Error)のエラーコードを調べる。
    参考サイト(C#/VB.NETでのGetLastErrorの呼び出し): https://www.atmarkit.co.jp/fdotnet/dotnettips/740win32errcode/win32errcode.html
    参考サイト(エラーコード一覧): http://ir9.jp/prog/ayu/win32err.htm

    エラーコードが 0x7E (ERROR_MOD_NOT_FOUND)であれば、おそらく下記に該当している。
    自身のプロセスから自身のHookを登録するときはhMod は NULL (IntPtr.Zero) にする必要があるらしい(?)
    参考: https://stackoverflow.com/questions/2774741/module-not-found

  6. 他言語から使うときにミスっている
    C#にて、Win32のドキュメント上のハンドル類が値NULLとなる場合はIntPtr.Zeroに置き換えるケースが多いが、うっかり null にしてしまっているなど。コードによってはコンパイルが通るので気づきにくい。

  7. コールバック関数を実行するスレッドをブロックしてしまっている(未検証)
    Formの初期化とかでフックすると、UIスレッドと同じスレッドでフックのコールバック処理が実行される。UIのイベント処理内で重い処理やユーザ操作待ちなどをすると、フックのコールバックが待たされてハマるかも。
    スレッドIDの調べ方:Console.WriteLine("ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());

キーボードのフックについて

  1. コールバック関数の処理時間が長すぎる(タイムアウトしている)
    公式によるとWM_KEYBOARD_LLはタイムアウト時間が設定されており、超過すると勝手にHookが外されるらしい。外されたことを検出する有効な手段はないらしい。ほかのHookはどうなのか知らない。。
    同ページの説明によるとタイムアウト時間はレジストリ設定(LowLevelHooksTimeout)によるらしいが、自分の環境では該当のレジストリキーが見つけられなかった。

    デフォルトは300msっぽい。10回超えるとダメらしい。あと、原理的に回避不可能なのではないか?:
    参考サイト: https://nazochu.blogspot.com/2011/08/windows7.html
    https://blogs.msdn.microsoft.com/alejacma/2010/10/14/global-hooks-getting-lost-on-windows-7/

  2. 「Fn」キーを取ろうとしている
    「Fn」キーはOSが受け付けないらしい。

  3. 「Alt」キーを拾いそこねている
    WM_SYSKEYDOWNを見ていない。

  4. WM_KEYDOWNWM_KEYUPをペアで処置できていない
    ・・・というか原理的に無理かもしれないが。

マウスのフック(WH_MOUSE_LL)について

  1. 座標のスケーリングが異なる
    lParamで得られるマウス座標は高解像度対応版の座標らしい。ここ参照
    LowLevelMouseProc callback functionMSLLHOOKSTRUCT
    > The x- and y-coordinates of the cursor, in per-monitor-aware screen coordinates.
7
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
13