最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

【滴水基礎(chǔ)】5.MFC(1)

2023-03-13 04:09 作者:沙漠里的鯨  | 我要投稿

第一:MFC本質(zhì)

#MFC介紹(Microsoft Fundation Classes)

---由微軟提供的放置Win32Api的,面向?qū)ο蟮陌bC++類庫

---MFC中大約封裝了2000個(gè)類,分別封裝了WinApiWinSDK中的結(jié)構(gòu)和過程

---另外,MFC提供了1個(gè)應(yīng)用程序框架,例如:程序向?qū)А㈩愊驅(qū)У淖灾a生成,提高了編碼效率

#Win32的Api、SDK和MFC區(qū)別

---API就是應(yīng)用程序接口,是由系統(tǒng)提供的一些函數(shù),比如你想創(chuàng)建一個(gè)文件,就要調(diào)用CreateFile,這個(gè)CreateFile就是一個(gè)API。
---SDK是指一些公司針對某一項(xiàng)技術(shù)為軟件開發(fā)人員制作的一套輔助開發(fā)的工具。一般專指Windows系統(tǒng)提供的相關(guān)的頭文件LIB文件。
---MFC是MS對API的一個(gè)封裝,也就是一個(gè)C++類庫,當(dāng)然MFC比一般類庫龐大,所以有人稱之為應(yīng)用程序框架。但其本質(zhì)還是一個(gè)類庫

#MFC的本質(zhì)

---對于Win32Api和Win32SDK的封裝

#使用Win32創(chuàng)建窗口(窗口的消息流程)

---1.OS捕獲鍵盤輸入,傳遞給線程消息隊(duì)列(RegisterClass)

---2.線程不斷的獲取消息(GetMessage),對獲取的消息,進(jìn)行翻譯(TranslateMessage)為字符碼

---3.轉(zhuǎn)發(fā)(DispachMessage):線程浸入內(nèi)核,利用窗口句柄將不同的消息分發(fā)給各個(gè)窗口

---4.窗口調(diào)用窗口函數(shù),執(zhí)行特定的代碼

---相關(guān)的代碼

---窗口創(chuàng)建和消息傳遞處理的流程

---效果如下:可以放大、拖拽、關(guān)閉等

#VC6創(chuàng)建一個(gè)MFC窗口,命名HelloMFC

---采用基本對話框

---使用靜態(tài)鏈接庫,直接把庫編譯到exe文件

----可以自定義窗口

#總結(jié)(利用MFC寫一個(gè)窗口程序)

---優(yōu)點(diǎn):簡單、方便;缺點(diǎn):代碼冗余復(fù)雜

第二節(jié):第一個(gè)MFC程序

#本節(jié)需要掌握的知識點(diǎn):

---1.CWinApp可以覆蓋的虛函數(shù)InitInstance(在里面創(chuàng)建窗口)

---2.CWinApp成員變量:m_pMainWnd(相當(dāng)于WinMain函數(shù))

---3.CFramWnd的成員函數(shù):Create以及參數(shù)(相當(dāng)于窗口函數(shù))

#需要簡單了解的內(nèi)容

---1.通過MSDN去看MFC的層次結(jié)構(gòu)圖

---2.對CWinApp有初步的認(rèn)知

---3.對CFramWnd有初步的認(rèn)知

#MFC的層次結(jié)構(gòu)圖(Hierarchy Chart)

#CWinApp(應(yīng)用程序框架)

---提供了初始化應(yīng)用程序運(yùn)行應(yīng)用程序的成員函數(shù)

---使用MFC的每個(gè)應(yīng)用程序只能包含1個(gè)WinApp的派生對象,

---當(dāng)你從WinApp派生應(yīng)用程序,覆蓋InitInstance成員函數(shù)以及創(chuàng)建應(yīng)用程序的主窗口對象

---InitInstance成員函數(shù)的成員變量:m_pMainWnd用來記錄主窗口對象

---BOOL InitInstance()是MFC的CWinApp類的成員函數(shù),而WinMain才是真正的入口點(diǎn),但是MFC不允許程序中有WinMain這個(gè)函數(shù)

---因?yàn)镸FC自己編寫了WinMain函數(shù),如果程序中再定義就重復(fù)定義了,

---而MFC編寫的的WinMain函數(shù)則調(diào)用了CWinApp::InitInstance函數(shù),所以InitInstance看起來似乎就是MFC程序的入口點(diǎn)。

---除了CWinApp成員函數(shù)外,Microsoft基類庫提供了以下全局函數(shù)

---來訪問CWinApp對象和其它全局信息

---1.AfxGetApp:獲取一個(gè)指向CWinApp對象的指針

---2.AfxGetInstanceHandle獲取當(dāng)前應(yīng)用程序?qū)嵗?/strong>(exe)的句柄

---3.AfxGetResourceHandle獲取應(yīng)用程序資源(dll)的句柄

---4.AfxGetAppName獲取指向包含應(yīng)用程序名稱的字符串指針

#總結(jié)

---MFC的核心:基于CWinApp的應(yīng)用程序對象(只能1個(gè))

---CWinApp的派生對象:代表1個(gè)程序本體(和程序本身有關(guān),和窗口無關(guān)的數(shù)據(jù)和動(dòng)作)

#CFrameWnd類


---提供了Windows單文檔界面(SDI),重疊或者彈出框架窗口的功能,以及用于管理窗口的成員

---要為應(yīng)用程序創(chuàng)建窗口,從FrameWnd派生類向派生類添加成員變量,以存儲(chǔ)特定的應(yīng)用程序數(shù)據(jù)

---在派生類中實(shí)現(xiàn):消息處理程序成員和消息映射(窗口函數(shù)

#創(chuàng)建和初始化Windows框架窗口

----CFrameWnd::Create(相當(dāng)于CreateWindow)

---這里可以只填寫LPCTSTR lpszClassName、LPCTSTR lpszWindowName兩個(gè)參數(shù),其它參數(shù)都存在默認(rèn)值

---如果LPCTSTR lpszClassName=NULL,則以MFC內(nèi)建窗口類產(chǎn)生一個(gè)標(biāo)準(zhǔn)的外框窗口

#創(chuàng)建一個(gè)CFrameWnd

#總結(jié)

---1,基于MFC的窗口程序,必須也只有1個(gè)CWinApp對象

---2.必須覆蓋CWinApp的虛函數(shù)InitInstance,在里面創(chuàng)建窗口,并把窗口對象保存在InitInstance()函數(shù)的成員變量m_pMainWnd

---3.創(chuàng)建窗口是通過CFrameWnd對象,在它的構(gòu)造函數(shù)里面調(diào)用成員函數(shù)Create

#MFC程序的注意事項(xiàng)

---1.使用Win32Application創(chuàng)建工程(空項(xiàng)目)

---New一個(gè)Hello.cpp和Hello.h

---2.使用靜態(tài)鏈接庫

---3.在Hello.h中寫下防止頭文件被重復(fù)引用,防止被重復(fù)編譯的宏:

---ifndef 它是if not define的簡寫,是宏定義的一種:條件編譯
---#ifndef可以避免以下錯(cuò)誤:如果在.h文件中定義了全局變量,一個(gè)C文件包含了.h文件多次

---如果不加#ifndef宏定義,會(huì)出現(xiàn)變量重復(fù)定義的錯(cuò)誤;如果加了#ifndef則不會(huì)出現(xiàn)這種錯(cuò)誤.

---4.使用頭文件afxwin.h

#Hello.h的代碼

---Hello.cpp的代碼:

---m_pMainWnd相當(dāng)于窗口句柄,InitInstance相當(dāng)于WinMain函數(shù)

---效果如下

---在UpdateShow()下斷點(diǎn),F(xiàn)5調(diào)試,然后單步步入F11

---發(fā)現(xiàn)AfxWinMain就是以前的WinMain(),因此:InitInstance就是MFC對于WinMain()的封裝

---而且,在AfxWinMain內(nèi)部,調(diào)用了CWinApp的InitInstance()成員函數(shù)

#存在的問題

---1.WinMain在哪里? 2.消息循環(huán)在哪里? 3.窗口過程函數(shù)在哪里?

---關(guān)于作業(yè):創(chuàng)建窗口,右側(cè)帶滾動(dòng)條,大小300*300

---可以看到結(jié)構(gòu)體RECT是4個(gè)長整型的結(jié)構(gòu)體

第三:MFC的初始化過程1

#全局變量、全局對象總是在任何其它代碼之前執(zhí)行

---發(fā)現(xiàn)在main函數(shù)之前,a已經(jīng)被賦值

---全局對象也是一樣

---發(fā)現(xiàn)構(gòu)造函數(shù)早于main函數(shù)執(zhí)行

#總結(jié)

---1.全局對象的構(gòu)建,會(huì)早于程序的入口點(diǎn)

---2.而WinMain又廣泛使用了應(yīng)用程序?qū)ο螅–WinApp)的InitInstance()方法

---3.所以CWinApp被構(gòu)建成了全局對象

#模擬MFC的初始化

---CWinApp類的繼承關(guān)系:CObject > CCmdTarget > CWinThread > CWinApp

---CFrameWnd類的繼承關(guān)系: CObject > CCmdTarget > CWND > CFrameWnd

---編寫一個(gè)控制臺(tái)程序模擬MFC初始化

---注意:可以通過新建類來指定繼承關(guān)系

---先創(chuàng)建CObject.h

---再創(chuàng)建CObject.cpp

---考慮到要使用cout,創(chuàng)建一個(gè)public.h

---再創(chuàng)建CCmdTarget類,并且繼承CObject類

---聲明CCmdTarget的函數(shù)

---以此類推,分別創(chuàng)建CWinThread 和 CWinApp類

---在Mian.cpp中創(chuàng)建全局對象CWinApp

---發(fā)現(xiàn)逐級調(diào)用了父類的構(gòu)造函數(shù)和析構(gòu)函數(shù)

---CObject > CCmdTarget > CWND > CFrameWnd也是同理

第四:MFC的初始化過程2

#知識點(diǎn)

---MFC如何使用應(yīng)用程序?qū)ο?/p>

---CWinApp的2個(gè)可以覆蓋的虛函數(shù):

---從創(chuàng)建MFC窗口的頭文件可以看出

---CMyApp繼承CWinApp對象,而CMainWindow繼承CFrameWnd對象

---對象的繼承圖

---依次創(chuàng)建對象的構(gòu)造函數(shù)和析構(gòu)函數(shù)

---在mian()中創(chuàng)建全局對象

---注意:這里只是模擬,WinMain()是由系統(tǒng)調(diào)用,和平時(shí)程序調(diào)用存在本質(zhì)區(qū)別

---WinMain()沒有封裝在CWinApp類或者其它MFC的類中,因此WinMain()不是其它類的成員

---最后會(huì)調(diào)用AfxWinMain函數(shù)

---WinMain()的本質(zhì)是AfxWinMain函數(shù)

---執(zhí)行結(jié)果如下

--但是,相當(dāng)于MFC的程序,還缺少

---1.InitInstance()的虛函數(shù)

---2.m_pMainWnd的指針(指向CFrameWnd::CMainWindow對象),而m_pMainWnd指針是和InitInstance()同一級或者更上一級的類的成員變量

---查看InitInstance()的類:這里有3個(gè)類,但是最大的還是CWinThread類

---同樣的m_pMainWnd是CWinThread()的成員

---在CWinThread.h中定義純虛函數(shù)InitInstance()和m_pMainWnd指針

---注意包含WND.h

---在CMyApp.h中重定義虛函數(shù),

---在CMyApp.cpp中重寫虛函數(shù),并且new一個(gè)CMainWindow()對象(注意包含)

----在CMainWindow類里面重新定義一個(gè)方法

---然后在MainWindow.cpp中打印Create,并且在構(gòu)造函數(shù)時(shí)調(diào)用Create

---修改主函數(shù),在WinMain()里面調(diào)用

---1.WinMain()之前,全局對象的初始化會(huì)調(diào)用:

CObject > CCmdTarget > CWinThread > CWinApp > CMyApp

---2.進(jìn)入WinMain()之后,創(chuàng)建CMainWindow對象

CObject > CCmdTarget > CWnd > CFrameWnd > CMainWindow > Create

---3.最后調(diào)用的析構(gòu)函數(shù)(奇怪:CMainWindow系列的父類的析構(gòu)函數(shù)沒有調(diào)用)

第五:MFC運(yùn)行時(shí)類型識別:

#什么是RTTI(Runtime Type Information)

---運(yùn)行時(shí)類型信息程序,能夠使用父類的指針或者引用,來檢查這些指針或者引用所指向的對象的實(shí)際派生類

---幫助我們在實(shí)際程序運(yùn)行時(shí),判斷某個(gè)對象是否屬于某個(gè)類


---在項(xiàng)目設(shè)置里面選擇C++語言,勾選允許RTTI

---RTTI需要包含頭文件<typeinfo.h>

---typeid運(yùn)算符用來獲取一個(gè)表達(dá)式的類型信息,

---typeid 會(huì)把獲取到的類型信息保存到一個(gè) type_info 類型的對象里面,

---并返回該對象的常引用;當(dāng)需要具體的類型信息時(shí),可以通過成員函數(shù)來提取

#static關(guān)鍵字

---相當(dāng)于一個(gè)全局變量,獨(dú)立于該類的任何對象(和類關(guān)聯(lián),但是和類的任何對象不關(guān)聯(lián))

---不能在類的構(gòu)造函數(shù)中聲明(初始化),可以不需要?jiǎng)?chuàng)建對象,就使用類的static成員變量/方法

#const關(guān)鍵字

---定義一個(gè)只能初始化一次(不可以改變)的變量

---如果是類里面const,直接在構(gòu)造函數(shù)進(jìn)行聲明

---如果是static const,就在類外面進(jìn)行聲明

---在之前的HelloMFC項(xiàng)目中,在Hello.h中,加入宏:DECLARE_DYNAMIC,在Hello.cpp中加入宏:IMPLEMENT_DYNAMIC

---和typeid類似,MFC也存在IsKindOf()函數(shù)來檢測:

---(1)對象是否屬于指定的類,(2)對象是否屬于指定類派生的類

---在Hello.h中

---在Hello.cpp中:

---下斷點(diǎn)發(fā)現(xiàn)i=1,說明CWinApp是CMyApp的父類(父子類關(guān)系)

---查看DECLARE_DYNAMIC()的宏定義

---定義了一個(gè)靜態(tài)常量CRuntimeClass結(jié)構(gòu)體,名為class##class_name

---定義了一個(gè)返回CRuntimeClass指針的GetRuntimeClass()的虛函數(shù),并且該函數(shù)的成員方法/變量都是常量(無法更改)

---AFX_DATA 實(shí)際是定義為空的,也許在MFC內(nèi)部編譯里有用,可以別管它

---##表示連接符,可以進(jìn)行字符的拼接,如class##CMyApp就是classCMyApp

---#表示字符串化,如#CMyApp就是"CMyApp"

----CRuntimeClass:類型記錄鏈表結(jié)構(gòu):

---對于MFC中每個(gè)CObject派生類來說,都有一個(gè)相關(guān)的CRuntimeClass結(jié)構(gòu)體,在程序運(yùn)行時(shí)可以訪問該結(jié)構(gòu)體獲取對象及其基類的運(yùn)行時(shí)信息。

---在運(yùn)行時(shí)確定一個(gè)對象的類型是很重要的,尤其是在做類型檢查時(shí);而C++語言本身并不支持運(yùn)行時(shí)類信息

---每一個(gè)類擁有這樣一個(gè)CRuntimeClass成員變量,并且有一定的命名規(guī)則(在類名稱之前冠以“class”作為它的名稱)

---然后通過某種手段將整個(gè)類庫構(gòu)建好,“類別型錄網(wǎng)”能呈現(xiàn)類似的風(fēng)貌

---這里的class_name就是CMyApp

---1.定義一個(gè)classCMyApp的CRuntimeClass結(jié)構(gòu)體的靜態(tài)常量

---2.定義一個(gè)獲取當(dāng)前類的CRuntimeClass結(jié)構(gòu)體地址的指針

---在Hello.cpp中查看聲明classCMyApp和重寫虛函數(shù)的宏:

IMPLEMENT_DYNAMIC(CMyApp,CWinApp)

---這里是另外一個(gè)宏:

IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

---跟進(jìn)去查看這個(gè)宏

---AFX_COMDAT是一種描述,用來控制編譯用的,可以去掉

---將這個(gè)宏轉(zhuǎn)移到Hello.cpp中

---這里的RUNTIME_CLASS也是一個(gè)宏目的是獲取指定類的CRuntimeClass地址

---替換之后的Hello.cpp

#總結(jié)

---在頭文件中定義當(dāng)前類的CRuntimeClass靜態(tài)常量結(jié)構(gòu)體classCMyApp,并且定義獲取當(dāng)前類的CRuntimeClass指針的虛函數(shù)GetRuntimeClass()

---初始化classCMyApp的值(指明類名、父類CRuntimeClass指針等)

---重寫GetRuntimeClass()虛函數(shù), 返回當(dāng)前CRuntimeClass結(jié)構(gòu)體的指針

#在int i = IsKindOf(((CRuntimeClass*)(&CWinApp::classCWinApp)));下斷點(diǎn)單步調(diào)試

---這里會(huì)刪除以下為了防止報(bào)錯(cuò)的代碼

---注意:這里pClass是父類的CRuntimeClass指針

---pClassThis是自己當(dāng)前類的CRuntimeClass指針

---this是當(dāng)前類CMyApp的指針

---進(jìn)入IsDerivedFrom函數(shù),這里的pBaseClass就是父類CWinApp的CRuntimeClass結(jié)構(gòu)體地址

---這里的pClassThis就是當(dāng)前類結(jié)構(gòu)體的CRuntimeClass地址

---進(jìn)入while循環(huán):如果當(dāng)前類的this(當(dāng)前類的CRuntimeClass地址)地址,不等于指定對象的CRuntimeClass地址

---就在當(dāng)前類的CRuntimeClass基礎(chǔ)上,向上遍歷父類的CRuntimeClass地址,直到父類遍歷完,m_pBaseClass指向NULL時(shí)退出循環(huán)(成功返回TRUE)

#作業(yè):讓CMianWindow支持RTTI,自己寫函數(shù)打印父類的CRuntimeClass

---頭文件

---遇到幾個(gè)問題:1.MFC里面不能使用printf函數(shù)

---2.想用m_pMainWnd->GetBaseRuntimeClass()調(diào)用,發(fā)現(xiàn)失?。ú恢朗莄onst限制還是我不能使用virtual,沒有辦法只能在構(gòu)造函數(shù)里面調(diào)用)

---3.這里調(diào)用CRuntimeClass指針的時(shí)候,直接pClassThis->m_pBaseClass,VC提示的成員變量是基于動(dòng)態(tài)鏈接庫的,我們這里是靜態(tài)鏈接庫

---4.如果要輸出LPCSTR,需要使用cout和for循環(huán),或者printf("%s")

第六:MFC六大核心機(jī)制:動(dòng)態(tài)創(chuàng)建

#什么是動(dòng)態(tài)創(chuàng)建

---MFC的動(dòng)態(tài)創(chuàng)建和C++的new幾乎沒有區(qū)別,但是回避了C++不讓如下語句的缺點(diǎn)

---編譯器不知道className是一個(gè)變量名,而不是類名,從className里面構(gòu)造的對象可能是錯(cuò)誤的

#面對對象之永久保存

---把內(nèi)存里面的東西,寫入到文件里面

---MFC永久保存:數(shù)據(jù)存儲(chǔ)入文件,讀出之后,根據(jù)文件的記錄,new一個(gè)對象

#類型記錄鏈表結(jié)構(gòu)(CRuntimeClass)

---在CFrameWnd中,存在宏:DECLARE_DYNCREATE

---在Hello.h中

---在Hello.cpp中:這里的邏輯是:變量class_name,根據(jù)class_name獲取到該類的結(jié)構(gòu)體CRuntimeclass,然后根據(jù)CRuntimeClass里面的CreateObject()創(chuàng)建該類的對象

---在MFC里面,根據(jù)宏,來創(chuàng)建當(dāng)前類或者父類的對象(前提是該類存在CRuntimeclass結(jié)構(gòu)體)

---查看DECLARE_DYNCREATE(CMainWindow)

---本質(zhì)上是上一節(jié)的DECLARE_DYNAMIC

---PASCAL 就是_stdcall調(diào)用約定,在DECLARE_DYNAMIC的 基礎(chǔ)上,創(chuàng)建了一個(gè)靜態(tài)函數(shù),并且返回CObject*

---查看IMPLEMENT_DYNCREATE

---查看IMPLEMENT_RUNTIMECLASS宏(這個(gè)就是IMPLEMENT_DYNMIC)

---因此,在Hello.h中

---在Hello,cpp中

#總結(jié)

第七:MFC的六大核心機(jī)制:消息映射

#MFC的消息映射

---消息映射是MFC的內(nèi)建的一個(gè)消息分配機(jī)制,利用數(shù)個(gè)宏固定形式的寫法

---類似于填表格,就可以讓框架知道,一旦消息產(chǎn)生

---該往哪一個(gè)類進(jìn)行傳遞,每一個(gè)類只能擁有一個(gè)消息映射表(也可以沒有)

#Win32的消息機(jī)制

---1.創(chuàng)建窗口對象,然后初始化窗口對象的背景、類名、句柄、窗口程序(結(jié)合WinMain)

---2.將窗口類和OS關(guān)聯(lián)(鼠標(biāo)操作,OS傳遞消息給線程)

---3.線程(WinMain)獲取消息(GetMessage),然后翻譯(TranslateMessage)消息為虛擬碼(類似ASCII)才能被識別

---4.分發(fā)(DispachMessage)消息給OS,OS根據(jù)msg結(jié)構(gòu)中的hWnd窗口句柄,找到相應(yīng)的窗口類,然后根據(jù)注冊窗口時(shí)wndclass類結(jié)構(gòu)找到相應(yīng)的窗口函數(shù)WndPorc()

---相關(guān)的Win32代碼

#MFC的消息處理

---在Hello.h定義消息的處理函數(shù)

---在Win32里面是每個(gè)窗口設(shè)置消息處理函數(shù),而在MFC中,在類中定義的消息和對應(yīng)的消息處理函數(shù)

---在Hello,cpp中,在固定的宏里面,實(shí)現(xiàn)消息類型,然后根據(jù)消息類型設(shè)定消息處理函數(shù)

---發(fā)現(xiàn)打印了內(nèi)容,并且彈出了消息盒子


---在CMainWindow::OnPaint()中,需要明確設(shè)備對象、設(shè)備上下文、圖形對象

---畫圖的代碼如下:設(shè)備對象就是窗口(窗口句柄為空就是桌面),根據(jù)窗口句柄獲取設(shè)備上下文

---自定義圖形對象,然后和設(shè)備上下文關(guān)聯(lián),然后通過設(shè)備上下文進(jìn)行畫圖

---繪制圖形如下(這個(gè)只能顯示一次,而窗口是不停的繪制、渲染)

---這也是為什么上面MFC要利用dc對象來進(jìn)行畫圖

---查看聲明DeCLARE_MESSAGE_MAP()

---定義了2個(gè)靜態(tài)常量,聲明2個(gè)結(jié)構(gòu)體AFX_MSGMAP_ENTRY和AFX_MSGMAP

---虛函數(shù):GetMessageMap(),獲取messageMap的地址

---AFX_MSGMAP_ENTRY

