SendMessage与PostMessage的区别

发表于2018-09-29
评论0 3k浏览
SendMessage与PostMessage的区别:

SendMessage函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回,可以简单理解SendMessage函数是阻塞的。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回,PostMessage函数是非阻塞的。

函数原型:

SendMessage函数的原型为 
LRESULT SendMessage( 
  HWND hWnd, 
  UINT Msg, 
  WPARAM wParam, 
  LPARAM lParam 
);

参数:

hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。

备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。
如果指定的窗口是由调用线程创建的,则窗口程序立即作为子程序调用。
如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。

PostMessage:

函数功能:该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。消息队列里的消息通过调用GetMessage和PeekMessage取得。

函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

参数hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。
NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
IParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。

备注:需要以HWND_BROADCAST方式通信的应用程序应当用函数RegisterwindwosMessage来获得应用程序间通信的独特的消息。如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage.SendNotifyMessage,SendMesssgeCallback),消息参数不能包含指针。否则,操作将会失败。函数将再接收线程处理消息之前返回,发送者将在内存被使用之前释放

GetMessage和PeekMessage的区别

在Win32中使用GetMessage和PeekMessage都可以获取对应该程序产生的消息。

GetMessage的一般用法是GetMessage(&msg,NULL,0,0);

这样可以接受所有的消息,GetMessage在没有产生消息的时候并不返回,而是一直在等待,直到一个消息返回;当消息不是WM_QUIT时,返回一个非零值,也就是说,当是WM_QUIT时会返回一个零。如果你在使用中如下使用:
While(true)
{
    if(GetMessage(&msg,NULL,0,0))
     break;
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

则会出现问题,什么问题呢,就是你结束程序时,窗口是结束了。但是你去任务管理器里看,还能看到那个进程。所以正确的用法应是:
While(GetMessage(&msg,NULL,0,0))
{
      TranslateMessage(&msg);
      DispatchMessage(&msg);
}

PeekMessage不管有没有消息都会返回一个值,有消息是非零值,没有消息则是零值。所以如果上面代码用PeekMessage的话就不会出现这样的问题了。
在使用PeekMessage的时候需要指定对消息的处理方法,一般使用PM_REMOVE,即删除消息。

PeekMessage(&msg,NULL,0,0,PM_REMOVE);
使用这个函数一个问题是他会一直占用你的CPU,因为一般情况下我们会一直让他循环,而这个函数就会一直不停的取消息。当然这两个函数各有各的好处,PeekMessage可以在没有输入消息的时候也处理一些事情。

关于这个两个函数的详细信息:
BOOL GetMessage(
       LPMSG lpMsg,         // 一个MSG的指针
       HWND hWnd,           // 一般为当前窗口的句柄
       UINT wMsgFilterMin,  // 要取的消息的最小值
       UINT wMsgFilterMax   // 要取的消息的最大值);

UINT wMsgFilterMax//要取的消息的最大值);如果第三,四个参数都为零,则取所有的消息。如果出现错误,比如参数一或参数而指向的指针或句柄无效,则会返回-1.
BOOL PeekMessage(
       LPMSG lpMsg,        
       HWND hWnd,          
       UINT wMsgFilterMin, 
       UINT wMsgFilterMax,   //前四个参数和GetMessage的一样
       UINT wRemoveMsg      // 取完消息要做的操作);

UINT wRemoveMsg//取完消息要做的操作);最后一个参数有PM_NOREMOVE和PM_REMOVE两种方式,前一种就是取完消息后不删除消息,不知道这中方式在什么情况下会采用,我目前还没有见过。一般都是采用后一种删除的方法。

两个函数主要有以下两个区别:
  1. GetMessage将等到有合适的消息时才返回,而PeekMessage只是撇一下消息队列。
  2. GetMessage会将消息从队列中删除,而PeekMessage可以设置最后一个参数wRemoveMsg来决定是否将消息保留在队列中。
在Windows的内部,GetMessage和PeekMessage执行着相同的代码。而两者最大的不同之处则体现在没有任何消息返回到应用程序的情况下。在此种情况下,PeekMessage会返回一个空值到应用程序,GetMessage会在此时让应用程序休眠。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引