1. 程式人生 > >GetMessage函式第二個引數的問題

GetMessage函式第二個引數的問題

轉載地址:https://blog.csdn.net/shyrgst/article/details/7322268

今天在學習VC++深入詳解的過程中發現當GetMessage的Hwnd引數不為NULL的時候,會導致應用程式接收不到WM_QUIT訊息,此時關閉視窗時,視窗可以正常析構但是應用程式不會正常退出,必須通過工作管理員結束。原因如下:

from:http://fyca.blog.163.com/blog/static/129633842006227134350/

HWND hWnd = CreateWindowEx(...);

MSG msg;

while( TRUE ) {
   if( GetMessage( &msg, NULL, 0, 0 ) == FALSE )
      break;
   TranslateMessage( &msg );
   DispatchMessage( &msg );
}

訊息迴圈這樣寫當然沒問題, 但為什麼GetMessage的第二個引數不能是視窗的控制代碼hWnd呢, 畢竟當前程式只有一個視窗啊? 如果是hWnd, 程式執行時沒有任何問題, 但是當你將視窗關閉後會發現程式並未真正退出, 而且此時cpu佔用為100%, Why?

MSDN中解釋如下:

當GetMessage第二個引數為NULL時:
GetMessage retrieves messages for any window that belongs to the calling thread and thread messages posted to the calling thread using the PostThreadMessage

function.

中文翻譯:GetMessage取得 那些屬於呼叫執行緒的視窗的訊息 和 通過PostThreadMessage函式投遞(傳送)到呼叫執行緒的執行緒訊息**.

**這樣問題就明白了, GetMessage需要檢索到WM_QUIT返回一個FALSE結束訊息迴圈, 而WM_QUIT是通過PostQuitMessage(0){IN WM_DESTROY OF WindowProc}傳送, 屬於執行緒訊息, 而非普通的視窗訊息. 如果在GetMessage中用hWnd而不是NULL, 雖然WM_QUIT 訊息仍會出現在程式的訊息佇列中,但GetMessage卻無法檢索到, 而且此時視窗已經被銷燬了, 如果還想取得hWnd的視窗訊息, 只可能發生錯誤( cpu佔用100%, 死迴圈? )**.

也適用於PeekMessage

所以,當視窗被銷燬的時候,視窗的控制代碼自然也就是無效控制代碼了,那麼GetMessage將返回-1。所以迴圈為死迴圈。

在MSDN中,推薦的程式碼寫法是這樣的,

Return Values

If the function retrieves a message other than WM_QUIT, the return value is nonzero.

If the function retrieves the WM_QUIT message, the return value is zero.

If there is an error, the return value is -1. For example, the function fails if hWnd is an invalid window handle or lpMsg is an invalid pointer. To get extended error information, call GetLastError.

Warning   Because the return value can be nonzero, zero, or -1, avoid code like this:

while (GetMessage( lpMsg, hWnd, 0, 0)) ...

The possibility of a -1 return value means that such code can lead to fatal application errors. Instead, use code like this:

BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}