描述一下问题先:
我需要用全局Hook来监控鼠标,键盘事件,还要监控菜单的选择操作。于是我做了这样几件事情:首先我写了一个C++ 的DLL,主要的函数是安装钩子,卸载钩子,设置用户回调函数。内部使用一个外部回调函数的三个实例,另外再写三个内部回调函数,对应三个Hook(都是全局的),一个是WH_KEYBOARD_LL,一个是WH_MOUSE_LL,一个是WH_CALLWNDPROC(第三个是监控菜单的,分析lParam参数当消息是WM_MENUSELECT时,就是菜单选择事件)。接下来要做的事情是,首先是在外部定义回调函数,将函数指针设置到DLL内部,然后InstallHook,安装Hook中使用的回调函数是DLL内部回调函数,在内部回调函数中调用外部回调函数。先来点关键代码首先是安装钩子:
bool InitializeHook(UINT hookID, int threadID)
{
if (g_appInstance == NULL)
{
return false;
}
if (hookID == WH_KEYBOARD_LL)
{
if (UserKeyboardHookCallback == NULL)
{
return false;
}
hookKeyboard = SetWindowsHookEx(hookID, (HOOKPROC)InternalKeyboardHookCallback, g_appInstance, threadID);
return hookKeyboard != NULL;
}
else if (hookID == WH_MOUSE_LL)
{
if (UserMouseHookCallback == NULL)
{
return false;
}
hookMouse = SetWindowsHookEx(hookID, (HOOKPROC)InternalMouseHookCallback, g_appInstance, threadID);
return hookMouse != NULL;
}
else if (hookID == WH_CALLWNDPROC)
{
if (UserMenuHookCallback == NULL)
{
return false;
}
hookMenu = SetWindowsHookEx(hookID, (HOOKPROC)InternalMenuHookCallback, g_appInstance, threadID);
return hookMenu != NULL;
}
return false;
}对应三个内部回调函数的实现:
static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookMouse, code, wparam, lparam);
}
if (UserMouseHookCallback != NULL && !mouseFilter.IsFiltered((int)wparam))
{
UserMouseHookCallback(code, wparam, lparam);
}
return CallNextHookEx(hookMouse, code, wparam, lparam);
}static LRESULT CALLBACK InternalKeyboardHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookKeyboard, code, wparam, lparam);
}
if (UserKeyboardHookCallback != NULL && !keyboardFilter.IsFiltered((int)wparam))
{
UserKeyboardHookCallback(code, wparam, lparam);
}
return CallNextHookEx(hookKeyboard, code, wparam, lparam);
}static LRESULT CALLBACK InternalMenuHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookMenu, code, wparam, lparam);
}
if(((CWPSTRUCT*)lparam)->message == WM_MENUSELECT)
{
if (UserKeyboardHookCallback != NULL && !menuFilter.IsFiltered((int)WM_MENUSELECT))
{
UserMenuHookCallback(code, wparam, lparam);
}
} return CallNextHookEx(hookMenu, code, wparam, lparam);
}最后是设置外部回调函数的地方:
static LRESULT CALLBACK InternalKeyboardHookCallback(int code, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK InternalMenuHookCallback(int code, WPARAM wparam, LPARAM lparam);int SetUserHookCallback(HookProc userProc, UINT hookID)
{
if (userProc == NULL)
{
return HookCoreErrors::SetCallBack::ARGUMENT_ERROR;
}
if (hookID == WH_KEYBOARD_LL)
{
if (UserKeyboardHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserKeyboardHookCallback = userProc;
keyboardFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
else if (hookID == WH_MOUSE_LL)
{
if (UserMouseHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserMouseHookCallback = userProc;
mouseFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
else if (hookID == WH_CALLWNDPROC)
{
if (UserMenuHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserMenuHookCallback = userProc;
menuFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
return HookCoreErrors::SetCallBack::NOT_IMPLEMENTED;
}好了,问题出来了,鼠标事件和键盘事件可以正确被Hook(这里是指外部回调函数被执行),但是菜单事件发生的时候,内部回调函数被执行了,外部回调函数却不被执行,我一查,原来InternalMenuHookCallback函数是被调用了,但是if (UserKeyboardHookCallback != NULL && !menuFilter.IsFiltered((int)WM_MENUSELECT))判断的结果是false,原来UserKeyboardHookCallback != NULL通不过,我没有释放UserKeyboardHookCallback对应的外部调用,并且我做了另外一个尝试:将InternalKeyboardHookCallback函数中的“if (UserKeyboardHookCallback != NULL && !keyboardFilter.IsFiltered((int)wparam))”这句话换成
“if (UserMenuHookCallback != NULL && !keyboardFilter.IsFiltered((int)wparam))”键盘事件发生的时候外部回调函数也能被调用,然后我又试验发现,在InternalKeyboardHookCallback函数中判断UserKeyboardHookCallback != NULL和UserMenuHookCallback != NULL,结果都是true,(我猜测在InternalMouseHookCallback函数中也是这样),但是在InternalMenuHookCallback函数中判断UserKeyboardHookCallback != NULL和UserMenuHookCallback != NULL,结果都是false,如果不判断就执行UserMenuHookCallback(code, wparam, lparam);这句,就会报指针操作异常。好了,问题描述好了,谁能知道为什么?是WH_CALLWNDPROC和WH_MOUSE_LL,WH_KEYBOARD_LL的差别造成的吗?
我需要用全局Hook来监控鼠标,键盘事件,还要监控菜单的选择操作。于是我做了这样几件事情:首先我写了一个C++ 的DLL,主要的函数是安装钩子,卸载钩子,设置用户回调函数。内部使用一个外部回调函数的三个实例,另外再写三个内部回调函数,对应三个Hook(都是全局的),一个是WH_KEYBOARD_LL,一个是WH_MOUSE_LL,一个是WH_CALLWNDPROC(第三个是监控菜单的,分析lParam参数当消息是WM_MENUSELECT时,就是菜单选择事件)。接下来要做的事情是,首先是在外部定义回调函数,将函数指针设置到DLL内部,然后InstallHook,安装Hook中使用的回调函数是DLL内部回调函数,在内部回调函数中调用外部回调函数。先来点关键代码首先是安装钩子:
bool InitializeHook(UINT hookID, int threadID)
{
if (g_appInstance == NULL)
{
return false;
}
if (hookID == WH_KEYBOARD_LL)
{
if (UserKeyboardHookCallback == NULL)
{
return false;
}
hookKeyboard = SetWindowsHookEx(hookID, (HOOKPROC)InternalKeyboardHookCallback, g_appInstance, threadID);
return hookKeyboard != NULL;
}
else if (hookID == WH_MOUSE_LL)
{
if (UserMouseHookCallback == NULL)
{
return false;
}
hookMouse = SetWindowsHookEx(hookID, (HOOKPROC)InternalMouseHookCallback, g_appInstance, threadID);
return hookMouse != NULL;
}
else if (hookID == WH_CALLWNDPROC)
{
if (UserMenuHookCallback == NULL)
{
return false;
}
hookMenu = SetWindowsHookEx(hookID, (HOOKPROC)InternalMenuHookCallback, g_appInstance, threadID);
return hookMenu != NULL;
}
return false;
}对应三个内部回调函数的实现:
static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookMouse, code, wparam, lparam);
}
if (UserMouseHookCallback != NULL && !mouseFilter.IsFiltered((int)wparam))
{
UserMouseHookCallback(code, wparam, lparam);
}
return CallNextHookEx(hookMouse, code, wparam, lparam);
}static LRESULT CALLBACK InternalKeyboardHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookKeyboard, code, wparam, lparam);
}
if (UserKeyboardHookCallback != NULL && !keyboardFilter.IsFiltered((int)wparam))
{
UserKeyboardHookCallback(code, wparam, lparam);
}
return CallNextHookEx(hookKeyboard, code, wparam, lparam);
}static LRESULT CALLBACK InternalMenuHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookMenu, code, wparam, lparam);
}
if(((CWPSTRUCT*)lparam)->message == WM_MENUSELECT)
{
if (UserKeyboardHookCallback != NULL && !menuFilter.IsFiltered((int)WM_MENUSELECT))
{
UserMenuHookCallback(code, wparam, lparam);
}
} return CallNextHookEx(hookMenu, code, wparam, lparam);
}最后是设置外部回调函数的地方:
static LRESULT CALLBACK InternalKeyboardHookCallback(int code, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam);
static LRESULT CALLBACK InternalMenuHookCallback(int code, WPARAM wparam, LPARAM lparam);int SetUserHookCallback(HookProc userProc, UINT hookID)
{
if (userProc == NULL)
{
return HookCoreErrors::SetCallBack::ARGUMENT_ERROR;
}
if (hookID == WH_KEYBOARD_LL)
{
if (UserKeyboardHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserKeyboardHookCallback = userProc;
keyboardFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
else if (hookID == WH_MOUSE_LL)
{
if (UserMouseHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserMouseHookCallback = userProc;
mouseFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
else if (hookID == WH_CALLWNDPROC)
{
if (UserMenuHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserMenuHookCallback = userProc;
menuFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
return HookCoreErrors::SetCallBack::NOT_IMPLEMENTED;
}好了,问题出来了,鼠标事件和键盘事件可以正确被Hook(这里是指外部回调函数被执行),但是菜单事件发生的时候,内部回调函数被执行了,外部回调函数却不被执行,我一查,原来InternalMenuHookCallback函数是被调用了,但是if (UserKeyboardHookCallback != NULL && !menuFilter.IsFiltered((int)WM_MENUSELECT))判断的结果是false,原来UserKeyboardHookCallback != NULL通不过,我没有释放UserKeyboardHookCallback对应的外部调用,并且我做了另外一个尝试:将InternalKeyboardHookCallback函数中的“if (UserKeyboardHookCallback != NULL && !keyboardFilter.IsFiltered((int)wparam))”这句话换成
“if (UserMenuHookCallback != NULL && !keyboardFilter.IsFiltered((int)wparam))”键盘事件发生的时候外部回调函数也能被调用,然后我又试验发现,在InternalKeyboardHookCallback函数中判断UserKeyboardHookCallback != NULL和UserMenuHookCallback != NULL,结果都是true,(我猜测在InternalMouseHookCallback函数中也是这样),但是在InternalMenuHookCallback函数中判断UserKeyboardHookCallback != NULL和UserMenuHookCallback != NULL,结果都是false,如果不判断就执行UserMenuHookCallback(code, wparam, lparam);这句,就会报指针操作异常。好了,问题描述好了,谁能知道为什么?是WH_CALLWNDPROC和WH_MOUSE_LL,WH_KEYBOARD_LL的差别造成的吗?
后来将WH_CallWndProc Hook换成了 WH_MSGFILTER Hook,但是还是一样的问题,回调被执行,但是用户自定义回调还是为NULL
Hook可以加载多个不冲突,捕获到了那个事件了,只是在调用外部回调函数的时候发现那个没有了
我使用的都是全局Hook,不知道这个会不会有问题