做“HOOK文件打开/保存对话框”的过程中,我首先研究了界面库的相关知识。界面库一般都是由C/C++这种中低级语言编码,这是因为在Windows下的界面库实现技术大都以直接操作控制Windows的消息和调用Windows的API为主,这就是这种中低级语言的优势了。无论何种界面库,最为根本的原理就是获得或者截获窗口的某些消息,按照自己的需要处理这些消息,画出自己需要的界面。

按照Windows下的界面库的使用方法来分类,可以分为两种: 1、 通过派生、继承界面库中的类来使用库。这类界面库现在是占绝大多数。这类界面库通常可以对同种类型的控件、窗口自己控制显示风格。这种类型的界面库典型的代表就是GuiToolkit、ProfUIS。 2、 通过Link头文件,使用DLL来使用的界面库。这类界面库一般都是商业化的界面库。这类界面库一般对于同种类型的控件、窗口都是显示统一的风格。这种类型的界面库的典型代表是Skin++、AppFace。

上面的分类,其实同时也代表着两种界面库实现技术,也就是获取用于自绘窗口的消息的两种来源: 1、 通过子类化、超类化改变窗口风格。

其实就是调用Windows的API SetWindowLong或者通过类的派生和继承来改变Windows窗口的默认的消息处理函数。 2、 使用HOOK技术改变Windows的默认消息处理。