----AFX_MSGMAP(查看靜態(tài)鏈接庫)

---查看BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()

---查看ON_WM_LBUTTONDOWN():根據(jù)消息類型,指定消息響應(yīng)函數(shù)

---查看AfxSig_vwp(指明了消息響應(yīng)函數(shù)的:返回類型、參數(shù)列表)

---查看ON_WM_PAINT()

---匯總起來,在Hello.h中

---private是完全私有的,只有當(dāng)前類中的成員能訪問到;protected是受保護(hù)的,只有當(dāng)前類的成員與繼承該類的類才能訪問

---聲明了2個(gè)結(jié)構(gòu)體AFX_MSGMAP_ENTRY和AFX_MSGMAP,以及獲取AFX_MSGMAP結(jié)構(gòu)體地址的虛函數(shù)

---注意:afx_msg就是消息響應(yīng)函數(shù)的返回類型

---Hello.cpp

---每一個(gè)類都有一個(gè)私有的AFX_MSGMAP_ENTRY結(jié)構(gòu)體,里面存儲(chǔ)著:不同類型的消息所對應(yīng)的消息處理函數(shù)、消息ID等

---然后每一個(gè)類存在一個(gè)保護(hù)的類型的結(jié)構(gòu)體AFX_MSGMAP,這個(gè)結(jié)構(gòu)體2個(gè)指針分別指向父類的AFX_MSGMAP,和自己的AFX_MSGMAP_ENTRY

---因此,我們可以通過AFX_MSGMAP獲取自己和父類的AFX_MSGMAP_ENTRY

---AFX_MSGMAP_ENTRY結(jié)構(gòu)體的類型是{{消息結(jié)構(gòu)體1},{消息結(jié)構(gòu)體2},{空消息結(jié)構(gòu)體}}

---注意:消息結(jié)構(gòu)體里面的消息響應(yīng)函數(shù)的參數(shù)、返回類型和命名是固定的

#MFC的三大類消息

#MFC處理消息的原理

---MFC內(nèi)部存在一個(gè)窗口過程處理函數(shù)

---根據(jù)MessageMap鏈表找到對應(yīng)的消息函數(shù)AFX_MSGMAP_ENTRY

---MessageMap存在2個(gè)指針,pBaseMap指向父類的AFX_MSGMAP結(jié)構(gòu)體,最終指向CCmdTarget::messageMap

---lpEntries指向自己的AFX_MSGMAP_ENTRY結(jié)構(gòu)體,在結(jié)構(gòu)體內(nèi)存在不同消息的:消息ID、消息響應(yīng)函數(shù)等

---因此:一個(gè)支持消息映射的類(標(biāo)準(zhǔn)消息),必須繼承CCmdTarget

#作業(yè)

---新建一個(gè)類,繼承于CMainWind(CNewWnd),給CMainWind添加鼠標(biāo)左鍵點(diǎn)擊事件,創(chuàng)建新的CNewWnd窗口,新窗口添加鼠標(biāo)左鍵點(diǎn)擊事件,彈出MessageBox

---在Hello.h中,聲明新建的類CNewWnd,并且聲明消息映射和消息響應(yīng)函數(shù)

---在hello.cpp中定義CNewWnd的指針,來進(jìn)行新窗口的創(chuàng)建

---創(chuàng)建效果如下

第八:MFC六大核心機(jī)制:命令的傳遞

#MFC命令傳遞

---消息會(huì)按照規(guī)定的路線,游走于各個(gè)對象之間,直到找到它的消息處理函數(shù)

---如果找不到,就交給DefWindowPro函數(shù)處理


---在Create(NULL,"主窗口")下斷點(diǎn)

---單步進(jìn)入CreateEx

---CREATESTRUCT結(jié)構(gòu)體用來存儲(chǔ)創(chuàng)建窗口的參數(shù)

---單步步入預(yù)窗口創(chuàng)建:PreCreateWindow(cs),設(shè)置窗口的風(fēng)格,并且注冊(根據(jù)所屬的類來進(jìn)行定義窗口的風(fēng)格)

---單步步入AfxDeferRegisterClass

---AfxHookWindowCreate(this)函數(shù)分析(this是CWnd類地址)

---_AfxCbtFilterHook函數(shù)分析

---在D:\VC6.0\VC98\MFC\SRC路徑下WINCORE.CPP文件

---在里面將Win32里面的窗口過程處理函數(shù)替換成afxWndProc

#總結(jié)MFC創(chuàng)建窗口流程

---1.判斷創(chuàng)建的窗口是否存在菜單,如果存在則加載菜單

---2.獲取窗口類的類名,根據(jù)類名調(diào)用CreateEx()函數(shù)

---3.聲明CREATESTRUCT結(jié)構(gòu)體cs,用來存儲(chǔ)Win32中CreateWindow()的參數(shù)

