这里使用的钩子类型idHook 是WH_MOUSE_LL。
在使用SetWindowsHook截获鼠标事件时,如果使用WH_MOUSE参数,则只能监控钩子所在模块的鼠标事件。
如需要截获整个系统的鼠标事件,那么使用WH_MOUSE_LL参数。
二、自定义消息通信
这里和参考的一样,将其写成MFC DLL然后使用导出函数。
通过发送消息SendMessage的方式,让dll和主程序进行通信(SendMessage 同步),
这里要注意使用的是自定义消息的方式来进行通信,就像IPC中的自定义消息一样,.dll与MFC中的消息定义必须完全一样:
//自定义消息,用于处理dll发来的消息
//该消息的定义和dll中定义的消息必须一样
#define WM_MOUSEMESSAGE WM_USER + 100
DLL部分代码:
.dll中
// 安装低级鼠标子函数,截获系统所有的鼠标消息
BOOL WINAPI StartHookMouse(HWND hwnd)
{
//这里自身的窗口句柄传过来 __hWnd = hwnd; /*
在使用SetWindowsHook截获鼠标事件时,如果使用WH_MOUSE参数,则只能监控钩子所在模块的鼠标事件。
如需要截获整个系统的鼠标事件,那么使用WH_MOUSE_LL参数。 */
__hhkMouse = SetWindowsHookEx(
WH_MOUSE_LL,
LowLevelMouseProc,
__hInstance, ); if (NULL == __hhkMouse)
{
return FALSE;
}
else
{
return TRUE;
} }
// 定义低级鼠标子函数
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// 有鼠标消息时,将其发给主程序 if (__hWnd != NULL && nCode == HC_ACTION)//HC_ACTION 有鼠标信息
{
//通知MFC
::SendMessage(__hWnd, WM_MOUSEMESSAGE, wParam, lParam);
} return CallNextHookEx(__hhkMouse, nCode, wParam, lParam); }
然后,主程序收到该消息后,将其显示在程序界面上。
这边为了给主程序发送消息,在主程序调用安装鼠标钩子的函数时,我们需要将主窗口的句柄通过参数传递到dll中,这样我们就可以发送消息给主程序了。
三、共享代码段,所有线程共享
如果一个程序运行了两个实例,很遗憾,这两个程序的代码并不会共享,因为程序代码在程序运行时就被装载到内存,第二个程序再启动时,系统没法判断也不会判断这个程序是否还是原来的程序(如果程序被更新或更改),所以仍然会把程序代码重新加载到内存的另一块区域。
代码的共享体现应该是链接库
中,特别是动态链接库
中。因为库被设计成动态链接的,所以程序可以在运行后再确定代码所在的内存地址,这也就能实现多个程序调用同一块代码了。
// 共享代码段,所有线程共享
#pragma data_seg("SHARED")
static HHOOK __hhkMouse = NULL; // 鼠标钩子句柄
static HINSTANCE __hInstance = NULL; // 本DLL的实例句柄
static HWND __hWnd = NULL; // 调用DLL的主窗口句柄
#pragma data_seg()
#pragma comment(linker,"/section:SHARED,rws")
四、卸载hook
// 卸载低级鼠标钩子
VOID WINAPI StopHookMouse()
{
if (__hhkMouse != NULL)
{
::UnhookWindowsHookEx(__hhkMouse);
}
}
/***********************************/
五、MFC中的自定义消息
首先必须得和dll中的完全一样,定义一个自定义消息,必须完全一样
(这里可以参考博客http://www.cnblogs.com/hcxblog/archive/2012/10/02/2710261.html)
然后要写自定义消息的三句话:
1.消息映射
2.消息处理函数的声明
3.消息处理函数的实现
ON_MESSAGE(WM_MOUSEMESSAGE, &CLowLevelHookMouseDlg::OnMouseMessage) //消息映射 afx_msg LRESULT OnMouseMessage(WPARAM wParam, LPARAM lParam); LRESULT CLowLevelHookMouseDlg::OnMouseMessage(
WPARAM wParam, LPARAM lParam)
----------------------------------------------------------------------------------------
使用函数:
HINSTANCE __hInstanceDll = NULL; typedef BOOL (CALLBACK *StartHookMouse)(HWND hwnd);
typedef VOID (CALLBACK *StopHookMouse)();
//启动鼠标钩子
void CLowLevelHookMouseDlg::OnBnClickedButtonStarthook()
{
// TODO: 在此添加控件通知处理程序代码
__hInstanceDll = LoadLibrary(_T("HookDll.dll"));
if (__hInstanceDll == NULL)
{
::MessageBox(NULL,(LPCTSTR)GetLastError(),L"LoadLibrary() Error",);
return;
} StartHookMouse StartHook;
StartHook = (StartHookMouse)::GetProcAddress(
__hInstanceDll, "StartHookMouse");
if (StartHook == NULL)
{
::MessageBox(NULL, (LPCTSTR)GetLastError(), L"GetProcAddress() Error", );
} if (StartHook(this->m_hWnd))
{
m_List.InsertItem(m_List.GetItemCount(), _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T("启动鼠标钩子成功")); CButton *pButton = (CButton *)GetDlgItem(IDC_BUTTON_STARTHOOK)->EnableWindow(FALSE); CButton *Button = (CButton *)GetDlgItem(IDC_BUTTON_STOPHOOK)->EnableWindow(TRUE); }
else
{
m_List.InsertItem(m_List.GetItemCount(), _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T("启动鼠标钩子失败"));
}
} //结束鼠标钩子
void CLowLevelHookMouseDlg::OnBnClickedButtonStophook()
{
// TODO: 在此添加控件通知处理程序代码 StopHookMouse StopHook;
__hInstanceDll = LoadLibrary(_T("HookDll.dll"));
if (__hInstanceDll == NULL)
{
::MessageBox(NULL, (LPCTSTR)GetLastError(), L"LoadLibrary() Error", );
return;
} StopHook = (StopHookMouse) ::GetProcAddress(
__hInstanceDll, "StopHookMouse"); if (StopHook == NULL)
{
m_List.InsertItem(m_List.GetItemCount(), _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T("获取函数 StopHookMouse 失败")); return;
}
else
{
StopHook();
m_List.InsertItem(m_List.GetItemCount(), _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T(""));
m_List.SetItemText(m_List.GetItemCount() - , , _T("停止HOOKMOUSE成功"));
CButton *pButton = (CButton *)GetDlgItem(IDC_BUTTON_STOPHOOK)->EnableWindow(FALSE); CButton *Button = (CButton *)GetDlgItem(IDC_BUTTON_STARTHOOK)->EnableWindow(TRUE); } if (__hInstanceDll != NULL)
{
::FreeLibrary(__hInstanceDll);
} // 确保list control 最后一行可见 跳转到stop那行
m_List.EnsureVisible(m_List.GetItemCount() - , FALSE); }
六、最后
剩下的都是一些简单的实现了,这里觉得重要的写在了上面。其他的实现比较常规。
1.其中有两个checkbox的实现做了发现没有达到想要的效果就废掉了。
2.还有就是源博主中如果多点了几次hook,在unhook的时候会出问题,所以这里
CButton *pButton = (CButton *)GetDlgItem(IDC_BUTTON_STOPHOOK)->EnableWindow(FALSE);
Ring3 x86 x64 通过.
以上就是本次的一个小总结,如有不妥还请批评指正。
再次感谢。
代码:
链接:http://pan.baidu.com/s/1dEPx03J 密码:y463
IPC自定义消息代码:
链接:http://pan.baidu.com/s/1o795ZRW 密码:dt6p