mfc中钩子的使用

2023-05-16

钩子的安装与卸载

  系统是通过调用位于钩子链表最开始处的钩子函数而进行消息拦截处理的,因此在设置钩子时要把回调函数放置于钩子链表的链首, 操作系统会使其首先被调用。由函数SetWindowsHookEx()负责将回调函数放置于钩子链表的开始位置。SetWindowsHookEx()函数原型声明为:

HHOOK SetWindowsHookEx(int idHook;HOOKPROC lpfn;HINSTANCE hMod;DWORD dwThreadId);


  其中,参数idHook 指定了钩子的类型,可以使用的类型有以下13种:

WH_CALLWNDPROC 系统将消息发送到指定窗口之前的“钩子”
WH_CALLWNDPROCRET 消息已经在窗口中处理的“钩子”
WH_CBT 基于计算机培训的“钩子”
WH_DEBUG 差错“钩子”
WH_FOREGROUNDIDLE 前台空闲窗口“钩子”
WH_GETMESSAGE 接收消息投递的“钩子”
WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD“钩子”记录的输入消息
WH_JOURNALRECORD 输入消息记录“钩子”
WH_KEYBOARD 键盘消息“钩子”
WH_MOUSE 鼠标消息“钩子”
WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息“钩子”
WH_SHELL 外壳“钩子”
WH_SYSMSGFILTER 系统消息“钩子”


  参数lpfn为指向钩子函数的指针,也即回调函数的首地址;参数hMod标识了钩子处理函数所处模块的句柄;参数dwThreadId 指定被监视的线程,如果明确指定了某个线程的ID就只监视该线程,此时的钩子即为线程钩子;如果该参数被设置为0,则表示此钩子为监视系统所有线程的全局钩子。此函数在执行完后将返回一个钩子句柄。

  在SetWindowsHookEx()函数完成对钩子的安装后,如果被监视的事件发生,系统会立即调用位于相应钩子链表开始处的钩子函数进行处理,每一个钩子函数在进行处理时都要考虑是否需要把事件传递给下一个钩子处理函数。如果需要传递,就要调用函数CallNestHookEx()。尽管在理论上不调用CallNestHookEx()也并不算错,但在实际使用时还是强烈建议无论是否需要进行事件传递都要在过程的最后调用一次CallNextHookEx( ),否则将会引起一些无法预知的系统行为或是系统锁定。该函数将返回位于钩子链表中的下一个钩子处理过程的地址,至于具体的返回值类型则要视所设置的钩子类型而定。CallNextHookEx( )的函数原型为:

LRESULT CallNextHookEx(HHOOK hhk;int nCode;WPARAM wParam;LPARAM lParam);


  其中,参数hhk为由SetWindowsHookEx()函数返回的当前钩子句柄;参数nCode为传给钩子过程的事件代码;参数wParam和lParam 则为传给钩子处理函数的参数值,其具体含义同设置的钩子类型有关。

  由于安装钩子对系统的性能有一定的影响,所以在钩子使用完毕后应及时将其卸载以释放其所占资源。释放钩子的函数为UnhookWindowsHookEx(),该函数比较简单只有一个参数用于指定此前由SetWindowsHookEx()函数所返回的钩子句柄,原型声明如下:

BOOL UnhookWindowsHookEx(HHOOK hhk);


  使用鼠标钩子

  由于系统全局钩子在功能上完全覆盖了线程局部钩子,因此其实际使用范围要远比线程局部钩子广泛的多。本节也由此着重对系统全局钩子的使用进行介绍。

  鼠标钩子是钩子中比较常用也是使用比较简单的一类钩子。下面给出的应用示例将通过安装鼠标全局钩子来捕获鼠标当前所处窗口的窗口标题。由于本例程使用了全局钩子,因此首先构造全局钩子的载体——动态链接库。考虑到 Win32 DLL与Win16 DLL存在的差别,在Win32环境下要在多个进程间共享数据,就必须采取一些措施将待共享的数据提取到一个独立的数据段,并通过def文件将其属性设置为读写共享:

#pragma data_seg("mydata")
HWND glhPrevTarWnd = NULL; // 上次鼠标所指的窗口句柄
HWND glhDisplayWnd = NULL; // 显示目标窗口标题编辑框的句柄
HWND glhHook = NULL; // 安装的鼠标钩子句柄
HINSTANCE glhInstance = NULL; // DLL实例句柄
#pragma data_seg()
……
SECTIONS // def文件中将数据段TestData设置为读写共享
TestData READ WRITE SHARED


  在完成上述准备工作后,在动态库输出函数StartHook()中调用SetWindowsHookEx()函数完成对全局鼠标钩子的安装,设定鼠标钩子函数为MouseProc(),安装函数返回的钩子句柄保存于变量glhHook中:

