1

Win32实现窗口盗窃(一)

这里所谓“窗口盗窃”,是指把其他窗口“装”进程序自身,感觉就像是把其他程序“偷”到了自己的袋里。程序还有另一个重要功能,就是让其他程序无法响应键盘、鼠标消息——当然,这就有点邪恶了,不过实现方法却是有时在编写Win32程序经常用到的一种技术。本文先简单讲解功能一的实现,下一篇文章将会对功能二进行介绍。

实现原理

1. 广义的窗口

要想知道如何把其他程序“装”入自身,那么首先需要理解父窗口的概念。先从窗口说起。
在Win32中,窗口有着丰富的含义,除了常见的大多数应用程序都有的矩形区域是窗口以外,还有很多部分其实也是窗口,比如按钮、编辑框、标签等控件也是窗口,所以在理解什么是窗口时,我们一定不能仅仅局限于矩形区域这种思维模式下。
为了能更深入地读懂窗口以及窗口背后的代码,先来看一下Win32 Platform SDK中用于创建窗口的API CreateWindow的定义

HWND WINAPI CreateWindow(
  _In_opt_ LPCTSTR   lpClassName,
  _In_opt_ LPCTSTR   lpWindowName,
  _In_     DWORD     dwStyle,   //指定要创建的窗口的样式
  _In_     int       x,
  _In_     int       y,
  _In_     int       nWidth,
  _In_     int       nHeight,
  _In_opt_ HWND      hWndParent,
  _In_opt_ HMENU     hMenu,
  _In_opt_ HINSTANCE hInstance,
  _In_opt_ LPVOID    lpParam
);

这里我们只关心其中的dwStyle参数,关于CreateWindow的具体用法和更多API介绍,我会在之后的其他文章中陆续给出。
dwStyle是一个32位的双字,也就是说我们可以用位或操作(|)将多个属性组合到一起,比如,要创建一个按钮时,我们就可以这么写:

CreateWindow(
    "BUTTON", "OK",
    WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  //只看这里
    10, 10, 100, 100, hwnd, NULL,
    (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL);

这里,我们就用了三个属性的组合,其中WS_CHILD表明这是一个子窗口,BS_DEFPUSHBUTTON说明要创建一个按钮。

2. 父窗口的引入

那么为什么要说明这个按钮是一个子窗口呢?因为独立的按钮是不存在的,任何控件都是为了更好的协助用户与主窗口(程序)之间的交互而存在的,控件脱离了所属的窗口是没有意义的。所以,这里的按钮就有一个父窗口,也就是说,按钮所在的窗口就是按钮的父窗口。
不过这里的按钮可不是简单地画在父窗口上,而是附着。说得再直白点,父窗口如果被关闭了,那么按钮也就没有了附着的空间,于是按钮也要被销毁。如果把父窗口当成一面墙,那么按钮就好比是粘在墙上的挂钩;要是墙不存在了,那难道挂钩还能粘在空气上吗?

3. 在本例中的应用

窗口上粘着一大堆控件,我们也可以把别的程序的窗口当成控件一起粘在我们的窗口上。所以,核心思想就是把别的程序的父窗口设置成我们的窗口,而且不去管它原本到底有没有父窗口。
这里我们要用到的最关键的API是CWnd类中的成员函数 SetParent(这里的示例程序用MFC完成,所以不使用Plaform SDK版本的)。这个函数很简单:

CWnd* SetParent(CWnd* pWndNewParent);

参数指明要成为该窗口新的父窗口的指针。

代码演示

既然把大象装进冰箱要三步,那么一般地,把别的窗口装进我们的窗口也需要三步:

  1. 找到别的窗口

  2. 获取该窗口的句柄(指针)

  3. 装进我们的窗口

是不是非常的简单?


Soap
78 声望25 粉丝