WM_CLOSE、WM_DESTROY、WM_QUIT學習總結(點擊關閉按鈕會觸發WM_CLOSE消息,DestroyWindow API會觸發WM_DESTROY和WM_NCDESTROY消息,MSDN上寫的很清楚)


WM_CLOSE:關閉應用程序窗口

WM_DESTROY:關閉應用程序
WM_QUIT:關閉消息循環
只有關閉了消息循環,應用程序的進程才真正退出(在任務管理器里消失)。
win32應用程序的完整退出過程:點擊窗口右上角的關閉按鈕,發送WM_CLOSE消息。此消息處理中調用DestroyWindow函數,發送WM_DESTROY消息。此消息處理中調用PostQuitMessage(0)函數,發送WM_QUIT消息到消息隊列中。GetMessage捕獲到WM_QUIT,返回0,退出循環(應用程序真正退出)。
tips:按照上述正常流程,WM_QUIT是不會到達窗口過程的。(因為在GetMessage截獲了WM_QUIT消息之后,程序已經徹底退出了!)
 
MFC應用程序的完整退出過程:點擊窗口右上角的關閉按鈕,或選擇【File/Close】,發出 WM_CLOSE消息。CMyFrameWnd 並沒有設置WM_CLOSE 處理常式,於是交給預設之處理常式。 預設函數對於WM_CLOSE 的處理方式是呼叫 ::DestroyWindow, 並因而發出WM_DESTROY。預設之WM_DESTROY 處理方式是呼叫::PostQuitMessage,因此發出WM_QUIT。CWinApp::Run 收到WM_QUIT 后會結束其內部之訊息回路, 然后呼叫ExitInstance,這是CWinApp 的?個虛擬函數。如果自己應用程序累CMyWinApp 改寫了ExitInstance , 那么CWinApp::Run 所呼叫的就是CMyWinApp::ExitInstance,否則就是 CWinApp::ExitInstance。最后回到 AfxWinMain,執行 AfxWinTerm,結束程序。
附加:當調用DestroyWindow函數后,操作系統就會進行一系列的刪除動作,先發送WM_DESTROY消息,接着發送WM_NCDESTROY消息。如果這個窗口還有子窗口或者是其它窗口的所有者,就需要給所有子窗口發送刪除消息。
WM_QUIT是唯一可以使GetMessage(&msg,NULL,0,0)返回假值的消息.
 
相關代碼分析:
//主函數中進入消息循環的代碼片斷
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg); //將消息進行處理一下
DispatchMessage(&msg); //再將消息變量msg傳給windows,讓windows來調用消息處理函數
}
如果把GetMessage(&msg,NULL,0,0)改為GetMessage(&msg,hWnd,0,0),則發現關閉應用程序后,任務管理器中仍有該程序的進程,且占用大量的內存,why?
msdn中的原因解釋;對於GetMessage(&msg,hWnd,0,0),當第二個參數無效時,此函數返回值為-1。對於上述循環來說,此while條件為真,因此進入死循環,進程無法退出。
http://hhfighting.blog.163.com/blog/static/5570032320108215323797/
---------------------------------------------------------------------------------------------------------------
VCL里相應的代碼:
procedure TCustomForm.WMClose(var Message: TWMClose);
begin
  Close;
end;

procedure TCustomForm.Close;
var
  CloseAction: TCloseAction;
begin
  if fsModal in FFormState then
    ModalResult := mrCancel
  else
    if CloseQuery then
    begin
      if FormStyle = fsMDIChild then
        if biMinimize in BorderIcons then
          CloseAction := caMinimize else
          CloseAction := caNone
      else
        CloseAction := caHide;
      DoClose(CloseAction);
      if CloseAction <> caNone then
        if Application.MainForm = Self then Application.Terminate
        else if CloseAction = caHide then Hide
        else if CloseAction = caMinimize then WindowState := wsMinimized
        else Release;
    end;
end;

procedure TCustomForm.WMDestroy(var Message: TWMDestroy);
begin
  if NewStyleControls then SendMessage(Handle, WM_SETICON, 1, 0);
  if (FMenu <> nil) and (FormStyle <> fsMDIChild) then
  begin
    Windows.SetMenu(Handle, 0);
    FMenu.WindowHandle := 0;
  end;
  inherited;
end;

還有:

function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
  Handled: Boolean;
begin
  Result := False;
  if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
  begin
    Result := True;
    if Msg.Message <> WM_QUIT then
    begin
      Handled := False;
      if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
      if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
        not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
      begin
        TranslateMessage(Msg);
        DispatchMessage(Msg);
      end;
    end
    else
      FTerminate := True;
  end;
end;

DestroyWindow函數來自這里(TApplication.Destroy里也調用了這個函數):

procedure TWinControl.DestroyWindowHandle;
begin
  Include(FControlState, csDestroyingHandle);
  try
    if not Windows.DestroyWindow(FHandle) then
      RaiseLastOSError;
  finally
    Exclude(FControlState, csDestroyingHandle);
  end;
  FHandle := 0;
end;

那難道每個TButton,每個TPanel,都會收到WM_DESTROY消息嗎?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM