在 DLL 中使用對話框、圖標等資源是常見需求,但 Win32 DLL 與 MFC DLL 的實現機制截然不同。本文系統講解兩類 DLL 的資源使用方法,重點剖析 MFC 模塊狀態切換的核心原理與實戰技巧。
Win32 DLL 直接使用 Windows API,流程簡單明確:
IDD_DLG_SHOW、IDD_ABOUTBOX)。ShowDlg()),內部調用 CreateDialog(非模態)或 DialogBox(模態)創建對話框,並指定回調函數處理消息。DllMain 中保存 HINSTANCE 供資源加載使用。.lib)調用導出函數即可。關鍵點: Win32 DLL 無「模塊狀態」概念,資源句柄即 DLL 實例句柄,直接傳給 API 即可正確加載。
MFC 使用全局狀態數據區分不同模塊(EXE/DLL),包含:實例句柄(加載資源用)、CWinApp/CWinThread 指針、OLE 引用計數、句柄映射表等。每個模塊擁有私有副本,只有當前模塊狀態有效時,MFC 才能正確查找資源。
DLL 內部鏈接 MFC 靜態庫,擁有獨立 MFC 副本,自動使用自身模塊狀態,無需手動切換。缺點是體積較大、代碼重複。
驗證:DLL 與 EXE 定義相同 ID 的對話框資源,調用 DLL 導出函數彈出的始終是 DLL 自己的對話框。
共享 MFC DLL 時,默認使用主應用程序的資源句柄,導致無法加載 DLL 內部資源(或加載到同 ID 的 EXE 資源)。必須手動切換模塊狀態。
| 方法 | 類型 | 適用場景 | 關鍵代碼 |
|---|---|---|---|
AFX_MANAGE_STATE(AfxGetStaticModuleState()) | 宏 | Regular DLL (Shared MFC) | 放在導出函數第一行,作用域結束自動恢復 |
AFX_MANAGE_STATE(AfxGetAppModuleState()) | 宏 | MFC Extension DLL | 同上,避免鏈接錯誤 __pRawDllMain 重複定義 |
AfxGetResourceHandle() / AfxSetResourceHandle() | API | 需精確控制恢復時機 | 手動保存/設置/恢復句柄,可在 DoModal() 後立即恢復 |
EXE 端調用 AfxSetResourceHandle | API | 不修改 DLL 源碼時 | EXE 獲取 DLL 模塊句柄(GetModuleHandle)切換 |
void ShowDlg()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Regular DLL
// AFX_MANAGE_STATE(AfxGetAppModuleState()); // Extension DLL
CDialog dlg(IDD_ABOUTBOX);
dlg.DoModal();
}
void ShowDlg()
{
HINSTANCE hOld = AfxGetResourceHandle();
AfxSetResourceHandle(theApp.m_hInstance); // 或 GetModuleHandle(_T("MyDLL.dll"))
CDialog dlg(IDD_ABOUTBOX);
dlg.DoModal();
AfxSetResourceHandle(hOld); // 立即恢復,避免工具條重繪等問題
}
最佳實踐: 在
WM_INITDIALOG處理後恢復句柄最安全,因對話框模板已讀取完畢,後續繪製不再依賴 DLL 資源。
| DLL 類型 | 是否需切換模塊狀態 | 推薦方法 |
|---|---|---|
| Win32 DLL | 否 | 直接用實例句柄調用 API |
| MFC 靜態鏈接 Regular DLL | 否 | 自動使用自身狀態 |
| MFC 動態鏈接 Regular DLL | 是 | AFX_MANAGE_STATE(AfxGetStaticModuleState()) |
| MFC Extension DLL | 是 | AFX_MANAGE_STATE(AfxGetAppModuleState()) |