windows发送窗口消息
所需工具:spy++,visual studio 2017,c#语言
技术路线:首先通过spy++获得所要操纵的窗口的句柄,函数的原型声明为:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
此函数获得目标窗口的句柄,如果要获得某个子窗口的句柄,通过以下函数可获得:
[DllImport("User32.dll ")]
public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childe, string strclass, string FrmText);
对目标窗口的操作(发送指令),使用的函数原型如下:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
我通过SendMessage函数发送的是绘图动作,具体包括鼠标的down,move,up
另一个发送消息的函数,原型声明:
[DllImport("User32.dll", EntryPoint = "PostMessage")]
private static extern int PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
我通过PostMessage函数发送的是点击按钮的动作,具体包括鼠标的down,up
SendMessage与PostMessage函数的差别
SendMessage为这个指定的消息调用窗口处理程序,直到窗口处理完这个程序后才会返回;PostMessage函数发送一个消息到线程消息对列中,并立即返回。
失败部分:1.在绘图过程中,我考虑过用WM_PAINT发送绘图消息,但是查看MSDN手册后发现WM_PAINT消息是由系统产生的,它不应该由一个应用程序发送。我也考虑过先生成一个图形,然后将它发送到窗口,这样违背了最初测试的目的。
失败经验总结:首先要确定技术路线,不能盲目乱试,查看官方文档的函数介绍。
Windows中的消息机制:消息就是一些指令。如果你想让窗口或控件(实质上,控件是特殊的窗口)执行何种动作,你应该传送一个消息给它;如果另一个窗口想让你执行何种操作,它可以传送一个消息给你。如果一个事件,如敲击键盘、移动鼠标、点击按钮等,系统将消息传送给窗口,如果你是这些窗口之一,你将接收到消息执行相应的操作。
消息队列:当消息发送过来,将消息加入消息队列,当一个消息被处理时,将其从消息队列移除。这样确保消息不会丢失,当你正在处理一个消息时,其它到来的消息可以加入到消息队列直到被处理。
消息循环:
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg); //可选,有的会用到
DispatchMessage(&Msg);
}
1. 消息循环调用GetMessage()从消息队列中查找消息进行处理,如果消息队列为空,程序将停止执行并等待(程序阻塞)。
2. 事件发生时导致一个消息加入到消息队列(例如系统注册了一个鼠标点击事件),GetMessage()将返回一个正值,这表明有消息需要被处理,并且消息已经填充到传入的MSG参数中;当传入WM_QUIT消息 时返回0;如果返回值为负表明发生了错误。
3. 取出消息(在Msg变量中)并将其传递给TranslateMessage()函数,这个函数做一些额外的处理:将虚拟键值信息转换为字符信息。
4. 上面的步骤执行完后,将消息传递给DispatchMessage()函数。DispatchMessage()函数将消息分发到消息的目标窗口,并且查找目标窗口过程函数,给窗口过程函数传递窗口句柄、消息、wParam、lParam等参数然后调用该函数。
5. 在窗口过程函数中,检查消息和其他参数,你可以用它来实现你想要的操作。如果不想处理某些特殊的消息,你应该总是调用DefWindowProc()函数,系统将按按默认的方式处理这些消息(通常认为是不做任何操作)。
6. 一旦一个消息处理完成,窗口过程函数返回,DispatchMessage()函数返回,继续循环处理下一个消息。