1. 程式人生 > >MFC中的DestroyWindow詳解

MFC中的DestroyWindow詳解

考慮單視窗情況:

假設自己通過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_DESTROYWM_NCDESTROY訊息。

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

DestroyWindowdelete的影響:

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

      CView::PostNcDestroy中唯一的操作就是delete thisCframeWnd::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

      CFrameWndOnClose中會呼叫DestroyWindow,但其析構中不會呼叫DestroyWindow

      CView的析構也不會呼叫DestroyWindow

一個SDI程式的銷燬過程

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

點選退出按鈕,CMainFrame會收到WM_CLOSE訊息。CframeWndCMainFrame的父類)間接會呼叫CWnd::DestroyWindow;它首先向CMyView傳送WM_DESTORYWM_NCDESTROY訊息,並引發相應的處理函式;然後向CMyDlg傳送WM_DESTORYWM_NCDESTROY訊息,並引發相應的處理函式;然後向CMyWnd傳送WM_DESTORYWM_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退出

上面情況是假設我們在CmyWndCmyDlgPostNcDestroy中添加了delete this。如果沒有新增,則710不會執行。

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

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

總結

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

另一種是deleteDelete一個視窗物件指標有的視窗類(如CWndCdialog)會間接呼叫DestroyWindow,有的視窗類(如CViewCframeWn)不會呼叫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操作符來刪除視窗物件.

轉自http://blog.csdn.net/xiaoxiongli/article/details/1670277

相關推薦

MFCDestroyWindow

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

JSJSON

名稱 完全 rip json詳解 core 兼容 json字符串 之間 org JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式,采用完全獨立於語言的文本格式,是理想的數據交換格式。同時,JSON是 JavaScript 原生格式

nodeJsnpm

commonjs -s license mon sem console 能力 效應 模塊安裝 npm 是 Node.js 的模塊依賴管理工具。作為開發者使用的工具,主要解決開發 node.js 時會遇到的問題。如同 RubyGems 對於 Ruby 開發者和 Maven 對

006_netstatstate

51cto time list osi lose 手動 請求 等待 沒有 TCP三次握手的過程如下: 主動連接端發送一個SYN包給被動連接端; 被動連接端收到SYN包後,發送一個帶ACK和SYN標誌的包給主動連接端; 主動連接

EditTextinputType

trac extc isa share bsp input itl 浮點 ttext <EditText Android:layout_width="fill_parent" android:layout_height="wrap_content" android

linuxtop

linux查看進程之top詳解簡介top命令是Linux下常用的性能分析工具,能夠實時顯示系統中各個進程的資源占用狀況,類似於Windows的任務管理器。top顯示系統當前的進程和其他狀況,是一個動態顯示過程,即可以通過用戶按鍵來不斷刷新當前狀態.如果在前臺執行該命令,它將獨占前臺,直到用戶終止該程序為止.

視覺SLAM相機

目的 攝像頭 像素 一定的 原理 接收 計算 傳感 span 視覺SLAM中,通常是指使用相機來解決定位和建圖問題。 SLAM中使用的相機往往更加簡單,不攜帶昂貴的鏡頭,以一定的速率拍攝周圍的環境,形成一個連續的視頻流。 相機分類: 單目相機:只是用一個攝像頭進行SLAM的

04-LinuxDNS(一)

訪問 舉例 dynamic linux下 目錄 col ofo 圖片 nslookup 零、關於配置Linux下的DNS中一些名詞的解釋請參見文章“03-關於配置Linux下的DNS中一些名詞的解釋(轉自網絡)”自行學習一、關於DNS配置文件查看DNS配置文件: rpm -

05-LinuxDNS(二)

相關 proc gen lin 四種方法 .... rate 我的網站 四種 接“04-Linux中DNS詳解(一)” 六、在Linux上測試域名解析1、先檢查DNS是否設置正確 cat /etc/resolv.conf [resolv.conf] # Generate

07-LinuxDNS(四)

用戶 mail all 驗證 src 更改 條目 http nslookup 接“06-Linux中DNS詳解(三)” 九、配置主從DNS服務器實現域名解析容錯 1、實驗環境zhangyujia.com(192.168.80.100)為主區域,com(192.168.8

Angular JS 指令

scope [] 功能 spa fun table clas rest 方法 Angular JS的強大功能就在於其可以自定義很多指令,現在就指令做一下詳細的剖析。 一個Angular js 指令(directive)的生命周期 開始於$compile方法 結束於$link

ES6 Promise

out 保持 type xxxxx 承諾 操作 結束 span aso Promise,簡單說就是一個容器,裏面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。 Promise 提供統一的 API

LeetCode-4. 兩個排序數組的位數()

說了 AC problems arr scrip print 奇數 時間復雜度 兩個 鏈接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/ 有兩個大小為 m 和 n

生成器接受和返還功能在執行過程

top exce ret one 代碼 stop ngx put rsa 1 import random 2 3 SENTENCES=[ 4 ‘How are you ?‘, 5 ‘Fine,thank you!‘, 6 ‘Nothi

Spring Boot 2.0 Intellij Idea 圖文打包成可執行Jar

off aps cycle 找到 sna 打包 AS main 切換 我們使用Spring Boot 2.0 創建好我們的項目後,我們一般需要打包,然後部署到服務器上。 打包步驟: 1. 選中項目,右鍵——> Open Module Settings. 2. 切換

DelphiTApplication(轉僅供自己參考)

exce 停止 main roc 參數 reference pause 響應 選擇 轉自:http://blog.sina.com.cn/s/blog_4d6f55d90100bmv9.html   TApplication是用於Delphi應用程序的類型,該類在單元fo

CentOS 7 Systemd

cts 模擬 lld 標記 httpd sco fail cati crs CentOS 7 中 Systemd詳解 [日期:2016-12-01] 來源:Linux社區 作者:lxlxlx [字體:大 中 小] 目錄 一、syst

PHPcurl

aid ftp上傳 直接 分享圖片 tran ret 交流 init https 定義 curl是一個庫,能讓你通過URL和許多不同種的服務器進行勾搭、搭訕和深入交流,並且還支持許多協議。並且curl可以支持https認證、http post、ftp上傳、代理、cookie

JavascriptDOM與學習

DOM(文件物件模型)是針對html和XML文件的一個API(應用程式程式設計介面)。DOM描繪了一個層次化的節點樹,允許開發人員新增,移除和修改頁面的某一部分。下面將從這幾個層次來學習。 一、節點層次 1、DOM可以將任何HTML或XML文件描繪成一個由多層節點構成的結構。節點分為幾種不同的型別,每種型