Win2000SP4 VC++6.0です。
システムフックを利用してマウスとキー入力が
一定時間無かったらある処理を行うといった事をやりたいのです。
丁度スクリーンセーバのようなイメージです。
そこで次のようなプログラムを書きましたが
マウスやキー入力をしても入力のイベントが取得できませんでした。
GetMessage()の後のコメントにしてあるMessageBox()を有効にして
表示されたメッセージボックス上でマウスを動かしたらキー入力すると
イベントが取れるようなのでローカルフックになっているのではないかと
思っていますが原因が分かりません。
どうすれば入力をフックする事ができるか教えて頂けませんでしょうか?
よろしくお願いします。
--------------------------EXE------------------------------------
// TESTTimer.cpp : アプリケーション用のエントリ ポイントの定義
//
#include stdafx.h
#include windows.h
#include winuser.h
#include TESTTimer.h
UINT g_nIDEvent;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
// TODO: この位置にコードを記述してください。
HINSTANCE hDllInstance;
TESTSETHOOK SetHook; // 関数アドレス
// DLLを呼び出し側プロセスのアドレス空間内にマップする
hDllInstance = ::LoadLibrary(..\\TESTHook\\Debug\\TESTHook.dll);
if( hDllInstance != NULL )
{
// エクスポートされた関数のアドレスを取得
SetHook = (TESTSETHOOK)(::GetProcAddress
(hDllInstance, TESTSetHook));
if( SetHook != NULL )
{
SetHook(::GetCurrentThreadId());
}
}
// メッセージループ
MSG msg;
while(true)
{
g_nIDEvent = SetTimer(NULL, 0, 1000, TimerProc);
if (g_nIDEvent != 0)
{
::GetMessage(&msg, NULL, 0, 0);
// ::MessageBox(NULL,test,test,NULL);
switch(msg.message)
{
case WH_MOUSE:
case WH_KEYBOARD:
::OutputDebugString(Input Event
Occured\n);
break;
case WM_TIMER:
::OutputDebugString(TimeOut!!!\n);
break;
default :
::OutputDebugString(default\n);
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
void CALLBACK TimerProc(HWND hwnd , UINT uMsg ,UINT idEvent , DWORD dwTime) {
if (idEvent == g_nIDEvent)
{
KillTimer(hwnd, idEvent);
::OutputDebugString(timeout\n);
}
}
--------------------------DLL---------------------------------
// TESTHook.cpp : DLL アプリケーション用のエントリ ポイントを定義します。
//
#include stdafx.h
#define EXPORT extern C __declspec(dllexport)
#pragma data_seg(.TESTHOOK)
HHOOK hHookMouse = NULL;
HHOOK hHookKeyboard = NULL;
#pragma data_seg()
#pragma comment(linker, /SECTION:.TESTHOOK,RWS)
HINSTANCE g_hInst;
DWORD g_ThreadID;
BOOL WINAPI DllMain( HINSTANCE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
g_hInst = (HINSTANCE)hModule;
break;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
EXPORT void TESTSetHook(DWORD ThreadID)
{
::OutputDebugString(SetHook\n);
g_ThreadID = ThreadID;
hHookMouse = ::SetWindowsHookEx(WH_MOUSE, HookProcMouse, g_hInst, 0);
hHookKeyboard = ::SetWindowsHookEx(WH_KEYBOARD, HookProcKeyboard,
g_hInst, 0);
}
LRESULT CALLBACK HookProcMouse(int nCode, WPARAM wp, LPARAM lp) {
::OutputDebugString(hookmouse\n);
::PostThreadMessage(g_ThreadID, WH_MOUSE, wp, lp);
return CallNextHookEx(hHookMouse, nCode, wp, lp);
}
LRESULT CALLBACK HookProcKeyboard(int nCode, WPARAM wp, LPARAM lp) {
::OutputDebugString(hookkeyboad\n);
::PostThreadMessage(g_ThreadID, WH_KEYBOARD, wp, lp);
return CallNextHookEx(hHookKeyboard, nCode, wp, lp);
}
g_ThreadID が共有されていないのが原因でしょう。
それに、PostThreadMessage は、無関係のプロセスをまたいで使えません。
HookProcでnCodeが0以下の時は、CallNextHookExを返したほうがいいですよ。
それから、処理が終わったら、UnhookWindowsHookExをしたほうがいいと思います。
PostThreadMessageは使ったことが無いので分からないですが、ダイアログ等ならHWND
を共有化してSendMessegeやPostMessageでメッセージを送れますよ。
回答ありがとうございます。
フックプロシージャ内のOutputDebugStringで文字列が出力されていないので
フックされていないものと思われます。
最初の書き込みにもありますがメッセージボックス上でマウスを
動かしたりするとフックされます。
メッセージの投げ方も間違っているのかも知れませんが
まずはフックプロシージャが呼ばれないとそれも確認できません。
分かりにくくて申し訳ないです。
> フックプロシージャ内のOutputDebugStringで文字列が出力されていないので
> フックされていないものと思われます。
フックプロシージャは、フックしているアプリケーションの一部として動きます。
自分のアプリケーション以外は、デバッガ上で動いているわけではないので、
OutputDebugString の表示は得られません。
その他の手段で確認してみてください。
(ファイルに出力するなど)
返事遅くなってすいません。
ファイルに出力したらちゃんと処理されていました。
OutputDebugString、なるほど~と思いました。
すごい納得です。
自分のアプリケーションにメッセージやイベントを飛ばすのを
理解するには今回はちょっと時間が無いのでファイル経由で処理しようと思います。
ご協力本当にありがとうございました!!