MFC(微軟)
微軟基礎類別館(英語:MicrosoftFoundationClasses,簡稱MFC)是一个微軟公司提供的類別館(class libraries), 以 C + + 類的形式封裝矣 Windows API,並且包含一个(嘛是微軟產品的唯一一个)應用程式框殼,以減少應用程式開發人員的工作量。其中包括的類包含大量 Windows 控制代碼封裝類佮真濟 Windows 內建控制項佮組件的封裝類。
特性
Visual C + + 包含 MFC 應用程式精靈,會當用相容 MFC 的應用程式。佇咧 ATL 程式內底嘛會當手動添加 MFC 支援。佇精靈中有各種選項以客製化生成的程式的功能,譬如講介面風格、語種、資料庫開發支援、列印支援、自動化支援、ActiveX 支援、網路支援、是因為 HTML 來說明文件支援等等。
佇咧 COM 開發方面,相對的是 ATL 來講,MFC 的組件較大,代碼無夠短小精刺,但是支援的功能嘛較濟,譬如講有對 ActiveX Document 的封裝類。
佇介面開發方面,MFC 提供對訊息迴圈的封裝,使用訊息對映來避免虛擬函式的開銷。MFC 嘛提供常用 Windows 通用控制項的封裝類。
MFC 擴充 DLL 的介面予 MFC 程式會當直接呼叫 MFC 擴充 DLL 中的 MFC 類。MFC 嘛支援咧標準 DLL 中予人使用。
發展
MFC 是佇一九九二年凊彩軟 Microsoft C / C + + 七鼗空編譯器發布的,用佇咧面向十六位元 Windows 的軟體開發。起初,MFC 是做為一个應用程式框架開發的,所以定名為 Application Framework eXtensions(AFX)。
隨著 . NET 框架的發布,捌一度予微軟重點推薦的 MFC 予被 Visual Basic . NET、C #、Windows Forms 搶去袂少市場分額,猶毋過 MFC 繼續佇非代管軟體開發中占據重要地位。佇代管開發方面,MFC 中嘛包括著 Windows Forms 佮代管/非代管互操作的封裝。軟軟仔佇咧 Windows Vista 和 Windows 七發布了後佇 MFC 加中增加了對新的 Windows API 支援。
MFC 的優點
MFC 的主要優點是會當用物件導向的方法來呼叫 Windows API,閣有會當更加方便捷地開發應用程式。MFC 將真濟應用程式開發閣常用的功能自動化,並且提供文件框殼視圖結構佮活動文件這款的便於自訂的應用程式框架。同時,佇咧 Visual C + + 內部原仔內底起足濟嘿 MFC 的比如講類精靈這款的支援以減少軟體開發的時間,使用類精靈會當快速生成 Hello World 程式。
MFC 的缺點
雖然 MFC 的原始碼著使用者是完全開放的,猶毋過 MFC 的一寡封裝過程傷過複雜,較致使新使用者真歹扭掠掌握 MFC 的應用程式框殼,猶閣有除錯中定位問題的位置。同時,足濟的 MFC 物件毋是執行緒安全的,致使佇跨執行緒存取 MFC 物件的時陣需要編寫額外的代碼。另外咧,MFC 的足濟類依賴佇應用程式精靈生成的代碼,予得咧使用 Visual C + + 著其他類型的應用程式精靈生成的工程中添加 MFC 支援的難度大大增加。
第三方支援
足濟商用類別館佇 MFC 的基礎頂懸進一步實現外觀、漸漸變風格、加頂層窗仔口程式、屬性列表等較受歡迎的功能;同時,佇咧 C + + 線頂社群內底,足大一部份開放的原始碼嘛是基於 MFC 的。
版本
- 一 Visual Studio 速成版(Express)無包括 MFC 程式庫。
- 二 Feature Pack 干焦用佇咧英文版本的 Visual Studio 兩千空八。非英文版本的支援於欲包括 Visual Studio 兩千空八 Service Pack 一。
MFC 的結構
做為一个應用程式的開發框架,著愛滿足各方面的功能需求。
應用程式啟動
是因為 MFC 開發的應用程式佇咧起動的時陣,Windows 作業系統:
一 . 代先先呼叫 WinMain 函式(佇佗位咧 appmodul . cpp 中,封裝甲 mfc 八十 . dll(VS 二千空五版)),WinMain 函式內呼呼了 AfxWinMain 函式。 二 . AfxWinMain 函式(佇佗位咧 WinMain . cpp 中)搧搧叫一 . 該該用程式自訂的 App 類(這个類衍生 CWinApp 的,CWinApp 閣是衍生 CWinThread,就按呢代表應用程式的主執行緒)的 InitInstance 函式,該函式註冊並且建立窗口(通過 AppUI 二 . cpp 中的 ProcessShellCommmand 函式 ),然後 ShowWindow、UpdateWindow ; 二 . CWinThread 的 InitInstance 函式; 三 . CWinThread 的 Run 函式(佇佗位咧 thrdcore . cpp 中)。 該函式內底是 Windows 的訊息迴圈。做應用程式收著 WM \ _ QUIT 訊息了後,CWinThread : : Run 函式倒轉來,咱趕緊 CWinThread : : ExitInstance 被呼叫,該函式會當予人崁。程式登出執行。訊息迴圈是一个 for ( ; ; ) 的無窮甲輪,該當無窮圓箍仔內部包含一个 do . . . while 的迴箍結構。while 迴箍仔的條件是呼叫 PeekMessage 函式的回值,若講當前 UI 執行緒訊息佇咧列為空就倒轉去外口的無窮迴圈;while 迴圈體內做兩件代誌: 一 . PumpMessage ( )。事實上呼叫 AfxInternalPumpMessage 函式實現伊的功能:GetMessage ( )、AfxPreTranslateMessage ( )、TranslateMessage ( )、DispatchMessage ( ) . 即:對 UI 執行緒訊息佇咧列移除一條訊息、遍歷該訊息的 CWnd 類直到該窗口的各級別爸窗口的 CWnd 類以提供預處理該訊息的機會、若該訊息是照鍵訊息則翻譯做 WM \ _ CHAR 訊息、共該訊息予相應的窗口函式。 二 . IsIdleMessage ( ):事實上歡喜矣 AfxInternalIsIdleMessage 函式,對於 WM \ _ PAINT、WM \ _ SYSTIMER、猶閣有游標位置無變化的喔 WM \ _ MOUSEMOVE 抑是 WM \ _ NCMOUSEMOVE,為 Idle Message。 四 . 逐个窗口函式(WndProc)內部代先取得對應當前窗口控制代碼的 CWnd 類似的指標,然後咻叫 AfxCallWndProc 函式。
應用程式結束
- 若是點擊的乎 IDOK 揤鈕,預設是呼叫 OnOK ( ),然後是 OnDestory ( ),最後是 PostNcDestroy ( )
- 若點擊 IDCANCEL 揤鈕,預設呼叫 OnCancel ( ),然後是 OnDestory ( ),最後是 PostNcDestroy ( )
- 若點擊正手角的關係揤鈕:先 OnClose ( ),然後是 OnCancel ( ),閣來咧是 OnDestory ( ),最後是 PostNcDestroy ( )
訊息迴圈佮訊息對映
訊息分類
控制項的通知訊息佮反射訊息
表單頂懸的控制項,應當向父表單通報控制項發生的各種事件,若予人點擊、畫製、內容改變等等,這號做通知訊息(notification message)。 佇咧 Windows 三 . x 的十六位元程式設計時代,控制項向父表單傳送 WM \ _ COMMAND 訊息,由父表單的代碼負責實現遮的事件。其中 wParam 的低十六位元是 control ID,高十六位元是 notification code ( 比如講 BN \ _ CLICKED );lParam 是控制項控制代碼。所以,閣無可能傳遞其他的資訊予父表單。為此,為傳遞具有特別內容的控制項事件,Windows 三 . x 定義一批特殊的通知訊息 ( notification messages ):
- WM \ _ PARENTNOTIFY : 窗仔口的某一寡重大事件發生的時通知爸仔門,包括建立、銷毀、滑鼠各鍵揤落等事件
- 子窗口的捲振動情況的通知訊息
- WM \ _ VSCROLL
- WM \ _ HSCROLL
- 子窗口的畫製通知訊息
- WM \ _ DRAWITEM ,
- WM \ _ MEASUREITEM ,
- WM \ _ COMPAREITEM ,
- WM \ _ DELETEITEM ,
- WM \ _ CHARTOITEM ,
- WM \ _ VKEYTOITEM
- WM \ _ CTLCOLOR:設定揤鈕、編輯框、ListBox、Static、捲軸控制項佮 MessageBox、DialogBox 的前景色、背景色、背景模式、字型,閣回倒轉來一把 Brush,用佇咧控制項背景繪。
較早四配零版本的 MFC,佇咧控制項類提供虛擬函式來處理遮的通知訊息,這步已經予人喝出來矣「訊息反射」取代(但是猶原向下跤相容繼續支援)。
隨著 Windows 九十五開始矣三十二位元程式時代,伴來的是 Win 三十二 API 佮 MFC 四配零。Win 三十二增加足濟複雜的控制項,需要使用閣較濟通知訊息傳達足濟複雜的資料予爸表單。Win 三十二 API 干焦增加一个訊息 WM \ _ NOTIFY,就實現矣遮的功能。lParam 參數開頭是 NMHDR 資料結構,其後是佮這个通知類型相關的特定資料結構。
CWnd : : OnNotify 函式處理通知訊息。伊的預設實現是檢查訊息對映表(message map)來揣通知的處理器函式並呼叫。一般來講,毋免崁 OnNotify;啊若應該愛寫一个處理器函式加增加替這个窗口類的訊息來對映表條目。
` ` ` ON _ NOTIFY ( wNotifyCode , id , memberFxn ) ` ` `
成員函式應該寫為:
` ` ` afx _ msg void memberFxn ( NMHDR * pNotifyStruct , LRESULT * result ) ; ` ` `
MFC 四配零提供了一種特性「訊息反射」(message reflection), 允准控制項通知訊息既然會當佇爸窗口內底,閣會當佇咧控制項內底去予人處理。會當對控制項建立一个衍生的控制項類,實現對爸窗口反射轉來的指定類型訊息的處理。訊息反射是 MFC 毋是 Win 三十二的特性,因為按呢窗仔口的類著愛對 CWnd 衍生,對彼个爸爸口佇咧 CWnd : : OnNotify 函式內底處理控制項的 WM \ _ NOTIFY 時,代先先呼叫 CWnd : : ReflectLastMsg 共訊息反射回控制項的 CWnd : : SendChildNotifyLastMsg 函式去處理;ReflectLastMsg 倒回值就是佇咧控制項的訊息對映中使用 ON \ _ NOTIFY \ _ REFLECT \ _ EX ( ) 聲明的反射訊息處理捷式的返回值,會當通知爸爸口該訊息敢是已經予人控制項處理。控制項的 CWnd : : SendChildNotifyLastMsg 函式,頭先得著執行緒的最後一條 message,然後呼叫傳送窗仔口的虛擬函式 OnChildNotify 函式。佇咧子窗口處理反射轉來的控制項訊息,頭一款方法是加載控制項窗仔口的 OnChildNotify 虛擬函式;第二項辦法是由 CWnd : : OnChildNotify 預設處理去呼叫 CWnd : : ReflectChildNotify 函式,進入控制項子窗口的 MFC 訊息對映的標準處理(子窗口處理的訊息被譯做 WM \ _ REFLECT \ _ BASE + WM \ _ NOTIFY 訊息)。 對於 WM \ _ NOTIFY,干焦做佇咧控制項的訊息(message map)中,控制項無通過 ON \ _ NOTIFY \ _ REFLECT ( ) 聲明的反射訊息處理常式,爸爸口的相應的通知訊息處理常式才會呼叫(佇爸窗口訊息對映中使用宏 ON \ _ NOTIFY 聲明)。 控制項內底通過 ON \ _ NOTIFY \ _ REFLECT \ _ EX ( ) 聲明的反射訊息處理常式會當倒轉去真的抑假的,決定講爸爸喙敢是繼續處理這个通知訊息。WM \ _ NOTIFY 以外的其他通知訊息,爸窗口佇第一時間有機會處理伊,控制項對伊的處理排佇第二位。反射訊息處理常式通常使用特定的名,對應的訊息反射宏的名是佇咧訊息名加上字條 ON \ _,字尾 \ _ REFLECT。如 WM \ _ CTLCOLOR 對應 ON \ _ WM \ _ CTLCOLOR \ _ REFLECT。但是以下三款的情形,反射訊息處理常式會使隨意家己起名,對應的訊息反射宏的名分別為:
- WM \ _ COMMAND 使用 ON \ _ CONTROL \ _ REFLECT
- WM \ _ NOTIFY 使用 ON \ _ NOTIFY \ _ REFLECT
- ON \ _ UPDATE \ _ COMMAND \ _ UI 使用 ON \ _ UPDATE \ _ COMMAND \ _ UI \ _ REFLECT
訊息傳遞處理機制
MFC 類體系內底,Windows 訊息傳遞處理機制是對 CCmdTarget 類和其衍生類別的靜態成員函式 GetThisMessageMap ( ) 內部定義的靜態資料成員:
- 成員類型的 AFX \ _ MSGMAP \ _ ENTRY 的陣列 \ _ messageEntries。佇類的實現檔案中,佇咧 BEGIN \ _ MESSAGE \ _ MAP 佮 END \ _ MESSAGE \ _ MAP 中間的內容來初始化訊息對映入口項陣列。
- 資料類型做 AFX \ _ MSGMAP 的變數 messageMap。結構包括兩項,分別是直接基礎類別 GetThisMessageMap 函式的指標佮本類的 \ _ messageEntries 陣列首元素位址。
佇標頭檔的類別定義中使用宏 DECLARE \ _ MESSAGE \ _ MAP ( ) 來聲明靜態成員函式 GetThisMessageMap 佮虛擬函式 GetMessageMap
使用者所寫的類的 Windows 訊息處理常式(比如講 OnCommand)著愛轉換做 CCmdTarget : : \ * 的成員函式指標類型 AFX \ _ PMSG,儉佇咧該類的 \ _ messageEntries 陣列中。
呼叫使用者類中間訊息處理常式的時間,根據這个函式儲存 \ _ messageEntries 中的 signature(一个無符號規型表示的函式的形參類型列表佮返回值類型), 共類型做 void ( CCmdTarget : : \ * AFX \ _ PMSG ) ( void ) 的成員函式指標強制轉做其他類型的 CCmdTarget 成員函式的指標(比如講 void ( AFX \ _ MSG \ _ CALL CWnd : : \ * pfn \ _ v \ _ i \ _ i ) ( int , int ),目前佇這馬 union MessageMapFunctions 中列出欲百種 CCmdTarget 成員函式的指標), 然後呼叫轉換以後的成員函式指標。這是對 Visual C + + 編譯器共單繼承的成員函式的指標編譯為只儲存了函式的記憶提起始位址,所以會當佇仝一个單繼承類中共一種類型的成員函式指標強制轉換做另外一種成員函式的指標,或者是共單繼承衍生類別的成員函式指標強制轉換做基礎類別成員函式指標。這是拍破去 C + + 違例辦法。比如講,對於 CWnd : : OnCommand 函式,轉換過程是:
CString
CString 是 MFC 上捷看著的類之一,用佇封裝字串資料結構。伊干焦有一个資料成員 m \ _ pszData,其值為字串的首位址,其資料類型做 wchar \ _ t \ * 抑是 char \ *。佇咧 CString 的 m \ _ pszData 的頭前實際閣分配矣 CSringData 資料塊,包含著管理資料 :
由下而上,CAtlStringMgr 提供記憶體管理,CStringData 提供跟享管理,CString 提供字串操作。
CAtlStringMgr 的一个成員是 IAtlMemMgr 介面,這是策略模式,會當參照某一个記持體管理類。CAtlStringMgr 的另外一个成員是 CNilStringData。
所以,逐擺為 CString 動態分配位址空間,實際分配長度為 : ` ( nChars + 一 ) * nCharSize + sizeof ( CStringData ) `。通過 Attach 操作,將這个 CStringData \ * 佮 CSimpleStringT : : m \ _ pszData 執行關聯。做執行 CString 的預設建構函式生做一个空字串時,實際上攏是構造一个 CnilStringData 東西。CNilStringData 衍生自 CStringData,另外有一个 achNil 的陣列成員,這个陣列初初的時陣化為空字捾。通過這 achNil,保證了一个經過呼叫預設建構函式初初的 CString,其實講的真正的字串是一个空字串。
部份編譯器對 std : : string 放棄矣寫時複製(Copy On Write)機制。猶毋過,CString 一直採取這一的機制。CSimpleStringT : : Fork 函式就提供矣按呢一个操作,具體分做下跤幾步:
一 . 根據傳入的一个長度分配一段新的空間;——Allocate ( nLength , . . . ) 二 . 共舊的資料審查到新的空間內底;——CopyChars ( . . . ) 三 . 舊資料塊的參照技術減一;——pOldData-> Release ( ) 四 . 共 m \ _ pszData 佮新的資料塊關聯起來。—— Attach ( pNewData )
GetString 方法倒轉來是唯讀的字串位址;而且 GetBuffer 方法倒轉來的是可寫的字串位址(若是資料區是把享的,則寫時複製), 若修改字捾內容,這陣需要呼叫 ReleaseBuffer 方法共新的字串長度修改到元資料內底(並佇尾增加兩个零位元組)。
CString 物件用作會當變參數函式(如 printf)的實參時陣,因為無法度通過形參類型確定呼叫佗一个 CString 的類型轉換運算子函式,因為按呢有必要顯式指明欲轉換的類型。若需要咧函式的參數傳達 CString,因為 CString 使用參照計數,因此函式參數傳遞一个 CString 物件是會用得的;無需要修改其內容的時陣,推薦使用 const CString &。
支援 MFC 的 DLL 開發
使用 Visual C + + 會當開發三種 DLL :
- 無咧用 MFC 的 DLL;
- 使用 MFC 的規則的 DLL:輸出的函式無牽磕 MFC,按呢會當予人支援 / 無支援 MFC 的應用程式呼叫該 DLL
- 動態連結到 MFC(Regular DLLs dynamically linked to MFC)。
- 靜態連結到 MFC(Regular DLLs statically linked to MFC)
- 使用 MFC 的擴充 DLL(Extension DLLs), 干焦會當動態連結著 MFC:輸出的函式牽涉著 MFC,嘛會使輸出是無 MFC 的衍生類別。
因為 DLL 佮呼叫伊的應用程式攏會當有家己的 MFC 全域資料佮控制代碼的對映(handle mapping), 若控制代碼值仝款,則預設使用應用程式的對映到資源。為著無互相干擾,容允 DLL 內部使用家己的資源,著愛佇咧 DLL 函式的入口處共資源模組控制代碼對預設的應用程式切換做該 DLL。辦法是:
一 . 佇咧應該 DLL 逐个出的函式的見面呼 ` AFX _ MANAGE _ STATE ( AfxGetStaticModuleState ( ) ) `。函式 AfxGetStaticModuleState 的功能是咧執行棧頂懸建立一个 AFX \ _ MODULE \ _ STATE 類別的實例,嘿其進行設定,函式返回值為 AFX \ _ MODULE \ _ STATE 的指標。AFX \ _ MODULE \ _ STATE 類利用其建構函式和解構函式進行模組狀態現場儲存佮恢復。 二 . 使用 AfxGetResourceHandle ( ) ; 取得當前資源模組控制代碼。使用 AfxSetResourceHandle ( HINSTANCE xxx ) ; 設定程式欲用的資源模組控制代碼。
捷用標頭檔佮庫檔案
- STDAFX . H 載入其他 MFC 標頭檔。
- AFXWIN . H 伊和伊載入檔案聲明矣所有的 MFC 類。其內包括 AFX . H,後者包括了 AFXVER \ _ . H,後者閣載入去 AFXV \ _ W 三十二 . H,後者閣載入 WINDOWS . H。
- AFXEXT . H 使用工具列、狀態列的程式著愛載入這个檔案
- AFXDLGS . H 通用對話方塊(Common dialog)的 MFC 程式需要載入這个檔案。伊內底包括 COMMDLG . H
- FXCMN . H 通用控制項(common control)的 MFC 程式需要載入這个檔案。
- AFXCOLL . H 使用 MFC 提供的容器攏愛載入這个檔案。
- AFXDLLX . H 見若使用 MFC extension DLLs 需要載入這个檔案。
- AFXRES . H MFC 程式的 RC 檔案愛載這个檔案。這檔案當中對標準資源的 ID 攏有預設值。𪜶遮的定義佇這个檔案內底。
參考佮參照
- ATL
- Microsoft Visual Studio
- Visual Studio . NET
- Object Windows Library