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和ATL之间的根本区别是什么?

    假设我是only将它们用于 普通 GUI 程序 没有 COM 没有 ActiveX 没什么花哨的 我将看到 ATL 和 MFC 之间的根本区别是什么 以帮助我弄清楚使用哪一个 我在网上做了一些搜索 但最终没有一个答案真正回答了我的问题 ht
  • MFC/WinAPI 的大问题

    我需要创建一个带有两个选项卡的表单视图的 SDI 表单 其中封装了多个对话框作为选项卡内容 但表格必须有彩色背景 诸如此类的事情让我讨厌编程 首先 我通过资源编辑器尝试了 CTabControl 尝试了不同的事情 但未记录的行为和没有答案的
  • 安装VS2008后,在winnt.h中出现编译错误

    我正在尝试将我们的项目从 VS2005 转移到 VS2008 并且在 MFC 项目上遇到此构建错误 C Program Files Microsoft SDKs Windows v6 0A include winnt h 236 error
  • 寻找 C++ 中搜索和替换的圣杯

    最近 我正在寻找一种替换字符串中标记的方法 这本质上是查找和替换 但至少还有一种解决问题的方法 看起来像是相当平庸的任务 我已经提出了几种可能的实现 但从性能的角度来看 它们都不能令人满意 最好的成绩是每次迭代约 50us 这种情况很理想
  • 在MFC项目中使用多个资源文件

    我在 VS2015 中使用 MFC C 11 并且有一组独立的 GUI 我想在多个项目中使用它们 我知道这可以通过创建一个 rc 文件来实现 该文件可以包含在每个项目的主 rc 文件中 使用多个资源文件 https msdn microso
  • GetWindowRect 坐标不与屏幕相关

    我正在使用 Visual Studio 2008 C 工作 我有一个 MFC 对话框 里面有一个控件 我正在尝试在控件中放置另一个对话框 第二个对话框上的 SetWindowPos 显然使用屏幕坐标 因此我需要获取控件或父对话框的屏幕坐标
  • 如何向现有 Win32 C++ 项目添加 MFC 支持?

    我正在创建一个 C 应用程序 它使用 Qt 创建 GUI 但是 我需要使用依赖于 MFC 的第三方库 用于 CString 等 无论如何 是否可以将 MFC 添加到我的应用程序中以允许我使用这个库 或者我需要自己重写它 I saw 这个问题
  • 具有透明背景的CWnd

    我想创建一个基于 CWnd 的类 它将引入具有透明背景的控件 只要内容是静态的 创建一个控件并用透明背景绘制其内容对我来说没什么大不了的 问题是当我想创建一个内容不断变化的控件时 这是因为我不知道如何用父背景删除控件的内容 一般情况下可能不
  • 跨平台 Windows / OS X 开发,具有大量现有代码库

    对于使用 MFC 和 WinAPI 用 C 编写的复杂应用程序 有大量现有代码库 需要将其移植到 Mac OS X 理想的解决方案是在不同平台之间拥有尽可能多的通用代码 尤其是诸如业务之类的代码逻辑 GUI 可能会有所不同 具体取决于跨平台
  • 如何在现有 Windows 应用程序中获得 ATL 支持

    我正在 Visual Studio 2012 中使用 Qt 5 3 1 构建一个应用程序 我还想使用一个硬件库 这需要我向项目添加一个简单的 ATL 对象 这可以通过使用 Visual Studio 向导来完成 该向导抱怨我的项目既不是 M
  • MFC CMenu 工具提示未显示

    我尝试使用类似的东西来设置 CMenu 项的工具提示 如所述here https stackoverflow com questions 2400180 mfc how to add tooltip in cmenu items 但它只是显
  • 获取正在运行的程序的属性

    我想开发一个程序 其 ID 是一张牌 因为它在另一个正在运行的程序 例如扑克或红心游戏或其他程序 中播放 我首先尝试获取有关已运行的游戏程序的所需信息 但我从一开始就遇到了问题 我正在运行 MSVC 2013 并开发 MFC 应用程序 现在
  • 如何使用 MFC 禁用顶级菜单项并使其变灰

    我有一个对话框应用程序 我希望在对话框顶部有可单击的菜单项 这些项目不显示下拉菜单 但实际上运行关联的命令 我通过在对话框属性中设置 Popup False 并分配消息 ID 来做到这一点 但我的问题是 当项目可点击没有意义时 无法正确禁用
  • C++ 检查 unicode 字符是否为全角

    如何检查unicode字符是否是全角 我使用Win32 MFC 例如 中是全宽 A不是全角 是全宽 F不是全宽 你需要的是检索东亚宽度 http www unicode org reports tr11 的角色 您可以通过解析来做到这一点东
  • 屏幕截图忽略了一些窗口

    我正在 MFC 中工作 我正在尝试捕获桌面的 bmp 我正在使用 GetDC NULL 来执行此操作 但它似乎忽略了特殊的皮肤窗口 它似乎忽略了用 UpdateLayeredWindow 绘制的窗口 此行为似乎仅发生在 Vista x64
  • Create CFrameWnd 给出了第一次机会异常——为什么?

    我正在尝试使用基于 CFrameWnd 的代码编写一个简单的 MFC 应用程序 该应用程序在可滚动窗口中绘制 下面的代码改编自 Prosise Programming Windows with MFC 第 2 版 第 89ff 页 当我在调
  • 从模态 MFC 表单获取输入信息

    我已经创建了表格CPreparationDlg具有Edit Control 然后我创建了创建模态表单的应用程序 在按 确定 后 我需要将编辑控件中输入的文本读入主程序的变量中 最好的方法是什么 class CPreparationApp p
  • 如何在MFC中对CListCtrl中的Item进行排序?

    我在 MFC 中制作了一个基于对话框的应用程序 我将 CListCtrl 控件放在对话框上 并将其视图样式设置为报告类型 我在此列表视图中有五列 所有列都是字符串类型 我想在此列表中实现排序 也就是说 当我单击某一列时 它应该对列表中的项目
  • 更改 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

随机推荐