1. 程式人生 > >MFC視窗銷燬過程

MFC視窗銷燬過程

考慮單視窗情況:

假設自己通過new建立了一個視窗物件pWnd,然後pWnd->Create。則銷燬視窗的呼叫次序:

1.手工呼叫pWnd->DestroyWindow();

2.DestroyWindow會發送WM_DESTROY;

3.WM_DESTROY對應的訊息處理函式是OnDestroy();

4.DestroyWindow會發送WM_NCDESTROY;

5.WM_NCDESTROY對應的訊息處理函式是OnNcDestroy;

6.OnNcDestroy最後會呼叫PostNcDestroy;

7.PostNcDestroy經常被使用者過載以提供釋放記憶體操作。例如可以使用delete this;

通過這種方式,視窗物件對應的視窗和視窗物件本身都被釋放了。

如果含有子視窗:

      如果含有子視窗,則呼叫父視窗的DestroyWindow時,它會向子視窗傳送WM_DESTROY和WM_NCDESTROY訊息。

      具體呼叫順序參考下文的例子。

DestroyWindowdelete的影響:

      應該說前者對後者並沒有什麼影響。但經常在DestroyWindow間接導致執行的PostNcDestroy中delete視窗物件指標,即delete this。

      CView::PostNcDestroy中唯一的操作就是delete this;CframeWnd::PostNcDestory也是如此。而預設的CWnd::PostNcDestroy是空操作,CDialog中也沒有對其進行過載,即也是空。

deleteDestroy的影響:

      delete會導致解構函式。CWnd的解構函式中有對DestroyWindow的呼叫,但必須保證:

m_hWnd != NULL &&

           this != (CWnd*) & wndTop && this != (CWnd*)&wndBottom &&

           this != (CWnd*)&wndTopMost && this != (CWnd*)&wndNoTopMost。

      Cdialog的解構函式中也有對DestroyWindow的呼叫,但條件比較鬆,只需要m_hWnd != NULL。另外Cdialog::DoModal也會呼叫DestroyWindow。

      CFrameWnd的OnClose中會呼叫DestroyWindow,但其析構中不會呼叫DestroyWindow。

      CView的析構也不會呼叫DestroyWindow。

一個SDI程式的銷燬過程

      有CMainFrame類、CMyView類。並且CMyView有兩個子視窗CMyDlg和CmyWnd的例項。

      點選退出按鈕,CMainFrame會收到WM_CLOSE訊息。CframeWnd(CMainFrame的父類)間接會呼叫CWnd::DestroyWindow;它首先向CMyView傳送WM_DESTORY和WM_NCDESTROY訊息,並引發相應的處理函式;然後向CMyDlg傳送WM_DESTORY和WM_NCDESTROY訊息,並引發相應的處理函式;然後向CMyWnd傳送WM_DESTORY和WM_NCDESTROY訊息,並引發相應的處理函式。

      具體的執行順序是:

1.呼叫CMainFrame::DestroyWindow

2.CFrameWnd::OnDestroy

3.CMyView::OnDestroy

4.CmyWnd::OnDestroy

5.CmyDlg::OnDestroy

6.CmyWnd::PostNcDestroy

7.CmyWnd的析構

8.CmyDlg::OnDestroy

9.CmyDlg的析構

10.CMyView::PostNcDestroy

11.CmyView的析構

12.CMainFrame的析構

13.CMainFrame::DestroyWindow退出

上面情況是假設我們在CmyWnd和CmyDlg的PostNcDestroy中添加了delete this。如果沒有新增,則7,10不會執行。

      因為CView::PostNcDestroy中呼叫了delete this,所以然後會執行CMyView的析構操作。因為CframeWnd::PostNcDestroy中呼叫了delete this,所以最後執行CMainFrame的析構操作。

      如果自己的CmyDlg和CmyWnd在PostNcDestroy中有delete this;則二者會被析構。否則記憶體洩漏。當然delete也可以放在CMyView的析構中做,只是不夠OO。