---4.調(diào)用PreCreateWindow(cs)函數(shù),判斷窗口類名是否為空(是否默認(rèn)的窗口對象)

---5.如果是默認(rèn)的窗口類,就調(diào)用AfxDeferRegisterClass函數(shù),初始化窗口類,根據(jù)不同的類來設(shè)置窗口的風(fēng)格、背景和如果沒有消息響應(yīng)的默認(rèn)窗口過程函數(shù),最后調(diào)用AfxRegisterClass()注冊窗口類

---6.在調(diào)用CreateWindowEx創(chuàng)建窗口之前,先調(diào)用AfxHookWindowCreate(this)下鉤子,也就是說,在DispatchMessage之后,AfxHookWindowCreate(this)最先受到消息

---7.通過SetWindowsHookEx安裝WH_CBT的過濾函數(shù),Windows系統(tǒng)在進(jìn)行窗口操作(最大化、最小化窗口)執(zhí)行之前,調(diào)用這個(gè)_AfxCbtFilterHook過濾函數(shù)

---8._AfxCbtFilterHook將Win32里面的窗口過程處理函數(shù)替換成afxWndProc

---在上一節(jié)的作業(yè)的消息響應(yīng)函數(shù)這里下一個(gè)斷點(diǎn)

---首先進(jìn)入的是消息響應(yīng)函數(shù)的調(diào)用格式

---WindowProc中,調(diào)用OnWndMsg()對消息進(jìn)行處理

---如果處理失敗,調(diào)用DefWindowProc()對消息進(jìn)行默認(rèn)處理

---執(zhí)行完WindowProc之后,進(jìn)入AfxCallWndProc()的

---執(zhí)行完AfxCallWndProc()之后,進(jìn)入AfxWndProc(真正的窗口過程處理函數(shù))

---DispatchMessage之后,AfxWndProc最先接受到消息

---本質(zhì)是調(diào)用AfxCallWndProc函數(shù),把消息送給CWnd類或其派生類的對象。

---該函數(shù)主要是把消息和消息參數(shù)(nMsg、wParam、lParam)傳遞給MFC窗口對象的成員函數(shù)WindowProc(pWnd->WindowProc)作進(jìn)一步處理。

---如果是WM_INITDIALOG消息,則在調(diào)用WindowProc前后要作一些處理。

#總結(jié)MFC的窗口過程(消息響應(yīng)函數(shù))

---每一個(gè)“窗口類”都有自己的窗口過程,使用該“窗口類”創(chuàng)建的窗口都使用它的窗口過程

---MFC的窗口對象在創(chuàng)建窗口時(shí),也使用已經(jīng)注冊的“窗口類”(使用應(yīng)用程序提供的窗口過程),AfxWndProc或AfxWndProcBase(動(dòng)態(tài)鏈接庫)(本質(zhì)是AfxCallWndProc)

---窗口創(chuàng)建最終是通過調(diào)用CWnd::CreateEx函數(shù)完成的(根據(jù)窗口類名調(diào)用),CreateEx函數(shù)流程如下

---在創(chuàng)建窗口之前,創(chuàng)建了一個(gè)WH_CBT類型的鉤子(Hook)。這樣,創(chuàng)建窗口時(shí)所有的消息都會(huì)被鉤子過程函數(shù)_AfxCbtFilterHook截獲。

---AfxCbtFilterHook函數(shù)首先檢查是不是希望處理的 Hook──HCBT_CREATEWND。如果是,則先把MFC窗口對象和剛剛創(chuàng)建的Windows窗口對象捆綁在一起,建立它們之間的映射(見后面模塊-線程狀態(tài));

---然后,調(diào)用::SetWindowLong設(shè)置窗口過程為AfxWndProc,并保存原窗口過程在窗口類成員變量m_pfnSuper中,這樣形成一個(gè)窗口過程鏈。需要的時(shí)候,原窗口過程地址可以通過窗口類成員函數(shù)GetSuperWndProcAddr得到。

---AfxWndProc就成為CWnd或其派生類的窗口過程。不論隊(duì)列消息,還是非隊(duì)列消息,都送到AfxWndProc窗口過程來處理

---Windows消息送給AfxWndProc窗口過程之后,AfxWndProc得到HWND窗口對應(yīng)的MFC窗口對象

---然后,搜索該MFC窗口對象和其基類的消息映射數(shù)組,判定它們是否處理當(dāng)前消息,如果是則調(diào)用對應(yīng)的消息處理函數(shù),否則,進(jìn)行缺省處理

#MFC中每一個(gè)窗口,都對應(yīng)了一個(gè)窗口類

---在這個(gè)窗口產(chǎn)生的消息,CWnd或者派生類的對象調(diào)用OnWndMsg搜索本對象或者基類的消息映射數(shù)組messageMap,尋找當(dāng)前消息的消息處理函數(shù)(在_messageEntries數(shù)組里面)

---在OnWndMsg搜索本對象對應(yīng)的消息映射數(shù)組,找到對應(yīng)的消息響應(yīng)函數(shù)

#總結(jié)

---在MFC中,每一個(gè)窗口都對應(yīng)一個(gè)MFC類(繼承于CCmdTarget)

---通過CWinApp的派生類,重寫InitInstance方法(相當(dāng)于WinMain入口)

---在InitInstance中,創(chuàng)建CFrameWnd對象(子類也可以),進(jìn)而調(diào)用CFrameWnd的構(gòu)造函數(shù)

---在構(gòu)造函數(shù)中,調(diào)用Create()創(chuàng)建MFC窗口(區(qū)別于CreateWindow),本質(zhì)是調(diào)用CreateEx

---CreateEx通過結(jié)構(gòu)體CREATESTRUCT傳遞定義窗口類的參數(shù),然后調(diào)用PreCreateWindow(cs)進(jìn)行窗口對象的自定義,以及窗口類的注冊

---調(diào)用AfxHookWindowCreate(this)在窗口創(chuàng)建前,創(chuàng)建了一個(gè)WH_CBT類型的鉤子(Hook),所有的消息都會(huì)被鉤子過程函數(shù)_AfxCbtFilterHook截獲

---_AfxCbtFilterHook,則先把MFC窗口對象(該對象必須已經(jīng)創(chuàng)建了)和剛剛創(chuàng)建的Windows窗口對象捆綁在一起建立它們之間的映射(將窗口類::WindowProc的消息處理過程和MFC窗口進(jìn)行關(guān)聯(lián))

---然后調(diào)用::SetWindowLong設(shè)置將Win32里面的窗口過程為AfxWndProc(本質(zhì)是AfxCallWndProc

---AfxWndProc就成為CWnd或其派生類的窗口過程。而經(jīng)過消息分發(fā)之后沒有被處理的消息,將送給原窗口過程處理。

---Windows消息送給AfxWndProc窗口過程之后(Win32是OS直接DispatchMessage給窗口句柄),AfxWndProc得到HWND窗口對應(yīng)的MFC窗口對象

---在MFC類的窗口過程函數(shù)中AfxWndProc,調(diào)用OnWndMsg()對消息進(jìn)行過濾識別,如果是標(biāo)準(zhǔn)消息,就搜索該MFC窗口對象和其基類的消息映射數(shù)組,判定它們是否處理當(dāng)前消息,如果是則調(diào)用對應(yīng)的消息處理函數(shù),否則,進(jìn)行缺省處理

#再次分析窗口過程處理函數(shù)AfxWndProc的本質(zhì)AfxCallWndProc(注意:這個(gè)順序應(yīng)該是反著來)

---步驟3:注意每一個(gè)CWnd對象的派生類(MFC窗口對象)都存在函數(shù)

---序員可以在CWnd的派生類中覆蓋它,改變MFC分發(fā)消息的方式。例如,MFC的CControlBar就覆蓋了WindowProc,對某些消息作了自己的特別處理,其他消息處理由基類的WindowProc函數(shù)完成

---在當(dāng)前例子中,當(dāng)前對象的類CTview沒有覆蓋該函數(shù),所以CWnd的WindowProc被調(diào)用。---這個(gè)函數(shù)把下一步的工作交給OnWndMsg函數(shù)來處理。如果OnWndMsg沒有處理,則交給DefWindowProc來處理

---OnWndMsg和DefWindowProc都是CWnd類的虛擬函數(shù)。

---步驟2

---步驟1:

#總結(jié)

---DispatchMessage之后,MFC窗口對象::AfxWndProc接受到消息,調(diào)用?AfxCallWndProc

---AfxCallWndProc根據(jù)接到的消息,調(diào)用消息處理函數(shù)CWnd::WindowProc

---WindowProc函數(shù)調(diào)用OnWndMsg遍歷父子類的messageMap結(jié)構(gòu)體,找到對應(yīng)消息的響應(yīng)過程函數(shù)

#為什么要使用消息映射

#MFC消息傳遞總結(jié)


【滴水基礎(chǔ)】5.MFC(1)的評論 (共 條)

分享到微博請遵守國家法律
洞头县| 新丰县| 五常市| 嫩江县| 民勤县| 蚌埠市| 泰兴市| 新泰市| 合水县| 桑日县| 铜陵市| 芦山县| 镇江市| 江西省| 九龙坡区| 麻江县| 彝良县| 二连浩特市| 乡城县| 淮南市| 桐庐县| 佛教| 静乐县| 逊克县| 南投县| 鸡西市| 墨竹工卡县| 响水县| 峨山| 宁南县| 永仁县| 长岭县| 贺兰县| 马边| 额尔古纳市| 遵化市| 昆山市| 新龙县| 宜兰县| 天等县| 即墨市|