通常我们捕获键盘消息会在WindowProc函数种用一个switch来监听WM_KEYUP和WM_KEYDOWN消息,当按下键盘时程序就会收到这个消息。但是,有一个前提是当焦点是在当前窗口时,这个WM_KEYUP和WM_KEYDOWN消息才会被捕获到。如果我们需要在任何情况下使用这个应用程序捕获到键盘的动作就需要使用钩子。
Hook(钩子)是一种在消息到达目标窗口前进行截获的技术。使用钩子主要使用以下三个函数:
SetWindowsHookEx:创建钩子
CallNextHookEx:将消息传给钩子链中的下一个钩子
UnhookWindowsHookEx:释放钩子
这些函数在windows上面使用没有问题,但是函数说明中可以看到以下文字:Windows CE: Unsupported。也就是说,wince并不支持钩子。
是不是真的不支持呢?只能说不直接支持钩子,我们可以使用直接获取钩子函数地址,然后调用的方法,来使用钩子。
具体过程如下:
第一步:定义以上三个函数的指针
typedef LRESULT (WINAPI *_CallNextHookEx)(HHOOK, int, WPARAM, LPARAM);
typedef LRESULT (WINAPI *_UnhookWindowsHookEx)(HHOOK);
typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);
typedef HHOOK (WINAPI *_SetWindowsHookExW)(int, HOOKPROC, HINSTANCE, DWORD);
static _CallNextHookEx CallNextHookEx;
static _SetWindowsHookExW SetWindowsHookEx;
static _UnhookWindowsHookEx UnhookWindowsHookEx;
第二步:创建结构体,这个结构体是这API中的定义,我们只能照搬和使用它。
ypedef struct {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
第三步:创建钩子回调函数,我们将在这个函数里处理捕获到的键盘动作。代码如下。
LRESULT __declspec(dllexport)__stdcall CALLBACK KeyboardProc(int nCode,WPARAM wParam,
LPARAM lParam)
{
// char ch;
RETAILMSG(DEBUG_CODE,(L"进入KeyboardProc "));
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
if(wParam == WM_KEYUP)
{
RETAILMSG(DEBUG_CODE,(L"key up\n"));
switch(pkbhs->vkCode)
{
case 0x31:
RETAILMSG(DEBUG_CODE,(L"1 up \n"));
break;
case VK_F15:
RETAILMSG(DEBUG_CODE,(L"pTT up \n"));
break;
}
}
if(wParam == WM_KEYDOWN)
{
RETAILMSG(DEBUG_CODE,(L"key down\n"));
switch(pkbhs->vkCode)
{
case 0x31:
RETAILMSG(DEBUG_CODE,(L"1 down \n"));
break;
case VK_F15:
RETAILMSG(DEBUG_CODE,(L"pTT down \n"));
break;
}
}
// LRESULT RetVal = CallNextHookEx( NULL, nCode, wParam, lParam );
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
第四步:创建一个函数ActivateKBHook在这个函数中来使用钩子,当然也可以不在这个函数中使用,创建函数只是为了使代码可读性好一些。具体代码如下:
HINSTANCE g_hHookApiDLL = NULL;
HHOOK g_hInstalledLLKBDhook = NULL;
BOOL ActivateKBHook(HINSTANCE hInstance, HOOKPROC LLKeyboardHookCallbackFunction)
{
RETAILMSG(DEBUG_CODE,(L"进入ActivateKBHook\r\n"));
//we need to manually load these standard Win32 API calls
//MSDN states that these aren't supported in WinCE
SetWindowsHookEx = NULL;
CallNextHookEx = NULL;
UnhookWindowsHookEx = NULL;
//now load the coredll.dll
g_hHookApiDLL = LoadLibrary(_T("coredll.dll"));
if(g_hHookApiDLL == NULL)
{
//something is awfully wrong
//the dll has to be present
RETAILMSG(DEBUG_CODE,(L"载入coredll.dll失败\r\n"));
return false;
}
else
{
//load the SetWindowsHookEx API call
//the SetWindowsHookEx function installs an application-defined hook procedure into a hook chain.
//You would install a hook procedure to monitor the system for certain types of events.
//here we use use the hook to monitor kyeboard events
SetWindowsHookEx = (_SetWindowsHookExW)GetProcAddress(g_hHookApiDLL, _T("SetWindowsHookExW"));
if(SetWindowsHookEx == NULL)
{
//this means that MS has really stopped supporting this API in WinCE
RETAILMSG(DEBUG_CODE,(L"获取SetWindowsHookExW地址失败\r\n"));
return false;
}
else
{
//install the KB hook
//the hande needs to be saved for default processing of the events and to uninstall the hook, once we are done with it
g_hInstalledLLKBDhook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hInstance, 0);
if(g_hInstalledLLKBDhook == NULL)
{
int re;
re=GetLastError();
RETAILMSG(DEBUG_CODE,(L"SetWindowsHookEx失败 %d \r\n",re));
return false;
}
}
//load CallNextHookEx() API call
//the CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain.
//we use this call for default processing of events.
CallNextHookEx = (_CallNextHookEx)GetProcAddress(g_hHookApiDLL, _T("CallNextHookEx"));
if(CallNextHookEx == NULL)
{
RETAILMSG(DEBUG_CODE,(L"获取_CallNextHookEx地址失败\r\n"));
return false;
}
//load UnhookWindowsHookEx() API
//the UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.
//we use this call to unistall the hook.
UnhookWindowsHookEx = (_UnhookWindowsHookEx)GetProcAddress(g_hHookApiDLL, _T("UnhookWindowsHookEx"));
if(UnhookWindowsHookEx == NULL)
{
RETAILMSG(DEBUG_CODE,(L"获取_UnhookWindowsHookEx地址失败\r\n"));
return false;
}
}
//all the APIs are loaded and the application is hooked
return true;
}
几点说明:
1、CALLBACK KeyboardProc(int nCode,WPARAM wParam, LPARAM lParam)中,wParam得到的是按下的状态,例如是按下还是抬起,因此wParam会得到WM_KEYUP和WM_KEYDOWN消息。lParam得到的是具体按键的VK值,用来表明是哪个按键被按下。
2、这里使用的是全局钩子,如果有两个程序使用同样的方式创建钩子,那么只能有一个正常工作。这个问题将在后续的实验中说明。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lovelynn/archive/2008/12/23/3589633.aspx