HOOK - 低级鼠标Hook
这里使用的钩子类型idHook 是WH_MOUSE_LL。
在使用SetWindowsHook截获鼠标事件时,如果使用WH_MOUSE参数,则只能监控钩子所在模块的鼠标事件。
如需要截获整个系统的鼠标事件,那么使用WH_MOUSE_LL参数。
二、自定义消息通信
这里和参考的一样,将其写成MFC DLL然后使用导出函数。
通过发送消息SendMessage的方式,让dll和主程序进行通信(SendMessage 同步),
这里要注意使用的是自定义消息的方式来进行通信,就像IPC中的自定义消息一样,.dll与MFC中的消息定义必须完全一样:
1 //自定义消息,用于处理dll发来的消息 2 //该消息的定义和dll中定义的消息必须一样 3 #define WM_MOUSEMESSAGE WM_USER + 100
DLL部分代码:
.dll中
1 // 安装低级鼠标子函数,截获系统所有的鼠标消息 2 BOOL WINAPI StartHookMouse(HWND hwnd) 3 { 4 //这里自身的窗口句柄传过来 5 6 __hWnd = hwnd; 7 8 9 10 11 /* 12 在使用SetWindowsHook截获鼠标事件时,如果使用WH_MOUSE参数,则只能监控钩子所在模块的鼠标事件。 13 如需要截获整个系统的鼠标事件,那么使用WH_MOUSE_LL参数。 14 15 */ 16 __hhkMouse = SetWindowsHookEx( 17 WH_MOUSE_LL, 18 LowLevelMouseProc, 19 __hInstance, 20 0 21 ); 22 23 if (NULL == __hhkMouse) 24 { 25 return FALSE; 26 } 27 else 28 { 29 return TRUE; 30 } 31 32 }
1 // 定义低级鼠标子函数 2 LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) 3 { 4 // 有鼠标消息时,将其发给主程序 5 6 if (__hWnd != NULL && nCode == HC_ACTION)//HC_ACTION 有鼠标信息 7 { 8 //通知MFC 9 ::SendMessage(__hWnd, WM_MOUSEMESSAGE, wParam, lParam); 10 } 11 12 return CallNextHookEx(__hhkMouse, nCode, wParam, lParam); 13 14 }
然后,主程序收到该消息后,将其显示在程序界面上。
这边为了给主程序发送消息,在主程序调用安装鼠标钩子的函数时,我们需要将主窗口的句柄通过参数传递到dll中,这样我们就可以发送消息给主程序了。
三、共享代码段,所有线程共享
如果一个程序运行了两个实例,很遗憾,这两个程序的代码并不会共享,因为程序代码在程序运行时就被装载到内存,第二个程序再启动时,系统没法判断也不会判断这个程序是否还是原来的程序(如果程序被更新或更改),所以仍然会把程序代码重新加载到内存的另一块区域。
代码的共享体现应该是链接库
中,特别是动态链接库
中。因为库被设计成动态链接的,所以程序可以在运行后再确定代码所在的内存地址,这也就能实现多个程序调用同一块代码了。
1 // 共享代码段,所有线程共享 2 #pragma data_seg("SHARED") 3 static HHOOK __hhkMouse = NULL; // 鼠标钩子句柄 4 static HINSTANCE __hInstance = NULL; // 本DLL的实例句柄 5 static HWND __hWnd = NULL; // 调用DLL的主窗口句柄 6 #pragma data_seg() 7 #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)
----------------------------------------------------------------------------------------
使用函数:
1 HINSTANCE __hInstanceDll = NULL; 2 3 typedef BOOL (CALLBACK *StartHookMouse)(HWND hwnd); 4 typedef VOID (CALLBACK *StopHookMouse)();
1 //启动鼠标钩子 2 void CLowLevelHookMouseDlg::OnBnClickedButtonStarthook() 3 { 4 // TODO: 在此添加控件通知处理程序代码 5 __hInstanceDll = LoadLibrary(_T("HookDll.dll")); 6 if (__hInstanceDll == NULL) 7 { 8 ::MessageBox(NULL,(LPCTSTR)GetLastError(),L"LoadLibrary() Error",0); 9 return; 10 } 11 12 StartHookMouse StartHook; 13 StartHook = (StartHookMouse)::GetProcAddress( 14 __hInstanceDll, "StartHookMouse"); 15 if (StartHook == NULL) 16 { 17 ::MessageBox(NULL, (LPCTSTR)GetLastError(), L"GetProcAddress() Error", 0); 18 } 19 20 if (StartHook(this->m_hWnd)) 21 { 22 m_List.InsertItem(m_List.GetItemCount(), _T("0")); 23 m_List.SetItemText(m_List.GetItemCount() - 1, 1, _T("0")); 24 m_List.SetItemText(m_List.GetItemCount() - 1, 2, _T("启动鼠标钩子成功")); 25 26 CButton *pButton = (CButton *)GetDlgItem(IDC_BUTTON_STARTHOOK)->EnableWindow(FALSE); 27 28 CButton *Button = (CButton *)GetDlgItem(IDC_BUTTON_STOPHOOK)->EnableWindow(TRUE); 29 30 } 31 else 32 { 33 m_List.InsertItem(m_List.GetItemCount(), _T("0")); 34 m_List.SetItemText(m_List.GetItemCount() - 1, 1, _T("0")); 35 m_List.SetItemText(m_List.GetItemCount() - 1, 2, _T("启动鼠标钩子失败")); 36 } 37 } 38 39 //结束鼠标钩子 40 void CLowLevelHookMouseDlg::OnBnClickedButtonStophook() 41 { 42 // TODO: 在此添加控件通知处理程序代码 43 44 StopHookMouse StopHook; 45 __hInstanceDll = LoadLibrary(_T("HookDll.dll")); 46 if (__hInstanceDll == NULL) 47 { 48 ::MessageBox(NULL, (LPCTSTR)GetLastError(), L"LoadLibrary() Error", 0); 49 return; 50 } 51 52 StopHook = (StopHookMouse) ::GetProcAddress( 53 __hInstanceDll, "StopHookMouse"); 54 55 if (StopHook == NULL) 56 { 57 m_List.InsertItem(m_List.GetItemCount(), _T("0")); 58 m_List.SetItemText(m_List.GetItemCount() - 1, 1, _T("0")); 59 m_List.SetItemText(m_List.GetItemCount() - 1, 2, _T("获取函数 StopHookMouse 失败")); 60 61 return; 62 } 63 else 64 { 65 StopHook(); 66 m_List.InsertItem(m_List.GetItemCount(), _T("0")); 67 m_List.SetItemText(m_List.GetItemCount() - 1, 1, _T("0")); 68 m_List.SetItemText(m_List.GetItemCount() - 1, 2, _T("停止HOOKMOUSE成功")); 69 CButton *pButton = (CButton *)GetDlgItem(IDC_BUTTON_STOPHOOK)->EnableWindow(FALSE); 70 71 CButton *Button = (CButton *)GetDlgItem(IDC_BUTTON_STARTHOOK)->EnableWindow(TRUE); 72 73 } 74 75 if (__hInstanceDll != NULL) 76 { 77 ::FreeLibrary(__hInstanceDll); 78 } 79 80 // 确保list control 最后一行可见 跳转到stop那行 81 m_List.EnsureVisible(m_List.GetItemCount() - 1, FALSE); 82 83 }
六、最后
剩下的都是一些简单的实现了,这里觉得重要的写在了上面。其他的实现比较常规。
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
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 2025成都.NET开发者Connect圆满结束