BOOL CMouseHook::StartHook(HWND hWnd)
{
 BOOL result = FALSE;
 // 安装钩子
 glhHook = (HWND)SetWindowsHookEx(WH_MOUSE, MouseProc, glhInstance, 0);
 if (glhHook != NULL)
  result = TRUE;
 glhDisplayWnd = hWnd; // 设置显示目标窗口标题编辑框的句柄
 return result;
}


  在鼠标钩子安装完毕后,系统内的任何鼠标动作所发出的鼠标消息均要经过钩子函数MouseProc()的拦截过滤处理。在此进行的处理是通过获取当前鼠标所在位置下的窗口句柄,并以此进一步得到窗口标题。在处理完成后,调用CallNextHookEx()函数将本事件传递到钩子链表中的下一个钩子函数:

LRESULT WINAPI MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
 LPMOUSEHOOKSTRUCT pMouseHook = (MOUSEHOOKSTRUCT FAR *) lParam;
 if (nCode >= 0) {
  HWND glhTargetWnd = pMouseHook->hwnd; // 取目标窗口句柄
  HWND ParentWnd = glhTargetWnd;
  while (ParentWnd != NULL){
   glhTargetWnd = ParentWnd;
   ParentWnd = GetParent(glhTargetWnd); // 取应用程序主窗口句柄
  }
  if (glhTargetWnd != glhPrevTarWnd) {
   char szCaption[100];
   GetWindowText(glhTargetWnd, szCaption, 100); // 取目标窗口标题
   if (IsWindow(glhDisplayWnd))
    SendMessage(glhDisplayWnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szCaption);
   glhPrevTarWnd = glhTargetWnd; // 保存目标窗口
  }
 }
 // 继续传递消息
 return CallNextHookEx((HHOOK)glhHook, nCode, wParam, lParam);
}


  此动态链接库还提供有输出函数StopHook(),调用程序通过对此函数的调用完成对先前加载钩子的卸载。在此输出函数内则是通过UnhookWindowsHookEx()函数来卸载指定钩子的:

