MFC (微軟)

微軟基礎類庫應用程式框架，以減少應用程式開發人員的工作量。其中包含的類包含大量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是在1992年隨微軟的Microsoft C/C++ 7.0編譯器釋出的，用於面向16位元Windows的軟體開發。起初，MFC是作為一個應用程式框架開發的，所以定名為Application Framework eXtensions。隨著.NET框架的釋出，曾經一度被微軟重點推薦的MFC被Visual Basic .NET、C#、Windows Forms搶走了不少市場份額，但是MFC繼續在非託管軟體開發中佔據重要地位。在託管開發方面，MFC中也包括對Windows Forms和託管／非託管互操作的封裝。微軟在Windows Vista和Windows 7釋出之後在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的。MFC的結構.作為一個應用程式的開發框架，必須滿足各方面的功能需求。應用程式啟動.基於MFC開發的應用程式在啟動時，Windows作業系統：訊息迴圈與訊息對映.控制元件的通知訊息與反射訊息.窗體上的控制元件，應當向父窗體通報控制元件發生的各種事件，如被點選、繪製、內容改變等等，稱為通知訊息。在 Windows 3.x的16位程式設計時代，控制元件向父窗體傳送WM_COMMAND訊息，由父窗體的程式碼負責實現這些事件。其中wParam的低16位是 control ID，高16位是notification code (例如BN_CLICKED)；lParam是控制元件控制代碼。因此，再無可能傳遞其它資訊給父窗體。為此，為傳遞具有特別內容的控制元件事件，Windows 3.x定義了一批特殊的通知訊息(notification messages)：早於4.0版本的MFC，在控制元件類提供了虛擬函式處理這些通知訊息，這一辦法已經被下述的“訊息反射”取代。隨著Windows 95開始了32位程式時代，伴之而來的是Win32 API 與 MFC 4.0。 Win32增加了很多複雜的控制元件，需要使用更多的通知訊息傳遞很多複雜的資料給父窗體。Win32 API僅僅增加了一個訊息WM_NOTIFY，就實現了這些功能。lParam引數開頭是NMHDR資料結構，其後是與該通知型別相關的特定資料結構。typedef struct tagNMHDR {HWND hwndFrom;UINT idFrom;UINT code;} NMHDR;CWnd::OnNotify函式處理通知訊息。它的預設實現是檢查訊息對映表查詢通知的處理器函式並呼叫。一般說來，不必覆蓋OnNotify；而應該寫一個處理器函式並增加為該視窗類的訊息對映表條目。ON_NOTIFY(wNotifyCode, id, memberFxn)成員函式應該寫為：afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);MFC 4.0提供了一種特性“訊息反射”。控制元件中透過ON_NOTIFY_REFLECT_EX()宣告的反射訊息處理函式可以返回真或假，以決定父視窗是否繼續處理該通知訊息。WM_NOTIFY以外的其它通知訊息，父視窗在第一時間有機會處理它，控制元件對它的處理排在第二位。反射訊息處理函式通常使用特定的名字，對應的訊息反射宏的名字是在訊息名字加上字首ON_，字尾_REFLECT。如WM_CTLCOLOR對應ON_WM_CTLCOLOR_REFLECT。但以下三種情況，反射訊息處理函式可以隨意自行起名，對應的訊息反射宏的名字分別為：訊息傳遞處理機制.MFC類體系中，Windows訊息傳遞處理機制是基於CCmdTarget類及其派生類的靜態成員函式GetThisMessageMap()內部定義的靜態資料成員：在標頭檔案的類定義中使用宏DECLARE_MESSAGE_MAP()來宣告靜態成員函式GetThisMessageMap與虛擬函式GetMessageMap使用者所寫的類的Windows訊息處理函式必須轉換為CCmdTarget::*的成員函式指標型別AFX_PMSG，儲存在該類的_messageEntries陣列中。struct AFX_MSGMAP_ENTRYUINT nMessage; // windows訊息代號UINT nCode; // WM_NOTIFY的控制程式碼UINT nID; // WM_COMMAND下面的ID號，如果為其他的訊息，則這個數字為0UINT nLastID; //和前面的ID一起組成一個範圍，用於傳送一次訊息，處理執行多次UINT nSig; // 標誌訊息處理函式的型別AFX_PMSG pfn; // 函式呼叫指標typedef void (CCmdTarget::*AFX_PMSG)(void);呼叫使用者類中該訊息處理函式時，根據該函式儲存在_messageEntries中的signature，然後呼叫轉換後的成員函式指標。這是基於Visual C++編譯器把單繼承的成員函式指標編譯為只儲存了函式的記憶體起始地址，因此可以在同一個單繼承類中把一種型別的成員函式指標強制轉換為另一種成員函式指標，或者把單繼承派生類的成員函式指標強制轉換為基類成員函式指標。這是打破了C++標準的違例辦法。例如，對於CWnd::OnCommand函式，轉換過程是：BOOL (CWnd::*)(WPARAM, LPARAM lParam) =&gt; void (CWnd::*)() =&gt; void (CCmdTarget::*)()CString.CString是MFC中最常見的類之一，用於封裝字串資料結構。它只有一個數據成員m_pszData，其值為字串的首地址，其資料型別為wchar_t*或char*。在CString的m_pszData的前面實際還分配了CSringData資料塊，包含了管理資料:IAtlStringMgr* pStringMgr;int nDataLength;int nAllocLength;int nRefs;自底向上，CAtlStringMgr提供記憶體管理，CStringData提供共享管理，CString提供字串操作。CAtlStringMgr的一個成員是IAtlMemMgr介面，這是策略模式，可以引用某個記憶體管理類。CAtlStringMgr的另一個成員是CNilStringData。因此，每次為CString動態分配地址空間，實際分配長度為:codice_1。透過 Attach 操作，將這個 CStringData* 與 CSimpleStringT::m_pszData 執行了關聯。當執行CString的預設建構函式生成一個空串時，實際上都是構造一個CnilStringData物件。CNilStringData 派生自 CStringData，額外擁有一個 achNil 的陣列成員，這個陣列初始化為空字串。透過這個 achNil，保證了一個經過呼叫預設建構函式初始化的 CString，其指向的真正的字串是一個空串。部分編譯器對std::string放棄了寫時複製機制。但是，CString一直採取這一機制。CSimpleStringT::Fork 函式就提供了這樣一個操作，具體分為下面幾步：GetString方法返回的是隻讀的字串地址；而GetBuffer方法返回的是可寫的字串地址。CString物件用作可變引數函式的實參時，由於無法透過形參型別確定呼叫哪個CString的型別轉換運算子函式，因此有必要顯式指明要轉換的型別。如果需要在函式的引數傳遞CString，由於CString使用了引用計數，因此函式引數傳遞一個CString物件是可行的；不需要修改其內容時，推薦使用const CString&amp;。支援MFC的DLL開發.使用Visual C++可以開發3種DLL:由於DLL與呼叫它的應用程式都可以有自己的MFC全域性資料與控制代碼對映，如果控制代碼值相同，則預設使用應用程式的對映到的資源。為了不互相干擾，允許DLL內部使用自己的資源，必須在DLL函式的入口處把資源模組控制代碼從預設的應用程式切換為該DLL。辦法是：