總結

      可以有兩種方法銷燬視窗物件對應的視窗和釋放視窗物件指標。一種是通過DestroyWindow。這是比較好的方法,因為最後MFC會自動相應WM_CLOSE導致CframWnd::DestroyWindow被呼叫,然後會一次釋放所有子視窗的控制代碼。使用者需要做的是在PostNcDestroy中釋放堆視窗物件指標。但因為某些物件是在棧中申請的,所以delete this可能出錯。這就要保證寫程式時自己建立的視窗儘量使用堆申請。

      另一種是delete。Delete一個視窗物件指標有的視窗類(如CWnd,Cdialog)會間接呼叫DestroyWindow,有的視窗類(如CView,CframeWn)不會呼叫DestroyWindow。所以要小心應對。

      二者是相互呼叫的,很繁瑣。

一個MFC視窗物件包括兩方面的內容:一是視窗物件封裝的視窗,即存放在m_hWnd成員中的HWND(視窗控制代碼),二是視窗物件本身是一個C++物件。要刪除一個MFC視窗物件,應該先刪除視窗物件封裝的視窗,然後刪除視窗物件本身。

刪除視窗最直接方法是呼叫CWnd::DestroyWindow::DestroyWindow,前者封裝了後者的功能。前者不僅會呼叫後者,而且會使成員m_hWnd儲存的HWND無效(NULL)。如果DestroyWindow刪除的是一個父視窗或擁有者視窗,則該函式會先自動刪除所有的子視窗或被擁有者,然後再刪除父視窗或擁有者。在一般情況下,在程式中不必直接呼叫DestroyWindow來刪除視窗,因為MFC會自動呼叫DestroyWindow來刪除視窗。例如,當用戶退出應用程式時,會產生WM_CLOSE訊息,該訊息會導致MFC自動呼叫CWnd::DestroyWindow來刪除主框架視窗,當用戶在對話方塊內按了OKCancel按鈕時,MFC會自動呼叫CWnd::DestroyWindow來刪除對話方塊及其控制元件。

視窗物件本身的刪除則根據物件建立方式的不同,分為兩種情況。在MFC程式設計中,會使用大量的視窗物件,有些視窗物件以變數的形式嵌入在別的物件內或以區域性變數的形式建立在堆疊上,有些則用new操作符建立在堆中。對於一個以變數形式建立的視窗物件,程式設計師不必關心它的刪除問題,因為該物件的生命期總是有限的,若該物件是某個物件的成員變數,它會隨著父物件的消失而消失,若該物件是一個區域性變數,那麼它會在函式返回時被清除。

對於一個在堆中動態建立的視窗物件,其生命期卻是任意長的。初學者在學習C++程式設計時,對new操作符的使用往往不太踏實,因為用new在堆中建立物件,就不能忘記用delete刪除物件。讀者在學習MFC的例程時,可能會產生這樣的疑問,為什麼有些程式用new建立了一個視窗物件,卻未顯式的用delete來刪除它呢?問題的答案就是有些MFC視窗物件具有自動清除的功能。

如前面講述非模態對話方塊時所提到的,當呼叫CWnd::DestroyWindow::DestroyWindow刪除一個視窗時,被刪除視窗的PostNcDestroy成員函式會被呼叫。預設的PostNcDestroy什麼也不幹,但有些MFC視窗類會覆蓋該函式並在新版本的PostNcDestroy中呼叫delete this來刪除物件,從而具有了自動清除的功能。此類視窗物件通常是用new操作符建立在堆中的,但程式設計師不必操心用delete操作符去刪除它們,因為一旦呼叫DestroyWindow刪除視窗,對應的視窗物件也會緊接著被刪除。

不具有自動清除功能的視窗類如下所示。這些視窗物件通常是以變數的形式建立的,無需自動清除功能。

所有標準的Windows控制元件類。

1.從CWnd類直接派生出來的子視窗物件(如使用者定製的控制元件)。

2.切分視窗類CSplitterWnd

3.預設的控制條類(包括工具條、狀態條和對話條)。

4.模態對話方塊類。

具有自動清除功能的視窗類如下所示,這些視窗物件通常是在堆中建立的。

1.主框架視窗類(直接或間接從CFrameWnd類派生)。

2.檢視類(直接或間接從CView類派生)。

讀者在設計自己的派生視窗類時,可根據視窗物件的建立方法來決定是否將視窗類設計成可以自動清除的。例如,對於一個非模態對話方塊來說,其物件是建立在堆中的,因此應該具有自動清除功能。

綜上所述,對於MFC視窗類及其派生類來說,在程式中一般不必顯式刪除視窗物件。也就是說,既不必呼叫DestroyWindow來刪除視窗物件封裝的視窗,也不必顯式地用delete操作符來刪除視窗物件本身。只要保證非自動清除的視窗物件是以變數的形式建立的,自動清除的視窗物件是在堆中建立的,MFC的執行機制就可以保證視窗物件的徹底刪除。

如果需要手工刪除視窗物件,則應該先呼叫相應的函式(如CWnd::DestroyWindow)刪除視窗,然後再刪除視窗物件.對於以變數形式建立的視窗物件,視窗物件的刪除是框架自動完成的.對於在堆中動態建立了的非自動清除的視窗物件,必須在視窗被刪除後,顯式地呼叫delete來刪除物件(一般在擁有者或父視窗的解構函式中進行).對於具有自動清除功能的視窗物件,只需呼叫CWnd::DestroyWindow即可刪除視窗和視窗物件。注意,對於在堆中建立的視窗物件,不要在視窗還未關閉的情況下就用delete操作符來刪除視窗物件

相關推薦

MFC視窗銷燬過程

考慮單視窗情況: 假設自己通過new建立了一個視窗物件pWnd,然後pWnd->Create。則銷燬視窗的呼叫次序: 1.手工呼叫pWnd->DestroyWindow(); 2.DestroyWindow會發送WM_DESTROY; 3.WM_DESTROY對

總結MFC視窗銷燬過程

考慮單視窗情況: 假設自己通過new建立了一個視窗物件pWnd,然後pWnd->Create。則銷燬視窗的呼叫次序: 1.手工呼叫pWnd->DestroyWindow(); 2.DestroyWindow會發送WM_DESTROY; 3.WM_DESTROY

MFC 視窗銷燬過程

考慮單視窗情況:   假設自己通過new建立了一個視窗物件pWnd,然後pWnd->Create。則銷燬視窗的呼叫次序:

MFC視窗的清除過程[轉]

對於vc++初學者來說,總覺得視窗物件的清除過程有些莫名其妙.在程式中看不到對delete的顯式呼叫,這似乎違反了c++中有關初始化和清除的規則.那麼,程式是怎樣取消一個視窗物件? 要消除視窗物件,必須清楚視窗物件的構成.在一個通常的程式中,先建立c++視窗物件,然後由Windows建立實際

MFC 建立非模態對話方塊和銷燬過程

今天專案中遇到的問題,記錄下來,做個總結。 一個簡單的目的是建立一個非模態對話方塊並在對話方塊關閉後將其銷燬。 這裡的銷燬包括:銷燬對話方塊物件資源和對話方塊物件指標; 首先說建立對話方塊: 一、模態對話方塊(model dialog box) 在程式執行的過程中,若出

MFC視窗的建立過程詳細解析

