2.Windows窗口和消息

本文深入解析Windows消息机制,包括消息的生成、传递及处理流程。介绍窗口类的设计、注册及消息循环等内容,并对比分析SendMessage与PostMessage、GetMessage与PeekMessage等函数的功能差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Windows内部运行机制

设计窗口类 -> 注册窗口类 -> 创建窗口 -> 显示更新窗口 -> 消息循环 -> 处理消息

                      注册公司  -> 创建公司 –> 公司开张   -> 接收业务往来 -> 办理业务

 

2.Windows窗口消息(windows程序设计3.2.2)

1.进队消息

       进队的消息是由Windows放入程序消息队列中的,在程序消息循环过程中,重新返回并分配给窗口过程。

不进队消息在Windows调用窗口时直接发送给窗口过程。

       也就是说,不进队消息发送给消息队列,不进队消息直接发送给窗口过程。多数情况下,进队消息来自于 用户的输入结果,如:一般由用户操作产生的消息,如:鼠标单击、键盘单击、窗口重画消息等;       进队消息还包括时钟消息,刷新消息和退出消息。

2.不进队消息

       多数情况下,不进队消息来自调用特定的Windows函数。例如CreateWindowEx函数内部会发送WM_CREATE消息,GetWindowText函数会发送WM_GETTEXT消息获取标题内容。当调用ShowWindow时,将产生WM_SIZE和WM_SHOWWINDOW消息、当调用UpdateWindow时创建的WM_PAINT消息(注意,并不是某个类型是进队消息就永远是进队消息,如WM_PAINT有进队的,也有不进队的)、还有其他进队消息也有可能在不进队消息中出现,整个处理过程是复杂的,但由于Windows已经解决大部分的问题,因此我们可以认为我们获得的消息是有序的、同步的。


3.Windows消息循环示意图

 


4.SendMessage()和PostMessage()

 先来看看Send与Post这两个英文单词的意思:Send有发送的意思,而Post具有投寄的意思。
      联想一下现实生活中我们写信(很久很久以前。。。。)来记就很简单了:
      Send: 相当于邮寄员,他会将快件亲手交给收件人,并且需要收件人签字,他才闪人。而在消息机制中,就是说,系统(邮寄员)会将收到的消息(邮局分发)直接发送到某个窗口的窗口过程(收件人),并且需要该窗口作出处理(收件人签字)才返回。 这东东就是SendMessage
      Post: 相当于邮局、邮筒等等,我们写好信好,会将信交给邮局,或投寄到邮筒里,而什么时候发送,发送到哪里都由邮局来处理,我们投寄信件的时候,是不会等候这封信件到达收件人手里,然后才回家的。 而在消息机制中,就是说,系统(我们)将收到的消息(信件)投寄到应用程序的消息循环(相当于邮筒)中,然后就闪人,具体啥时候处理这条消息(啥时候发送邮件),那就得看“办事效率”了。
           区别很明显,SendMessage的消息是不进队列的,而PostMessage进队。 
           但,值得说明的是:虽然一个要进队,一个不进队,但是最终处理消息的地方都一样:都是系统调用窗口过程进行处理(收件人作出反应)

与此类似的还有一队函数,GetMessage()和PeekMessage()这里顺便再总结一下

 

5.GetMessage()和PeekMessage()的区别

相同点:

两函数都用于检查线程消息队列,有消息时取得消息并放入指定的结构。

返回值:

GetMessage()   TRUE:有消息且消息不为WM_QUIT

                       FALSE:有消息且该消息为WM_QUIT

 

PeekMessage()  TURE:有消息        FALSE:没有消息

不同点:

     从上面可以看出,GetMessage()无论返回何值队列中都有消息,也就是说在队列有消息时,函数返回,如果队列中没有消息,刚函数会一直等待,真到有消息出现才返回。(在函数等待时间内,应用程序不能执行任何指令。

Peek的意思为“看一眼,一瞥”。同时从上面的返回值可以看出,无论消息队列中是否有消息,PeekMessage()都立即返回,程序得以继续执行后面的语句(无消息则执行其它指令,有消息时一般要将消息派发出去,再执行其它指令)。

 

6.PreTraslateMessage()

Send和Post是否可以预处理?答案是否定的:

比如你要从A寄信到B,那么有两种方法:1、自己带着信跑到B,2、将信放到邮局,由邮局分发。
     第1 种情况下,就是SendMessage了,这个时候,还有谁能预处理你的信呢?
    第2种情况下,就是PostMessage了,这个时候,嘿嘿,万一运气不好,被邮局给用PreTranslateMessage给截了.....
    所以说,用SendMessage发送的消息是不能用PreTranslateMessage来预处理的。而Post的就可以,因为它要经过“第三者”嘛。


应用实例:

#include"tchar.h"
#include<windows.h>


LRESULT CALLBACK WindowProc(
						 HWND hwnd,      // handle to window
						 UINT uMsg,      // message identifier
                                                WPARAM wParam,  // first message parameter
                                                  LPARAM lParam   // second message parameter
						 )
{
	switch(uMsg)
	{
	case WM_CLOSE:
		{
			::DestroyWindow(hwnd);
		}
		break;
	case WM_DESTROY:
		{
			::PostQuitMessage(0);
		}
		break;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}




int WINAPI WinMain(HINSTANCE hInstance,      // handle to current instance
				   HINSTANCE hPrevInstance,  // handle to previous instance
				   LPSTR lpCmdLine,          // command line
				   int nCmdShow)            //_tWinMain兼容不同字符集
{
	const TCHAR* pszClassName=_T("lsfreeing");
	WNDCLASSEX wcex;
	wcex.cbSize=sizeof(WNDCLASSEX);
	wcex.cbClsExtra=0;
	wcex.cbWndExtra=0;
	wcex.hbrBackground=(HBRUSH)::GetStockObject(BLACK_BRUSH);
	wcex.hCursor=(HCURSOR)::LoadCursor(NULL,IDI_QUESTION);
	wcex.hIcon=(HICON)::LoadIcon(NULL,IDI_APPLICATION);
	wcex.hIconSm=NULL;
	wcex.hInstance=hInstance;
	wcex.lpfnWndProc=WindowProc;
	wcex.lpszClassName=pszClassName;
	wcex.lpszMenuName=NULL;
	wcex.style=CS_HREDRAW | CS_VREDRAW;
	BOOL flag=::RegisterClassEx(&wcex);
	if(flag==FALSE)
	{
		MessageBox(NULL,_T("注册失败"),_T("lsfreeing"),MB_YESNOCANCEL);
		return FALSE;
	}
	HWND hwnd=::CreateWindowEx(0,pszClassName,_T("ls"),WS_VISIBLE|WS_OVERLAPPEDWINDOW
		,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);//创建窗口
	if(hwnd==NULL)
	{
		
		MessageBox(NULL,_T("创建失败"),_T("ls"),MB_YESNOCANCEL);
		return FALSE;
	}
	::ShowWindow (hwnd,SW_SHOW);     //显示
	::UpdateWindow(hwnd);			 //更新
	MSG msg;
	while(GetMessage(&msg,NULL,NULL,NULL))  //第二个参数为NULL 因为消息循环接收所有窗口的消息
	{
		//消息循环
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
	}
	return TRUE;
}


      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值