ホームズ 。 しかし、私の友人、ワトソン、ウィンドウフック、特にグローバルフックの登録を解除したことがありますか?
ワトソン うーん...簡単にできることは、ホームズ。
::UnhookWindowsHookEx( hhookMy);
X わからない、ワトソン、わからない。 この呼び出しの後、フック関数を含むDLLモジュールは、それがロードされたすべてのプロセスにまだロードされています。 システムは、しばらくしてからこのDLLをアンロードします。 つまり、少なくとも1つのウィンドウメッセージが(そのようなキューを持つ)すべてのスレッドのメッセージキューを通過する瞬間です。 したがって、デスクトップ上のすべてのプロセスに対して。
B. ここ、すごい! ホームズ、私をからかっているの? これはUser32です。 Win32の主要部分の1つで、Windowsの他のすべてのテクノロジに依存しています。 たとえば、同じ.Net。 そして突然、これは完全に決定的な動作ではありません。
そして、たまたま
CreateFile
、たとえば、ファイルへの最初の書き込みまで、あまりにも遅延したファイルを作成しませんか? そして、たまたま
CreateProcess
は...
X いいえ、ワトソン、今回は冗談ではありません。
CreateFile
と
CreateProcess
はKernel32であり、まったく別の問題です。
私を信じて、バディ。 私は調査を実行して、User32モジュールの内部構造を研究するのに多くの時間を費やし、自信を持って言っています。著者はKernel32とはまったく異なる品質で作成(およびサポート)しました。
B. これは別の開発チームですか?
X はい、明らかにそうです。
B. おそらく、この動作はまだ正当化されています。 フックDLLがアンロードされるとき、それは本当に重要ですか?
X アプリケーションがインターネットを介して自身を更新し、再起動したと想像してください。 再起動後、一部のプロセスが古いバージョンのDLLをロードし、一部のプロセスが新しいバージョンをロードしたことがわかります。 この場合、メッセージがキューを通過しても、古いバージョンはアンロードされません。
B. なんて恐ろしいことでしょう!
しかし、ちょっと待ってください。 アプリケーションがファイルを更新した場合、フックDLLの古いバージョンの名前を変更したか、一時ディレクトリに移動したことを意味します。 次に、新しいバージョンが起動します...
SetWindowsHookEx
DLLアドレスに渡します。このファイルのパスは、あなたが言うように、ロードされたままのDLLとは異なります。
システムが
SetWindowsHookEx
に渡す間違ったDLLをターゲットとするフックを作成すると言いたいですか? ありえない!
X DLLがアンロードできなかったプロセスでは、これがまさに起こることです。調整されたキーボードを誓います。
どうやら、User32は、フックが最初に作成されたときにDLLが持っていたパスを内部的に保存します。 2回目の作成で、彼はこれが同じDLLであり、アンロードおよびリロードする必要がないと考えています。
B. うーん...そして、これはどうですか?
UnhookWindowsHookEx
後、ちょっと待ってください。 ウィンドウメッセージは頻繁に発生します。
X これは、ユーザーがウィンドウで何かをする場合です。 また、たとえば、最小化されたウィンドウは静かです。 メッセージが1秒以内に各キューに表示されるという保証はありません。 または1時間。
B. どうする? すべてのプロセスからDLLをアンロードすることが保証されている注文方法は?
(ホームズは沈黙し、喫煙します、ワトソンを見てください。)
B. ホームズ、あなたになります。 私はあなたがすでに状況から抜け出す正しい方法を考え出したと確信しています。 共有してください。
X フック関数が、特定のスレッドで初めて実行されていることを発見したら、特別な一時ファイルにファイルストリームを作成します。 そして、このスレッドの名前の右は、それが実行されるスレッドのIDを示します。 このようなもの:
using namespace std; namespace k = Kernel32; ... if( nullptr == tls_plistiterHookedThreadFileStreamHandle) // . { _listHookedThreadFileStreamHandles.push_front( k::CreateFile( k::FormatMessage( L"%1:%2!4u! %3!4u!", sHookedThreadListFilePath, k::GetCurrentThreadId(), k::GetCurrentProcessId() ), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE )); tls_plistiterHookedThreadFileStreamHandle = new list< HANDLE>::iterator( _listHookedThreadFileStreamHandles.begin()); }
次に、メインEXEはこれらのスレッド(
FindNextStream
)を
FindNextStream
し、User32がフックに関連付けた各スレッドに
WM_NULL
メッセージを送信できます。 その結果、User32はDLLをアンロードします。
DLL、アンロードは、リスト
_listHookedThreadFileStreamHandles
からすべての記述子を閉じる必要があります。
したがって、処理が完了したという良い基準も得られます-一時ファイルを削除しようとすると成功します。
B. ホームズ、なぜそんなに困るの? 引数
HWND_BROADCAST
持つ
SendMessage
があります。
X
SendMessage
は、キューを持つスレッドすべてにメッセージを送信するわけではありません。 ただし、おそらくこれも機能します。 ほとんど常に。
(叫び声)ハドソン夫人、お茶を出してください!
翌日
B. ある紳士のホームズは、少なくとも彼の場合、
SendMessage( HWND_BROADCAST)
は
SendMessage( HWND_BROADCAST)
ないと報告しました。
X うん