win32第四天

本文深入解析Windows消息处理机制,包括消息类型、消息循环、消息队列及消息队列消息与非队列消息的区别,详细阐述了如何使用GetMessage、PeekMessage、SendMessage和PostMessage进行消息管理。

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

第四课
类样式以CS开头,如CS_HREDRAW|CS_VREDRAW
窗口样式以WS开头,WS_OVERLAPPEDWINDOW
MESSAGEBOX以MB开头MB_OK,MB_YESNOCANCEL
1.GetMessage--获取消息
BOOL GetMessage(
LPMSG lpMsg;//存放获取到的消息BUFF
HWND hWnd;//窗口句柄
UINT wMsgFilterMin;//获取消息的最小ID
UINT wMsgFilterMax;//获取消息的最大ID
);
hWnd--获取到hWnd所指定窗口的消息,如果为NULL,则抓取所有本进程的消息不管是哪一个窗口。
lpMsg--当获取到消息后,将消息的参数存放到MSG结构中。
wMsgFilterMin和wMsgFilterMax -只能获取到由它们指定的消息范围内的消息,如果都为0,表示没有范围,所有消息都抓。
PostQuitMessage()这个函数可以发送一个WM_QUIT消息,而WM_QUIT 消息可以让GetMessage()这个函数返回0.
TranslateMessage--翻译消息,将按键消息,翻译成字符消息。
BOOL TranslateMessage(
    CONST MSG *lpMsg //要翻译的消息地址
    );
    检查消息是否是按键的消息,如果不是按键消息,不做任何处理,继续执行。


Windows常用消息
消息何时产生,用来做什么,附带什么信息
WM_DESTROY窗口被销毁时的消息,无消息参数。常用于在窗口被销毁之前,做相应的善后处理,例如资源、内存等。
直接点击关闭按钮并不是出现WM_DESTROY消息。而是WM_SYSCOMMAND
WM_SYSCOMMAND - 系统命令消息,当点击窗口的最大化、最小化、关闭等命令时,收到这个消息。
常用在窗口关闭时,提示用户处理。
wParam - 具体命令,例如关闭SC_CLOSE等.
lParam - 鼠标位置
LOWORD 低字 - 水平位置
HIWORD 高字 - 垂直位置
switch(uMsg){
 case WM_DESTROY:PostQuitMessage(0);break;
 case WM_SYSCOMMAND:MessageBox(NULL,"syscommand","sys",MB_OK);break;
 return 0;
 }
 return DefWindowProc(hwnd,uMsg,wParam,lParam);
点击关闭按钮后的选择对话框:
case WM_SYSCOMMAND:
 if(wParam==SC_CLOSE){
 int nRet=MessageBox(hwnd,"真的要关闭嘛?","message",MB_YESNO);
 if(nRet==IDYES)
 MessageBox(hwnd,"关闭","dd",MB_OK);
 else
 return 0;
 break;
 }
WM_CREATE - 在窗口创建成功还未显示之前,收到这个消息。
常用于初始化窗口的参数、资源等等,包括创建子窗口等。
WPARAM - 不使用
LPARAM - 是CREATESTRUCT结构的指针,保存了CreatWindowEx中的12个参数。
case WM_CREATE:MessageBox(NULL,"WM_CREATE","create",MB_OK);break;表明在窗口显示之前这个函数被调用 。
//窗口显示前OnCreate函数获取CreateWindow中的参数
void OnCreate(LPARAM lParam){
CREATESTRUCT *pst=(CREATESTRUCT *)lParam;
CHAR szText[256];
sprintf(szText,"%s",(char*)pst->lpCreateParams);
MessageBox(NULL,szText,"infor",MB_OK);
}
利用上面的函数OnCreate在窗口显示之前创建一个子窗口,添加代码 
CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","hello",WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,g_hInstance,NULL);


WM_SIZE - 在窗口的大小发生变化后,会收到WM_SIZE。
常用于窗口大小变化后,调整窗口内各个部分的布局。
WPARAM - 窗口大小变化的原因。
LPARAM - 变化窗口客户区的大小
LOWORD - 变化后的宽度
HIOWORD- 变化后的高度
AllocConsole();给当前程序附带控制台窗口
HANDLE h_output=0;
h_output=GetStdHandle(STD_OUTPUT_HANDLE);
case WM_SIZE:OnSize(hwnd,lParam);
void OnSize(HWND hWnd,LPARAM lParam){
int nWidth=LOWORD(lParam);
int nHeight=HIWORD(lParam);
char szText[256];
sprintf(szText,"WM SIZE-宽度:%d,高度:%d\n",nWidth,nHight);
WriteConsole(h_output,szText,strlen(szText),NULL,NULL);
}  
实现功能:使窗口中控件的大小随窗口大小的改变而改变
 MoveWindow(h_edit,0,0,0.4*nWidth,0.4*nHeight,TRUE);




WM_QUIT - 用于结束消息循环处理。
wParam - PostQuitMessage 函数传递的参数。
lParam - 不使用
当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环。


