PostQuitMessage, PostThreadMessage( WM_QUIT )

http://blogs.msdn.com/b/oldnewthing/archive/2005/11/04/489028.aspx

Why is there a special PostQuitMessage function?

Because it's not really a posted message.

Commenter A. Skrobov asked, "What's the difference 

between PostQuitMessage and PostThreadMessage (GetCurrentThreadId, WM_QUIT)?"

They are not equivalent, though they may look that way at first glance.

The differences are subtle but significant.

Like the WM_PAINTWM_MOUSEMOVE, and WM_TIMER messages,

the WM_QUIT message is not a "real" posted message.

Rather, it is one of those messages that the system generates as if it were posted, even though it wasn't.

And like the other messages, the WM_QUIT message is a "low priority" message,

generated only when the message queue is otherwise empty.

When a thread calls PostQuitMessage, a flag in the queue state is set that says,

"If somebody asks for a message and there are no posted messages, then manufacture a WM_QUIT message."

This is just like the other "virtually posted" messages. 

WM_PAINT messages are generated on demand if there are any invalid regions, 

WM_MOUSEMOVE messages are generated on demand if the mouse has moved since the last time you checked, and 

WM_TIMER messages are generated on demand if there are any due timers.

And since the message is "virtually posted", multiple calls coalesce,

in the same way that multiple paint messages, multiple mouse motions, and multiple timer messages also coalesce.

Why is WM_QUIT handled like a low-priority message?

Because the system tries not to inject a WM_QUIT message at a "bad time";

instead it waits for things to "settle down" before generating the WM_QUIT message,

thereby reducing the chances that the program might be in the middle of a multi-step procedure triggered by a sequence of posted messages.

 

If you PeekMessage(..., PM_NOREMOVE) a WM_QUIT message, this returns a WM_QUIT message but does not clear the flag.

The WM_QUIT message virtually "stays in the queue". You can peek it use PeekMessage(..., PM_NOREMOVE) again ?

 

复制代码
  i := 0;
  while TRUE do
  begin
    if LongInt( PeekMessage( Msg, 0, 0, 0, PM_REMOVE ) ) > 0 then
    begin
      case Msg.message of
        WM_QUIT :
          begin
            Inc( i );
            if i = 1 then           // First WM_QUIT posted by other thread
            begin
              for j := 0 to 100 do
                PostQuitMessage( j );    // only 1 WM_QUIT in queue !
            end else if i = 100 then     // i = 2 
              break;              // Never be executed, unless other thread posted WM_QUIT again  
          end;
      end;
    end else begin
      Sleep( 10 );
    end;
  end;
复制代码

 

Only can peek WM_QUIT once even if more WM_QUIT posted !

复制代码
  i := 0;
  while TRUE do
  begin
    if LongInt( PeekMessage( Msg, 0, 0, 0, PM_REMOVE ) ) > 0 then
    begin
      case Msg.message of
        WM_QUIT :
          begin
            Inc( i );
            if i = 1 then         // First WM_QIUT from other thread       
            begin
              for j := 0 to 100 do
              begin
                PostQuitMessage( j );  // Only set "quit message pending" flag
                PostThreadMessage( GetCurrentThreadId( ), WM_USER+j, 0, 0 ); // 1024, 1025, .... 
              end;
            end else if i = 100 then  // Next WM_QUIT from this thread, but no more ...
              break;
          end;
        else
          begin
            Sleep( 1 );           // 1024, 1025, ...
          end;
      end;
    end else begin
      Sleep( 1 );              // 
    end;
  end;
复制代码

 

 

复制代码
  i := 0;
  while TRUE do
  begin
    if LongInt( PeekMessage( Msg, 0, 0, 0, PM_REMOVE ) ) > 0 then
    begin
      case Msg.message of
        WM_QUIT :
          begin
            Inc( i );
            if i = 1 then
            begin
              for j := 0 to 100 do
              begin
                PostThreadMessage( GetCurrentThreadId( ), WM_QUIT, 0, 0 );    
                PostThreadMessage( GetCurrentThreadId( ), WM_USER+j, 0, 0 );   // WM_QUIT, WM_USER+0, WM_QUIT, WM_USER+1, ... 
              end;
            end else if i = 100 then
              break;
          end;
        else
          begin
            Sleep( 1 );
          end;
      end;
    end else begin
      Sleep( 1 );
    end;
  end;

// Exit from here
复制代码

 

As another special behavior, the generated WM_QUIT message

bypasses the message filters passed to the GetMessage and PeekMessage functions.

If the internal "quit message pending" flag is set, then you will get a WM_QUIT message once the queue goes quiet, regardless of what filter you pass.

By comparison, PostThreadMessage just places the message in the thread queue (for real, not virtually),

and therefore it does not get any of the special treatment that a real PostQuitMessage triggers.

 


 

PostQuitMessage : Set "quit message pending" flag, Generate a WM_QUIT when the queue goes quit

PostThreadMessage : Place WM_QUIT in queue


 

 

Thread0 : PostThreadMessage( ThreadId, WM_QUIT )

Thread1 : PostThreadMessage( ThreadId, WM_USER )

Thread2 : PostThreadMessage( ThreadId, WM_XXXX )

Thread3 : PostThreadMessage( ThreadId, WM_QUIT )

Thread4 : PostThreadMessage( ThreadId, WM_YYYY )

PeekMessage() : WM_USER, WM_XXXX, WM_YYYY, WM_QUIT

Because the system tries not to inject a WM_QUIT message at a "bad time";

instead it waits for things to "settle down" before generating the WM_QUIT message,

thereby reducing the chances that the program might be in the middle of a multi-step procedure triggered by a sequence of posted messages.

 

函数GetMessage里是使用一个循环不断地检测消息,周止复始的,是不可能出现死亡的,但它会检测到消息WM_QUIT就退出来。
 
那现在问题是谁发送WM_QUIT消息出来呢?这就是PostQuitMessage函数所做的工作。
 
当你点击窗口右上角的关闭时,Windows就会把窗口从系统里删除,这时就会发出消息WM_DESTROY给窗口消息处理函数WindowProc,
 
WindowProc收到这条消息后,最需要做的一件事情就是调用PostQuitMessage发出退出消息,让消息循环结束。
 
函数GetMessage检测到消息WM_QUIT就退出来。
 
函数PostQuitMessage声明如下:
 
WINUSERAPI
VOID
WINAPI
PostQuitMessage(
    __in int nExitCode); 

nExitCode是退出标识码,它被放到WM_QUIT消息的参数wParam里。

PostQuitMessage寄送一个WM_oUT消息给线程的消息队列并立即返回;

此函数向系统表明有个线程请求在随后的某一时间终止。

当线程从消息队列里取得WM_QUIT消息时,应当退出消息循环并将控制返回给系统。

返回给系统的退出值必须是消息WM_QUIT的wParam参数。

复制代码
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 int wmId, wmEvent;
 PAINTSTRUCT ps;
 HDC hdc;

 switch (message)
 {
 case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);

        switch (wmId)
        {
        case IDM_ABOUT:
              DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
              break;
        case IDM_EXIT:
              DestroyWindow(hWnd);
              break;
        default:
              return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
        
 case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        //
        EndPaint(hWnd, &ps);
        break;
        
 case WM_DESTROY:
       PostQuitMessage(0);
       break;
default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
复制代码

 

posted @   IAmAProgrammer  阅读(2084)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
历史上的今天:
2012-09-19 解析“0”的读法
2012-09-19 汉语拼音方案里的O(哦)和 UO(窝)
点击右上角即可分享
微信分享提示