Windows平台上的应用程序是事件驱动的 ,它们不会显式地调用底层函数以获得用户输入或其它信息,而是等待系统将这些信息提供给它们。同类定义的窗口向系统声明一个唯一的 窗口过程函数 (Window Procedures)。当有关某一窗口句柄的事件发生时(比如:鼠标单击这个窗口,或键盘向这个窗口输入一个字符),系统调用这个函数,把某个特定的消息作为参数。
要向特定的窗口过程发送消息,Windows提供了以下函数:
由于lpPrevWndFunc为同一类窗口共有,发送的消息在被某一窗口处理前事实上可能已被多个窗口接收。本文不会用到这一函数,关于此函数的完整定义请参阅:
这一函数在中定义,它向唯一的窗口句柄发送消息,并只在发送的消息被处理后返回。与之相似的是PostMessageW,它在发送消息后立即返回,即只将消息添加到目的窗口句柄的消息队列里,并不等待其处理。
HWND hwnd:接收消息的窗口句柄
(特别地(HWND)0xffff为广播)
UINT Msg:发送的消息类型
WPARAM wParam:发送的消息
LPARAM lParam:发送消息的附加参数
实现刷屏
mian dui dui xiang
获得Windows提供的API函数后,下面用C++实现。
首先将刷屏过程封装到一个类中
--------Bomb.h--------
构造类时向构造函数提供刷屏消息的重复次数和刷屏消息 (UTF-16格式)
ShowMessage()用于调试,把当前类保存的消息输出到控制台上
StartBombing(int)用于开始刷屏,参数定义开始刷屏前的延时。用户可在这段延时内把键盘焦点设置到目标窗口上去,使目标窗口句柄或得消息后把消息内容加入到文本输入框中去。此函数有一个无延迟参数的重载。
消息内容存储在私有段中一个类型为WPARAM的数组中(该类型在上文中有介绍),附加消息是一个值为NULL的LPARAM类型——实现本例中的功能不需要向SendMessageW()提供附加消息。
--------Bomb.cpp--------
出于某些考量,我们在此不提供主要函数的定义。在StartBombing()中,程序按用户设定的刷屏消息重复次数循环times次,并按消息长度循环MessageLength,每次将消息字符串中的第j个字符以WH_CHAR模式向所有窗口广播。获得键盘输入焦点的窗口会将其加入到文本框中。
在发送完一条消息后,通过keybd_event函数模拟一次【回车键按下】事件,使目标窗口(比如:wechat)发送消息或换行。
--------Main.cpp--------
这是应用程序入口点。注意它设置了wcout/wcin的本地化,使其将储存在WPARAM类型(其本质是unsigned int)中的UTF-16数据转化为中文字符输出/输入。
可见,按以上代码编译的应用程序已经可以完成质问马人王的任务。然而, 这速度也太慢了?? 这个速度比打字快不了多少,如果这样的话就没必要用刷屏软件了。哪里出了问题呢?
问题在于,如本文开头介绍:SendMessageW()强制在目标窗口过程将消息处理完毕后才返回,这使得整个过程变得相当缓慢。
解决方法是显而易见的:用PostMessageW()取代原函数。但是这样做会带来新的问题:Post函数只是简单地把消息加入到目标的消息队列去,之后立即返回。而原程序在Post/Send函数返回后会调用keybd_event()模拟一个键盘事件。然而,窗口过程处理消息的速度现在看来并不尽如人意,这往往会导致大量字符消息堆积在消息队列中,最终导致键盘事件和消息发送间不协调(比如:微信PC端输入框中堆积了很多信息而不发送,因为回车键按下事件没有按正常顺序处理)
所以,要兼顾消息的稳定性和发送速度,就要把keybd_event替换成另一个PostMessageW(),使【回车键按下】这一事件也像其它字符事件那样加入到消息队列中去,这样就能保证字符消息和回车间的先后顺序不变。