WM_PAINT绘图消息
键盘消息
鼠标消息
定时器消息


GetMessage - 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,GetMessage会等候下一条消息。
PeekMessage - 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。
BOOL PeekMessage(
LPMSG lpMsg,         // message information
HWND hWnd,           // handle to window
UINT wMsgFilterMin,  // first message
UINT wMsgFilterMax,  // last message
UINT wRemoveMsg //移除标识
);
利用上述这个函数重写消息循环:
while(1){
if(!PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)){
if(!GetMessage(&nMsg,NULL,0,0))
return;
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
else{
//空闲处理
WriteConsole(h_output,"空闲处理",strlen("空闲处理"),NULL,NULL);
}
}


SendMessage - 发送消息,会等候消息处理的结果。
PostMessage - 投递消息,消息发出后立刻返回,不等候消息执行结果。
    BOOL PostMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam  //消息参数
);
    LRESULT SendMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam  //消息参数
);
PostQuitMessage调用的是PostMessage.


消息的分类
1 系统消息 - ID范围 0 - 0x03FF 
由系统定义好的消息,可以在程序中直接使用。(1000多个消息)
2 用户自定义消息 - ID范围 0x0400 - 0x7FFF 
由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理。(31743)
自定义消息宏:WM_USER
#define WM_MYMESSAGE 0x400+N(<31743)
#define WM_MYMESSAGE WM_USER+N
SendMessage/PostMessage
关于消息中的附带参数在SendMessage和PostMessage中都可以赋值。 
3 应用程序消息 - ID范围 0x8000 - 0xBFFF 
程序之间通讯时使用的消息。
应用程序消息宏:WM_APP 


4 系统注册消息 - ID范围 0xC000 - 0xFFFF 
在系统注册并生成相应消息,然后可以在各个程序中使用这个消息。


消息队列用于存放消息的一个队列,消息在队列中先入先出。所有窗口程序都具有消息队列。程序可以从队列中获取消息。
消息队列的类型
系统消息队列-由系统维护的消息队列。存放系统产生的消息,例如鼠标、键盘等。
程序消息队列-属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护。
消息队列的关系
1 当鼠标、键盘产生消息时,会将消息存放到系统消息队列
2 系统会根据存放的消息,找到对应窗口的消息队列。
3 将消息投递到程序的消息队列中。
操作系统如何将一个消息正确转发?
1.将系统消息队列中的消息提取出来。
2.根据这个消息的hWnd,提取出来。
3.在内存中获取"Main".
4.拿着这个"Main"到操作系统中去匹配窗口类名。
5.一旦匹配到窗口类,就可以确定这个窗口类的g_hInstance;
6.将这个消息扔到g_hInstance确定的程序的消息队列中。




根据消息和消息队列之间使用关系,将消息分成两类:
队列消息 - 消息的发送和获取,都是通过消息队列完成。
非队列消息 - 消息的发送和获取,是直接调用消息的窗口处理完成。
队列消息-消息发送后,首先放入队列,然后通过消息循环,从队列当中获取。
GetMessage - 从消息队列中获取消息
PostMessage - 将消息投递到消息队列
常见队列消息:WM_PAINT、键盘、鼠标、定时器。
非队列消息-消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用处理函数,完成消息。
SendMessage - 直接将消息发送给窗口的处理函数,并等候处理结果。
常见消息:WM_CREATE、WM_SIZE等。
SendMessage(hWnd,```){
1.根据hWnd找到内存
2.在内存中"Main"
3.拿着"Main"系统中匹配窗口类
return 那个窗口类中函数
}


GetMessage /PeekMessage从程序的消息队列当中,获取到消息。
TranslateMessage 检查获取到的消息,如果发现是按键消息,产生一个字符消息(WM_CHAR),并放入程序的消息队列。
DispatchMessage 根据消息,找到窗口处理函数,调用窗口处理函数,完成消息的处理。


GetMessage的全部家底,最后一次解释 
1.四个参数(&nMsg,NULL,0,0)
2.返回0 WM_QUIt
3.阻塞函数,等待消息


GetMessage/PeekMessage
1 在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(HWND,ID范围),不满足条件就不会取出消息,否则从队列取出消息返回。
2 如果程序(线程)消息队列没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程序的消息队列。
3 如果系统消息队列也没有消息,检查当前窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生WM_PAINT消息,取得消息返回处理。
4 如果没有重新绘制区域,检查定时器如果有到时的定时器,产生WM_TIMER,返回处理执行。
5 如果没有到时的定时器,整理程序的资源、内存等等。
6 GetMessage会继续等候下一条消息。PeekMessage会返回FALSE,交出程序的控制权。
注意:GetMessage如果获取到是WM_QUIT,函数会返回FALSE。
1 SendMessage
发送消息到指定的窗口处理函数,并等候对方将消息处理,然后消息执行结果,用于非队列消息的发送。
2 PostMessage
将消息放到消息队列中,立刻返回,用于队列消息的发送。
无法获知消息是否被对方处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值