こんにちは。
マウスのクリックを監視して、クリックされた時アクティブなウィンドウにメッセージを送り、
規定の動作とは別の動作をさせるアプリを作っています。
(例えばクリックされたら、キーボードの'a'が押されたというメッセージを送るような)
考えている流れとしては、
dll : 1.SetWindowsHookExでマウスフックをかける
2.マウス動作メッセージがきたら exe にその旨ユーザー定義メッセージを送る
exe : 3.dllからメッセージがきたらアクティブなウィンドウのハンドルを取得して
そのウィンドウに向けて指定されたメッセージを送るです。
dll側からきたメッセージをexe側で受け取るところまではできたのですが、
その後アクティブなウィンドウへメッセージを送ることができません。
自分のウィンドウ内で行った動作については指定された動作をしてくれるのですが、
他アプリのウィンドウに対しては全く動いてくれません。
ちなみに、exeにメッセージを送らずにdll内で他ウィンドウにメッセージを送ってしまうと
正しく動作してくれました。
コードの一部です。
dll:
EXPORT LRESULT CALLBACK MouseHookProc( int nCode, WPARAM wp, LPARAM lp){
MOUSEHOOKSTRUCT *pmh;
pmh = ( MOUSEHOOKSTRUCT *)lp;
if ( nCode < 0)
return CallNextHookEx( hMouseHook, nCode, wp, lp);
switch( wp){
case WM_MBUTTONDOWN:
PostMessage( hWnd, WM_MDOWN, wp, lp); // hWnd : exeウィンドウのハンドル break;
}
return CallNextHookEx( hMouseHook, nCode, wp, lp);
}
exe:
BOOL CALLBACK MainDlgProc( HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam){
switch( Msg){
case WM_MDOWN:
hTarget = GetForegroundWindow( );
PostMessage( hTarget, WM_CLOSE, 0L, 0L);
return TRUE;
}
return FALSE;
}
マウスフックについては http://www.kumei.ne.jp/c_lang/sdk2/sdk_162.htmを参考にさせていただきました。
よろしくお願いします。
長文失礼しました。
書き忘れました。環境は
Windows2000 sp3 + VC++6.0 sp5 + SDK
です。
問題点は次のどちらでしょうか?
A) EXEにWM_MDOWNメッセージが飛んでこない
B) ターゲットにWM_CLOSEを投げているのに反応しない
また、PostMessageは(DLLとEXEの両方とも)正常に実行されていますか?
戻り値を調べてみてください。
dairygoodsさんありがとうございます。
問題点を整理すると、
dllでマウスフックをかけてマウスメッセージをつかむところまでは問題なしです。
その後、
exeにメッセージを送らずににdllから対象ウィンドウへWM_CLOSEなどのメッセージを送ると
問題なく動作します。
うまく動かないのはdllからexeへメッセージを送り、それを受けたexeが対象ウィンドウへ
WM_CLOSEなどのメッセージを送る場合です。
dll=>exeへメッセージを送ったときのPostMessageの戻り値は 1 で問題無しでした。
exe=>対象ウィンドウのときは、
1対象ウィンドウが自ウィンドウの場合: PoseMessageの戻り値は1で、問題なく動作します。
2対象ウィンドウが他のアプリの場合 : dllからメッセージがきていないようです
問題なのは上の 2 の場合で、exe「MainDlgProc」の case WM_MDOWN 内にブレークポイントを貼っても止まってくれません。
そのときdll側でも同じように、exeにメッセージを送るPostMessageにブレークポイントを貼っても止まってくれません。
しかし、dllがマウスメッセージをつかんでいないのかというと、前述したとおり
dllから対象ウィンドウ(自ウィンドウ、他アプリのウィンドウ)へ直接メッセージ(WM_CLOSEやWM_KEYDOWNなど)を送ったときは問題なく動作します。
となると問題なのは、
他のアプリのウィンドウ上でマウスイベントが発生したときにdllからexeへメッセージが送られていない、もしくはexeが受け取っていない、ということでしょうか。
自分でもどこが問題なのかはっきりわかっていない状態です。
また長文になってしまいました。どなたかよろしくお願いいたします。
> PostMessage( hWnd, WM_MDOWN, wp, lp); // hWnd : exeウィンドウのハンドル
フックDLLは、イベントをフックするプロセスのコンテキストで
呼び出されますが、このhWndは共有メモリ等を利用して
全てのDLLコンテキストで共有していますでしょうか?
dairygoodsさんありがとうございます。
exeウィンドウハンドルのhWndは、dllソースファイルで宣言されたグローバル変数で、
exe起動時にexeからdll内の関数を呼び出してコピーしています。
これが問題ということでしょうか。
このあたりはあまり理解していなかった部分でした。
#pragma data_seg(.hookdata)
HWND hWnd = NULL;
#pragma data_seg()
のようにする必要があるということでしょうか?
GetForegroundWindow が自スレッドが作ったウィンドウハンドルしか
返さないからだと思います
dll 側でGetForegroundWindow して
そのウィンドウハンドルを exe 側に渡すようにすればよいと思います
(というか、dll 側では GetForegroundWindow するまでもなく
フック関数に渡ってくるウィンドウハンドルですよね)
フックDLLは複数のEXEにロードされます。
そのときグローバル変数はそれぞれロードされたDLL間で
共有されることはありません。
(EXEを複数起動したときにグローバル変数が共有されないのと同じです)
#pragma data_seg(.hookdata)
HWND hWnd = NULL;
#pragma data_seg()
のようにセグメントを宣言し、DEFファイルで
SECTIONS
.hookdata READ WRITE SHARED
のように共有読み書き属性を付与します。
dairygoods さん、たみあさん、ありがとうございます。
まずdairygoods さんのおっしゃるとおりの方法で自ウィンドウのハンドルを
プロセス間で共有できるようにし、dllからメッセージを送る際にフック関数についてくる
対象ウィンドウのハンドルをいっしょに渡してやることで無事動いてくれました。
目的が達成されるにはまだまだ先が長そうですが、これでようやく前に進めそうです。
長文駄文にもかかわらずお付き合いくださいましてありがとうございました。