MFC視窗的建立過程詳細解析 關於MFC的視窗創建過程一直感覺比較神祕,那麼我們來看下MFC中的視窗創建到底是一個什麼過程(視窗創建前的視窗類準備就直接忽略了,與標準Win32視窗類準備大同小異)。MFC中視窗創建主要涉及三個重要的函式,分別是CWnd::CreateEx(

vs2010、MFC視窗中繪製點、線、面

詳細地記錄了一下在VS2010中建立MFC工程的過程,以及繪製點、線、面功能的實現。因為是教學所用,所以過程記錄的比較繁瑣。主要包含了如何建立在MFC中建立MFC工程、繪製固定座標的圖形、通過滑鼠繪製線段。 一、建立MFC工程  

單文件mfc視窗分割

說明:第一次發表部落格,全當為自己學習做個記錄,將自己的學習新東西和bug整理記錄,方便自己日後的學習。內容有借鑑別人的地方,結尾均附上別人的連結。 1、新建單文件專案,生成如下幾個類 2、在mainFrm。h檔案中新增如下程式碼 CSplitterWnd m_spl

MFC視窗風格 WS_style/WS_EX_style

視窗風格(Window style) WS_BORDER   有邊框視窗 WS_CAPTION   必須和WS_BORDER風格配合,但不能與WS_DLGFRAME風格一起使用。指示視窗包含標題要部分。 WS_CHILD  

MFC視窗位置和大小的獲取

最近在做一個專案,需要控制元件隨對話方塊大小的變化而變化,因此需要準確獲取對話方塊視窗、控制元件的大小和位置。 經過好一番查尋、測試,終於看到了希望。下面是一些獲取視窗位置和大小的函式,示例如下: 1、獲取螢幕解析度 //下邊兩個函式獲取的是顯示螢幕的大小,但不包括工作列等區域 in

VS2010 MFC視窗程式 pugixml讀寫XML

       為了用VC++讀寫XML檔案前後弄了差不多5天了,試過微軟自家的MSXML和libxml2庫,介紹MSXML的相關書籍和CSDN部落格裡的文章基本全是XP時代的MSXML4.dll,WINDOWS 7 system32目錄只有MSXML3.d

MFC視窗之間傳遞資料(結構體)

MFC視窗之間的通訊一般會利用傳送訊息的方式傳遞,那麼具體如何實現呢,程式碼如下: 下面實現的是一個子視窗把訊息傳送到主視窗的示例: 1.訊息傳送視窗部分程式碼: 首先新增自定義訊息; #defi

MFC視窗程式退出訊息的響應

1.MFC三個結束訊息的區別 WM_CLOSE: 在系統選單裡選擇了“關閉”或者點選了視窗右上角的“X”按鈕,你的視窗過程就會收到WM_CLOSE。DefWindowProc對 WM_CLOSE的處理是呼叫DestroyWindow。當然,你可以不讓DefWin

MFC視窗風格 WS_style/WS_EX_style(超詳細)

視窗風格(Window style) WS_BORDER 有邊框視窗 WS_CAPTION 必須和WS_BORDER風格配合,但不能與WS_DLGFRAME風格一起使用。指示視窗包含標題要部分。 WS_CHILD 說明視窗為子視窗,不能應用於彈出式視窗風格(WS_POPUP)。

MFC視窗動態改變其child模態或popup模態

在dialog的虛擬函式 PreSubclassWindow中設定視窗模式 void CMyDlg::PreSubclassWindow() { long lStyle=GetWindowLong(m_hWnd,GWL_STYLE); //獲取風格 if (m_bCh

MFC(2):底層實現視窗MFC視窗建立與訊息對映、windows字符集和嚮導的使用

=====================從底層去實現一個視窗=============== 程式入口是WinMain函式 視窗的建立步驟: -->  設計(WNDCLASS)  -->  註冊(RegisterClass)  -->

MFC OnFileNew OnFileOpen過程分析程式碼(一)

原文:http://blog.csdn.net/teleinfor/article/details/1856725 對OnFileNew()/OnFileOpen()的MFC程式碼跟蹤簡析,簡析可能也談不上了,為了快速的理解MFC的實現思路以及文件檢視架構的應用,在學習的過程當中我也沒有進

Window視窗建立過程

Win32專案—用C語言寫的。。。 #include<windows.h> #include "stdio.h" /* 1.定義入口函式winMain() 2.建立一個視窗 A.設計視窗類WNDCLASS(給成員變數賦值) B.註冊視窗類 C.建

如何去除MFC視窗的自動記憶功能 (如去除工具欄,選單欄上次執行程式自動儲存的內容)

BCG登錄檔清除: 第一次在CXXXApp::ExitInstance() 加入CleanState(), 執行一次 接著註釋掉,再在OnInitInstance加入m_bSaveState=FALSE 估計在BCG控制元件要寫登錄檔的時候,它自己的寫入登錄檔函式會判斷m

基於對話方塊的MFC視窗之間值的傳遞

編碼時碰到一個MFC多個對話方塊視窗之間值的傳遞的問題,花了些時間總結一下。問題具體是這樣的: 單擊CWorkerBorrow對話方塊類中的“新增借調“功能按鈕,彈出CMBorrow對話方塊來編輯資訊,然後滑鼠點選CEdit型別的編輯框區域,在CMBorrow對話方塊上彈出