MFC 延伸模組 DLL
MFC 擴充 DLL 是一種 DLL,通常實作衍生自現有 Microsoft Foundation Class Library 類別的可重複使用類別。
MFC 擴充功能 DLL 具有下列功能和需求:
用戶端可執行檔必須是使用
_AFXDLL
定義的編譯 MFC 應用程式。MFC 擴充功能 DLL 也可以由動態連結至 MFC 的一般 MFC DLL 使用。
MFC 擴充 DLL 應該使用已定義來
_AFXEXT
編譯。 這也會強制_AFXDLL
定義,並確保從 MFC 標頭檔提取適當的宣告。 它也可確保AFX_EXT_CLASS
在建置 DLL 時定義為__declspec(dllexport)
,如果您使用這個宏來宣告 MFC 擴充 DLL 中的類別,這是必要的。MFC 擴充 DLL 不應該具現化衍生自
CWinApp
的類別,但應該依賴用戶端應用程式 (或 DLL) 來提供這個物件。不過,MFC 擴充 DLL 應該提供函
DllMain
式,並在該處執行任何必要的初始化。
擴充 DLL 是使用 MFC 的動態連結程式庫版本所建置(也稱為 MFC 的共用版本)。 只有使用 MFC 共用版本所建置的應用程式或一般 MFC DLL 的 MFC 可執行檔可以使用 MFC 延伸模組 DLL。 用戶端應用程式和 MFC 擴充功能 DLL 都必須使用相同的 MFCx0.dll 版本。 透過 MFC 擴充 DLL,您可以從 MFC 衍生新的自訂類別,然後將這個擴充版本的 MFC 提供給呼叫 DLL 的應用程式。
擴充 DLL 也可用於在應用程式和 DLL 之間傳遞 MFC 衍生的物件。 與傳遞物件相關聯的成員函式存在於建立物件的模組中。 由於這些函式在使用 MFC 的共用 DLL 版本時會正確匯出,因此您可以在應用程式與載入的 MFC 延伸模組 DLL 之間自由傳遞 MFC 或 MFC 衍生的物件指標。
MFC 擴充功能 DLL 使用 MFC 的共用版本,就像應用程式使用 MFC 的共用 DLL 版本一樣,還有一些其他考慮:
它沒有
CWinApp
衍生的物件。 它必須使用CWinApp
用戶端應用程式的衍生物件。 這表示用戶端應用程式擁有主要訊息幫浦、閒置迴圈等等。它會在其函式中
DllMain
呼叫AfxInitExtensionModule
。 應該檢查此函式的傳回值。 如果從AfxInitExtensionModule
傳回零值,則從函DllMain
式傳回 0。如果 MFC 擴充 DLL 想要將物件或資源匯出
CRuntimeClass
至應用程式,則會在初始化期間建立 CDynLinkLibrary 物件。
在 MFC 4.0 版之前,這種 DLL 類型稱為 AFXDLL。 AFXDLL 是指 _AFXDLL
建置 DLL 時定義的預處理器符號。
共用 MFC 版本的匯入程式庫會根據 MFC DLL 命名慣例中所述 的慣例來命名。 Visual Studio 提供預先建置的 MFC DLL 版本,加上許多非 MFC DLL,可供您搭配應用程式使用及散發。 這些記載于 Redist.txt 中,其會安裝到 Program Files\Microsoft Visual Studio 資料夾。
如果您要使用 .def 檔案匯出,請將下列程式碼放在標頭檔開頭和結尾:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA
這四行可確保您的程式碼已針對 MFC 延伸模組 DLL 正確編譯。 排除這四行可能會導致 DLL 編譯或連結不正確。
如果您需要將 MFC 或 MFC 衍生的物件指標傳遞至 MFC DLL 或從 MFC DLL,DLL 應該是 MFC 擴充 DLL。 與傳遞物件相關聯的成員函式存在於建立物件的模組中。 由於這些函式在使用 MFC 的共用 DLL 版本時會正確匯出,因此您可以在應用程式與載入的 MFC 延伸模組 DLL 之間自由傳遞 MFC 或 MFC 衍生的物件指標。
由於 C++ 名稱管理及匯出問題,不同平臺之相同 DLL 偵錯和零售版本的匯出清單可能會不同。 零售 MFCx0.dll 有大約 2,000 個匯出進入點:偵錯 MFCx0D.dll 有大約 3,000 個匯出的進入點。
記憶體管理
MFCx0.dll 和載入用戶端應用程式位址空間的所有 MFC 擴充 DLL 都會使用相同的記憶體配置器、資源載入和其他 MFC 全域狀態,就像它們位於相同的應用程式中一樣。 這很重要,因為非 MFC DLL 程式庫和一般 MFC DLL 會執行完全相同的動作,並讓每個 DLL 配置出自己的記憶體集區。
如果 MFC 延伸模組 DLL 配置記憶體,該記憶體可以自由地與任何其他應用程式佈建的物件混搭。 此外,如果動態連結至 MFC 的應用程式失敗,作業系統的保護會維護任何其他共用 DLL 之 MFC 應用程式的完整性。
同樣地,其他全域 MFC 狀態,例如從中載入資源的目前可執行檔,也會在用戶端應用程式與所有 MFC 擴充 DLL 以及 MFCx0.dll 本身之間共用。
共用資源和類別
匯出資源是透過資源清單來完成。 每個應用程式都包含 CDynLinkLibrary 物件的單選連結清單 。 尋找資源時,載入資源的大部分標準 MFC 實作會先查看目前的資源模組 ( AfxGetResourceHandle
),如果找不到資源,請流覽嘗試載入所要求資源的 CDynLinkLibrary 物件清單 。
逐步執行清單有稍微慢一點的缺點,而且需要管理資源識別碼範圍。 它的優點是連結至數個 MFC 擴充 DLL 的用戶端應用程式可以使用任何 DLL 提供的資源,而不需要指定 DLL 實例控制碼。 AfxFindResourceHandle
是用來步行資源清單來尋找指定相符專案的 API。 它會取得資源的名稱和類型,並傳回第一次找到的資源控制碼(或 Null)。
如果您不想要逐步執行清單,而且只從特定位置載入資源,請使用 函 AfxGetResourceHandle
式並 AfxSetResourceHandle
儲存舊的控制碼並設定新控制碼。 返回用戶端應用程式之前,請務必先還原舊的資源控制碼。 如需使用此方法明確載入功能表的範例,請參閱 MFC 範例 DLLHUSK 中的 Testdll2 .cpp。
指定 MFC 名稱的 MFC 物件動態建立很類似。 MFC 物件還原序列化機制必須註冊所有 CRuntimeClass
物件,以便根據先前儲存的物件動態建立所需類型的 C++ 物件,以重新建構它。
在 MFC 範例 DLLHUSK 的案例中,清單看起來會像這樣:
head -> DLLHUSK.EXE - or - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
MFCOxxD.DLL |
| |
MFCDxxD.DLL |
| |
MFCxxD.DLL MFCxx.DLL
其中 xx 是版本號碼,例如 42 代表 4.2 版。
MFCxx.dll 通常最後一個位於資源和類別清單上。 MFCxx.dll 包含所有標準 MFC 資源,包括所有標準命令識別碼的提示字串。 將它放在清單結尾可讓 DLL 和用戶端應用程式本身沒有自己的標準 MFC 資源複本,而是依賴 MFCxx.dll 中的共用資源。
將所有 DLL 的資源和類別名稱合併到用戶端應用程式的名稱空間中,有缺點是要求您小心您挑選的識別碼或名稱。
DLLHUSK 範例會使用多個標頭檔來管理共用資源名稱空間。
如果您的 MFC 延伸模組 DLL 需要維護每個應用程式的額外資料,您可以從 CDynLinkLibrary 衍生新的類別 ,並在 中 DllMain
建立它。 執行時,DLL 可以檢查目前應用程式的 CDynLinkLibrary 物件清單 ,以尋找該特定 MFC 擴充 DLL 的清單。