| 類型 | MFC 使用方式 | 適用場景 | 體積/部署 |
| Regular DLL (共享 MFC) | 動態連結 MFC DLL (mfc140.dll 等) | 一般功能 DLL、控制項庫、大型專案模組化 | DLL 小,需部署 MFC 運行庫 |
| Regular DLL (靜態連結 MFC) | 靜態連結 MFC 程式庫 | 無 MFC 環境目標機、簡易工具 DLL | DLL 較大 (含 MFC 程式碼),無外部相依 |
| Extension DLL | 共享 MFC,**匯出 MFC 衍生類** | 提供可被客戶端繼承的 MFC 類別、文檔/視圖範本 | 需共享 MFC DLL,客戶端也須用共享 MFC |
關鍵差異:Extension DLL 匯出完整 C++ 類別 (含虛擬函數表),客戶端可直接繼承;Regular DLL 僅匯出 C 風格函數或非 MFC 類別。
模組狀態:跨 DLL 邊界的資源與類別管理
MFC 維護 AFX_MODULE_STATE 結構,每個模組 (EXE/DLL) 各有一份:
- 資源鏈柄:
m_hCurrentResourceHandle,決定 AfxFindResource、LoadString、對話框模板等資源來源。
- 類別工廠鏈表:
m_classList,支援 CRuntimeClass 動態建立、OLE 類別註冊。
- OLE 伺服器資訊、訊息映射鎖 等。
AFX_MANAGE_STATE 宏:切換模組狀態的鑰匙
// Extension DLL 導出函數入口必加
extern "C" __declspec(dllexport) void MyExportedFunction()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // 切換到 DLL 自身模組狀態
// 此處安全使用 MFC 資源、動態建立、OLE 等
CMyDialog dlg; dlg.DoModal(); // 正確載入 DLL 內的對話框資源
}
規則:所有 DLL 導出函數入口、回呼函數、執行緒函數 必須以此宏開頭。否則資源載入失敗、動態建立找不到類別、Assert 失敗。
連結規範與名稱修飾
| 規範 | 語法 | 名稱修飾 | 用途 |
| C++ (預設) | void Foo(); | 嚴重修飾 (?Foo@@YAXXZ),含類別、參數、呼叫慣例 | C++ 類別成員、多載函數 |
| C | extern "C" void Foo(); | 無修飾 (_Foo@0 或 Foo),僅含參數大小 | DLL 導出函數、跨語言呼叫、GetProcAddress |
標準模式:
// MyDll.h
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
MYDLL_API int __stdcall MyFunc(int a, int b); // 使用 __stdcall (WINAPI) 統一呼叫慣例
#if defined(__cplusplus)
}
#endif
匯入庫 (.lib)、匯出檔 (.exp)、映像檔 (.map)
- .lib (匯入庫):含 DLL 導出符號的存根,連結器用它解析 .exe 對 DLL 的引用。COFF 格式,可用
dumpbin /exports 檢視。
- .exp (匯出檔):連結器產生,含導出符號資訊,用於建立 DLL (隱含步驟)。
- .map (映像檔):連結器輸出,含區段佈局、公共符號表、入口點、Fixup 表,除錯符號解析必備。
資源管理與共享資料區段
共享資料區段 (Named Data Section)
// 僅 Extension DLL 或 Regular DLL (靜態 MFC) 可用
#pragma data_seg("SHARED_DATA")
LONG g_lRefCount = 0; // 所有載入此 DLL 的進程共享此變數
#pragma data_seg()
#pragma comment(linker, "/SECTION:SHARED_DATA,RWS") // 告訴連結器:可讀寫共享
慎用:需自行同步化 (Mutex),且僅限基本型別/POD,不可放置 C++ 物件 (建構/解構問題)。
實戰檢查清單
- 專案屬性 → Configuration Type: Dynamic Library (.dll)。
- Use of MFC: Shared DLL (推薦) 或 Static。
- Preprocessor Definitions 加入
MYDLL_EXPORTS (DLL 專案) / 移除 (客戶端)。
- 導出函數/類別加
MYDLL_API + extern "C" (C 函數) / AFX_CLASS_EXPORT (MFC 類別)。
- 所有導出入口函數首行加
AFX_MANAGE_STATE(AfxGetStaticModuleState())。
- 客戶端專案:Additional Dependencies 加入 .lib,Additional Include Directories 加入 DLL 標頭路徑。
- 部署:DLL 放入應用程式目錄或 System32;共享 MFC 需安裝 VC++ Redistributable。
總結
MFC DLL 開發的核心在於模組狀態隔離與正確的匯出/導入聲明。理解「載入時 vs 執行時動態連結」、「Regular vs Extension DLL」、「AFX_MANAGE_STATE 切換機制」、「名稱修飾與呼叫慣例」,並遵循標準專案配置流程,即可構建穩定、可維護、可跨專案複用的 DLL 組件。
- 上一篇文章: MFC 應用程式優雅退出全流程:從 WM_CLOSE 到文檔關閉的完整機制
- 下一篇文章: MFC 程式設計:深入理解 Win32 行程與執行緒
Copyright ©
程式碼之家 All Rights Reserved