exeからdllのSetWindowsHookEx(WH_GETMESSAGE...を呼び出す関数を呼び、
メッセージをグローバルフックしています。
テスト用に、dll側に以下のようなフックプロシージャを作りました。
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
MSG* pMsg = (MSG*)lParam;
// exeからのメッセージ
if (pMsg->message == RegisterWindowMessage(TEXT(test)))
{
MessageBeep(MB_OK | MB_ICONWARNING);
Sleep(500);
}
// マウスホイール
if (pMsg->message == WM_MOUSEWHEEL)
{
MessageBeep(MB_OK | MB_ICONWARNING);
Sleep(500);
}
}
return CallNextHookEx(g_hHookGetMsg, nCode, wParam, lParam);
}
exe側では、特定のホットキーが押された際に、
GetForegroundWindowで取得したアクティブなウィンドウに、
RegisterWindowMessage(TEXT(test)) を、PostMessageで送信するようにしています。
問題なく動いているようなのですが、特定のアプリケーションで同じメッセージが2回
きます。
例えば、Visual Studio 環境をアクティブにし、ホットキーを押したり、ホイールを回
転させると、
同じメッセージが2回もダブって届くのです。
MSG構造体、dllのインスタンスハンドル、モジュールハンドルなど、2回ともまったく
同じままです。
メッセージ受け取った後、CallNextHookExを呼ばずにreturn 0 などとしてもだめでし
た。
Visual Studio 以外では、自作のDirect3Dアプリケーションで、フルスクリーン時にの
み再現しました。
他、フリーソフトのPaint.NET 3.36でも確認。
これらの原因、または解決策をご存知の方おられませんでしょうか?
よろしくお願いします。
環境 Windows XP SP3 / Visual Studio 2005 Standard SP1 / Visual C++
なぜでしょうね。
確認をしていませんが、もし
・APP側で、PM_NOREMOVEフラグ付きでPeekMessageを発行している
・PM_NOREMOVEでPeekMessageを発行した場合でも
フック側プロシージャが呼ばれる
という仕様であれば、2回プロシージャが呼ばれることになるとは思います。
MSDNには
> The system calls this function whenever the GetMessage or PeekMessage
> function has retrieved a message from an application message
とあります。
あと、掲載コードはテスト用かもしれませんが
フックプロシージャ側で、500msも待たすのはよくなかったような。。
お返事ありがとうございます。
浩二さんのご指摘通りでした。
フックプロシージャのwParamを調べてみたところ、
1度目はPM_NOREMOVE
2度目はPM_REMOVE
がセットされていました。
このあたりも見落としなく調べたつもりだったんですが、
未チェックだったようです。
> フックプロシージャ側で、500msも待たすのはよくなかったような。。
フックプロシージャが他のモジュールから呼ばれてくるため、
ブレークポイントもOutputDebugStringも利かないため、
2度呼ばれていることを簡単に検出するための苦肉の策でした。
3日ほど試行錯誤しても解決できなかったので、質問して良かったです。
どうもありがとうございました。
アプリ側が2回 DispatchMessage をコールしたら、
フックプロシージャも2回呼ばれるんだろうな、
と思うけど...
うぁ、7分前。orz...