一、SetWindowLong  SetWindowLong(HWND hWnd,                    //需要改变UI的窗口的窗口句柄 Int nIndex,                                                           //替换窗口的默认消息处理函数时为GWL_WNDPROC Long dwNewLong)                                           //新的默认的窗口消息处理函数 调用这个API函数可以替换一个窗口的默认的消息处理函数,这样就可以在新的窗口消息处理函数中截获到目标窗口的相关消息,然后根据需要处理这些消息。这个API用于获取当前窗口的消息,它不能获取窗口中子窗口的消息。  这种类型的界面库,一般是开源的或者是提供了头文件和Lib文件的界面库。 这个Windows API大家很可能很少直接调用,但是它的封装――――SubclassWindow这个成员函数,我想大家都使用过。先让我们看看各种类型的子类化过程中的SetWindowLong都藏在什么地方,它们是如何工作的。 1、 MFC下的实现 在MFC程序中,可以先在工程中添加一个用于子类化的窗口类,然后就可以通过ClassWizard这个工具来完成剩下的子类化的工作了。我们以一个自定义的Button类CMyButton类来举例。在打开ClassWizard为我们的基于Dialog的工程中的一个Button资源添加一个对应的变量的时候我们就可以看到可以直接定义了CMyButton类,如下图:  我们为ID为IDC_BUTTON1的一个按钮资源定义一个类型为CMyButton的成员变量m_MyBtn。这时候ClassWizard就会在重载的虚函数DoDataExchange中为我们添加上一条语句,如下: void CMFCSampleDlg::DoDataExchange(CDataExchange* pDX) {  CDialog::DoDataExchange(pDX);  //{{AFX_DATA_MAP(CMFCSampleDlg)  DDX_Control(pDX, IDC_BUTTON1, m_MyBtn);//这就是ClassWizard为我们添加的  //}}AFX_DATA_MAP } 让我们来看看DDX_Control这个函数为我们做了什么,在MFC的源代码DLGDATA.CPP文件中我们能找到这个函数的源代码: void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl) {  if (rControl.m_hWnd == NULL)    // not subclassed yet  {  …… …   //注意看看,噢,原来SubclassWindow在这里   if (!rControl.SubclassWindow(hWndCtrl))   {    ASSERT(FALSE);      // possibly trying to subclass twice?    AfxThrowNotSupportedException();   } …… …  } }

让我们再看看MFC下的SubclassWindow这个成员函数的实现,在MFC的源代码wincore.cpp中可以看到所有MFC下窗口类的基类CWnd中的SubclassWindow的实现: BOOL CWnd::SubclassWindow(HWND hWnd) {  if (!Attach(hWnd))   return FALSE;

// allow any other subclassing to occur  PreSubclassWindow();

// now hook into the AFX WndProc  WNDPROC* lplpfn = GetSuperWndProcAddr();  //注意看看,原来它也是使用SetWindowLong啊  WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,   (DWORD)AfxGetAfxWndProc());  ……  …

return TRUE; } 上面的源代码跟踪说明,ClassWizard为我们自动完成的子类化工作中,其实也是调用的SetWindowLong这个Windows API。当然在MFC下你也可以自己调用SubclassWindow这个成员函数去手动的完成子类化。

2、 ATL/WTL下的实现 在ATL的源代码中,文件ATLWIN.H文件中,我们可以找到所有ATL窗口类的基类CwindowImplBaseT中的SubClassWindow的实现: template <class TBase, class TWinTraits> BOOL CWindowImplBaseT< TBase, TWinTraits >::SubclassWindow(HWND hWnd) {  ATLASSERT(m_hWnd == NULL);  ATLASSERT(::IsWindow(hWnd));  m_thunk.Init(GetWindowProc(), this);  WNDPROC pProc = (WNDPROC)&(m_thunk.thunk);  //注意看看,它也是调用SetWindowLong的!  WNDPROC pfnWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);  if(pfnWndProc == NULL)   return FALSE;  m_pfnSuperWindowProc = pfnWndProc;  m_hWnd = hWnd;  return TRUE; } 在ATL/WTL没有MFC下的那种自动子类化的机制,如果需要子类化一般都是直接调用SubclassWindow这个成员函数。

二、SetWindowsHookEx SetWindowsHookEx( int idHook,                      //HOOK的类型 HOOKPROC lpfn,                                               //HOOK的回调函数 HINSTANCE hMod,                                            //应用程序的实例句柄 DWORD dwThreadId)                                        //线程的ID SetWindowsHookEx这个API可以设置很多种类型的HOOK,它们分别在不同的时间截获线程ID为dwThreadId的线程的不同消息。在编写界面库的时候一般设置类型为WH_CALLWNDPROC的HOOK,用以在窗口处理消息之前获得消息并进行处理。

在HOOK的CALLBACK函数中可以获得窗口句柄,进而获得窗口的类型和窗口的风格,这样就可以知道需要处理的消息类型。

一般都是从截获WM_CREATE消息开始,然后处理WM_PAINT、WM_NCPAINT等等和UI有关的消息以达到自绘窗口UI的目的。 使用HOOK技术的界面库中当然也可以使用SetWindowLong技术,在C++写的界面库中一般是在获得了窗口句柄以后,即使用SetWindowLong技术将窗口句柄关联到一种特定的窗口类上。并且可以根据窗口的风格让同一个类做出不同风格的显示效果,可惜的是现在市面上的界面库都很少进行这种比较繁琐的区分工作。 这种类型的界面库一般都是以DLL文件格式出现,现在最为流行的是将界面库封装为一个COM DLL,在应用程序中创建这个COM组件,获得相关的接口,调用相关的接口函数来为应用程序安装HOOK。在做“Picasso风格的文件打开/保存对话框”过程中,我们一直以Yahoo Messenger的Save对话框作为参考,其实Yahoo Messenger就是使用的这种类型的界面库的。Yahoo messenger的界面库截获了进程中所有线程的消息,并做了相关的处理,所以它可以截获一些系统的窗口的创建消息和UI相关的消息,以达到改变Windows系统窗口的显示风格的目的。

最后介绍一下几个比较好的开源的界面库或者例子。 1、 ClassXP(http://www.yonsm.net/read.php?26) 一个个人的开源界面库,C语言写的,不完善,使用HOOK技术。Yahoo messenger的界面库就类似于这个界面库,只不过Yahoo messenger做的更完善而已。 2、 ProfUIS(http://www.codeproject.com/docking/prod_profuis.asp) 一个部分开源的界面库,有完善功能的商业版。比较完善,MFC写的,使用的是SetWindowLong技术。 3、 GuiToolkit(http://www.codeproject.com/library/guitoolkit.asp) 一个开源的界面库,比较完善,MFC写的,使用的是SetWindowLong技术。 4、 MSDN中的ControlSpy例子。 MSDN中的一个例子,用于了解各种控件的消息。

http://www.cnblogs.com/lidabo/archive/2013/05/05/3060502.html

HOOK自绘原理 good的更多相关文章

  1. 阿里系产品Xposed Hook检测机制原理分析

    阿里系产品Xposed Hook检测机制原理分析 导语: 在逆向分析android App过程中,我们时常用的用的Java层hook框架就是Xposed Hook框架了.一些应用程序厂商为了保护自家a ...

  2. 黄聪:WordPress 的 Hook 机制与原理(add_action、add_filter)

    稍有接触过 WordPress 主题或插件制作修改的朋友,对 WordPress 的Hook机制应该不陌生,但通常刚接触WordPress Hook 的新手,对其运作原理可能会有点混乱或模糊.本文针对 ...

  3. Android中免root的hook框架Legend原理解析

    一.前言 Android中hook框架已经非常多了,最优秀的当属Xposed和Substrate了,这两个框架我在之前的文章都详细介绍过了,不了解的同学,可以转战这里:http://www.wjdia ...

  4. 运用Detours库hook API(原理是改写函数的头5个字节)

    一.Detours库的来历及下载: Detours库类似于WTL的来历,是由Galen Hunt and Doug Brubacher自己开发出来,于99年7月发表在一篇名为<Detours: ...

  5. MFC重绘原理的关键理解

    // ====================Windows重绘消息与函数========================== 得到桌面窗口的句柄,然后再绘图HWND GetDesktopWindow ...

  6. 深入Windows窗体原理及控件重绘技巧

    之前有学MFC的同学告诉我觉得Windows的控件重绘难以理解,就算重绘成功了还是有些地方不明白,我觉得可能很多人都有这样的问题,在这里我从Windows窗体的最基本原理来讲解,如果你有类似的疑惑希望 ...

  7. IAT Hook 原理分析与代码编写

    Ring 3层的 IAT HOOK 和 EAT HOOK 其原理是通过替换IAT表中函数的原始地址从而实现Hook的,与普通的 InlineHook 不太一样 IAT Hook 需要充分理解PE文件的 ...

  8. 使用React Hook后的一些体会

    一.前言 距离React Hook发布已经有一段时间了,笔者在之前也一直在等待机会来尝试一下Hook,这个尝试不是像文档中介绍的可以先在已有项目中的小组件和新组件上尝试,而是尝试用Hook的方式构建整 ...

  9. 分针网—每日分享:HTML解析原理

    标准的web前端工程师需要知道 ◎浏览器(或者相应播放器)的渲染/重绘原理   这我得加把劲了.我还真的说的不是很清楚,我就G下,结果不是很多,找到了有一个,就记下来了...   以下部分来自hand ...

随机推荐

  1. iOS5.1下emoji表情显示方框的解决办法

    在iOS5.1的部分设备上,emoji表情无法正常显示.我测试了一下,iOS5.1(9B176 for iPhone 4)无法正常显示emoji,全部是方框iOS5.1(9B179 for iPhon ...

  2. 那些年搞不懂的"协变"和"逆变"

    博主之前也不是很清楚协变与逆变,今天在书上看到了有关于协变还是逆变的介绍感觉还是不太懂,后来看了一篇园子里面一位朋友的文章,顿时茅塞顿开.本文里面会有自己的一些见解也会引用博友的一些正文,希望通过本篇 ...

  3. Main方法的执行过程(转)

    要运行一个 main 方法 , 首先要知道 main 方法所在的 Class, 在命令行中指定这个 Class 名 Class Lava{ Private int speed = 4; Void fl ...

  4. 金融管理 - MBA智库百科

    金融管理 - MBA智库百科     金融管理    出自 MBA智库百科(http://wiki.mbalib.com/)     金融管理(Financial Management)    目录  ...

  5. 非确定有限状态自动机的构建(二)——将CharVal转换为NFA

    保留版权,转载注明出处:潘军彪的个人博客(http://blog.csdn.net/panjunbiao/article/details/9378933) 将上下文无关文法读入内存之后,可以将它转换成 ...

  6. BZOJ 1072 [SCOI2007]安排perm 如压力DP

    意甲冠军:联系 方法:状压DP? 题解:这题事实上没啥好写的.不算非常难,推一推就能搞出来. 首先看到这个问题,对于被d整除这个条件,非常easy就想到是取余数为0,所以想到可能状态中刚開始含有取余数 ...

  7. LVM的一般操作过程

    1. 在磁盘分区上建立物理卷  #fdisk /dev/hdb  #pvdisplay /dev/hdb1 //在已经建立好的分区或硬盘上建立物理卷  #pvcreate /dev/hdb1    2 ...

  8. Sqrt(x) 牛顿迭代法

    为了实现sqrt(x),可以将问题看成是求解\(x^2-y=0\) ,即sqrt(y)=x: 牛顿法是求解方程的近似方法,给定初始点\((x0,f(x0))\),迭代公式为: #include < ...

  9. js 中 字符串的转换

    JS 中将 number 转换为 string 我们比较熟悉,直接用toString() 的方法就可以了:那么将 string 转换成为 number 都有些什么方法呢?如下便简单的列举了一些,以便记 ...

  10. WinDbg分析DUMP文件

    1. 如何生成dump文件?     原理:通过SetUnhandledExceptionFilter设置捕获dump的入口,然后通过MiniDumpWriteDump生成dump文件:       ...