BOOL CMouseHook::StopHook()
{
 BOOL result = FALSE;
 if (glhHook){
  result = UnhookWindowsHookEx((HHOOK)glhHook); // 卸载钩子
  if (result)
   glhDisplayWnd = glhPrevTarWnd = glhHook = NULL;
 }
 return result;
}


  通过编译、链接可以得到有关鼠标全局钩子的动态链接库,在经过调用程序对其的调用后,可以实现对在当前系统所有线程中的鼠标消息的拦截处理。在钩子动态链接库加载到进程后,只需调用输出函数StartHook()安装好全局钩子即可对鼠标消息进行拦截过滤,在调用程序退出前调用输出函数StopHook()卸载钩子。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mfc中钩子的使用 的相关文章

  • 在MFC项目中使用多个资源文件

    我在 VS2015 中使用 MFC C 11 并且有一组独立的 GUI 我想在多个项目中使用它们 我知道这可以通过创建一个 rc 文件来实现 该文件可以包含在每个项目的主 rc 文件中 使用多个资源文件 https msdn microso
  • SetWindowPos() 函数不移动窗口?

    我有一个对话框 我想将其放置在另一个对话框中 并相对于主对话框上的其中一个控件进行定位 void CspAceDlg DrawResultsArea CWnd pTabCtl GetDlgItem IDC BUILDTABS CRect r
  • 从不同操作系统检索到的故障转储指向消息循环。如何从那里到达故障位置? (TeamViewer 使我的进程崩溃。)

    我们软件的一位客户抱怨说 该软件在他的 Windows XP 计算机上崩溃了 我让他下载ProcDump https technet microsoft com en us sysinternals dd996900 aspx并按如下方式运
  • CloseWindow和WM_CLOSE有什么关系

    我现在有点困惑 是吗 WM CLOSE http msdn microsoft com en us library windows desktop ms632617 28v vs 85 29 aspx and CloseWindow htt
  • 将简单的 MFC CView/CDocument/CSingleDocTemplate 应用程序转换为 ActiveX 控件

    我有一个相当简单的 MFC 应用程序 它只定义了自己的子类CDocument CView and CFrameWnd并通过使用它们CSingleDocTemplate在视图的树中显示文档的只读内容 都是非常标准的MFC MVC 我现在需要转
  • 如何将 std::variant 作为 VARIANT* 传递给 ExecWB?

    我看过这篇关于使用的文章std variant https en cppreference com w cpp utility variant 这是因为以下代码引发了代码分析警告 void CChristianLifeMinistryHtm
  • 如何向 CMFCPopupMenu 添加图标?

    我想用CMFCPopupMenu用于右键单击期间的弹出菜单 如何添加图标CMFCPopupMenu 这是我在基本 MFC 应用程序中尝试的示例代码 CMFCPopupMenu TestCMFCPopMenu new CMFCPopupMen
  • 如何找到激活时打开给定 HMENU 的菜单项(如果有)?

    我想用原型实现一个功能 Locates the menu item of the application which caused the given menu mnu to show up return true if the given
  • MFC 是否提供了将文本放入剪贴板的快速方法?

    我们的代码库中的添加到剪贴板代码非常低级 分配全局内存等等 对于简单的情况 我只想将一些纯文本放在剪贴板上 是否有任何例程可以包装所有这些内容 一个例子是 CRichEditCtrl 具有 Copy 和 Cut 方法 可以自动将当前选择放入
  • 如何将命名管道字符串从非托管代码空间发送到托管代码空间?

    我似乎遇到了命名管道 101 问题 我有一个非常简单的设置来连接从 C 非托管应用程序传输到 C 托管应用程序的单工命名管道 管道已连接 但我无法通过管道发送 消息 除非我关闭似乎刷新缓冲区并传递消息的句柄 就好像消息被屏蔽了一样 我尝试颠
  • 想要将 ColeDateTime 转换为 CTime

    我正在从数据库中读取日期时间ColeDateTime格式 我想将其转换为CTime获取日期 月份 年份和时间 CString repDt this will hold the datetime which i read from Datab
  • 如何将基数词转换为序数词

    有没有一种简单的方法可以将数字 1 2 3 转换为 1st 2nd 3rd 并且以这种方式我可以为该函数提供一种语言并具有它会返回我目标语言的正确形式吗 标准 C stl 或 boost 都可以 MFC 或 ATL win32 api 或我
  • 如何使用 MFC 禁用顶级菜单项并使其变灰

    我有一个对话框应用程序 我希望在对话框顶部有可单击的菜单项 这些项目不显示下拉菜单 但实际上运行关联的命令 我通过在对话框属性中设置 Popup False 并分配消息 ID 来做到这一点 但我的问题是 当项目可点击没有意义时 无法正确禁用
  • .NET(或 MFC)的高速图形控件?

    我需要编写一个数字示波器类型的应用程序 有很多很棒的静态绘图控件 但我需要一些可以绘制每秒处理 4000 个样本的 16 条轨迹的东西 有人知道 NET 的高速图形控件吗 我什至会选择 MFC 因为它可以封装到 NET 控件中 谢谢您的帮助
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • 更改 GLUT 调用以与 MFC/C++ 一起使用

    我有一个使用 GLUT 进行 OpenGL 渲染的程序 现在我需要它位于 MFC 项目内部 以便它可以与另一个程序组件一起使用 我已经按照这个教程进行操作 http www codeguru com cpp g m opengl openf
  • MFC CList 支持复制分配吗?

    我在 MSVC 中查找了 CList 定义afxtempl h http www cppdoc com example mfc classdoc MFC AFXTEMPL H html并记录在MSDN http msdn microsoft
  • 通过 MFC 对话框中的代码更改 Tab 顺序

    我在 OnInitDialog 中通过代码创建了一个控件 但我找不到任何方法通过代码更改对话框的选项卡顺序 有人知道如何做到这一点吗 First Option use ctrl d on resource view in visual st
  • 在运行时将无模式对话框转换为模式对话框

    我有一个对话框 CDialog 派生类 可以以两种不同的方式使用 编辑模式和编程模式 当对话框打开以在编程模式下使用时 它是一个无模式对话框 用于修改主视图 类似于工具栏 当它以编辑模式打开时 用户可以更改对话框本身的配置 在这种情况下 它
  • 调试器忽略动态加载的 DLL 中的错误

    我有一个与自编码 DLL 的调试相关的非常奇怪的问题 我有一个 MFC 驱动的基于对话框的应用程序 几个静态链接的项目和几个在运行时加载的 DLL 项目 我在调试中构建解决方案 运行应用程序 然后我可以轻松调试这些 DLL 项目 现在问题来

随机推荐