WindowsのHookが不安定になる原因
※勉強中。対策までには至っていないのであしからず。
-
ローカル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 -
32bit 64bitの片方しかhookしていない
公式による。よく読んでいないが32bitと64bitは別扱いのようです。両方Hookしろということっぽい?
ここらへんがよさそう ttp://uisteven.blog.fc2.com/blog-entry-3.html左記のサイトの中のリンクがウイルスサイトくさい。 -
GC(ガベージコレクト)されてしまっている(GCがある言語特有)
Hookのハンドルと、Hookに登録したProcはGCされないような工夫が必要。
C#では、とりあえずメンバ宣言しておく。そのインスタンスも何かから参照されている状態にする必要があるかと。
(Hookのハンドルのほうは、UnHookするのに使うのでうっかりGCされることはないと思うが、Procはやりがち。) -
SendKeys,SendInput,SendMessage,PostMessageなどと併用している
メッセージキューに積みすぎたり、送ったメッセージを再度Hookして無限ループしたり。とりあえずSendKeysはタイミングが安定しないと公式が言っているようなのでやめたほうがよさげ。 -
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 -
他言語から使うときにミスっている
C#にて、Win32のドキュメント上のハンドル類が値NULLとなる場合はIntPtr.Zeroに置き換えるケースが多いが、うっかりnullにしてしまっているなど。コードによってはコンパイルが通るので気づきにくい。 -
コールバック関数を実行するスレッドをブロックしてしまっている(未検証)
Formの初期化とかでフックすると、UIスレッドと同じスレッドでフックのコールバック処理が実行される。UIのイベント処理内で重い処理やユーザ操作待ちなどをすると、フックのコールバックが待たされてハマるかも。
スレッドIDの調べ方:Console.WriteLine("ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
キーボードのフックについて
-
コールバック関数の処理時間が長すぎる(タイムアウトしている)
公式によると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/ -
「Fn」キーを取ろうとしている
「Fn」キーはOSが受け付けないらしい。 -
「Alt」キーを拾いそこねている
WM_SYSKEYDOWNを見ていない。 -
WM_KEYDOWNとWM_KEYUPをペアで処置できていない
・・・というか原理的に無理かもしれないが。
マウスのフック(WH_MOUSE_LL)について
-
座標のスケーリングが異なる
lParamで得られるマウス座標は高解像度対応版の座標らしい。ここ参照
LowLevelMouseProc callback function
⇒ MSLLHOOKSTRUCT
The x- and y-coordinates of the cursor, in per-monitor-aware screen coordinates.