TN011:將 MFC 當成 DLL 的一部分來使用
此附注描述一般 MFC DLL,可讓您使用 MFC 程式庫作為 Windows 動態連結程式庫 (DLL) 的一部分。 它假設您熟悉 Windows DLL 並知道如何建置它們。 如需 MFC 擴充功能 DLL 的相關資訊,您可以建立 MFC 程式庫的延伸模組,請參閱 MFC 的 DLL 版本。
DLL 介面
一般 MFC DLL 假設應用程式與 DLL 之間的介面是在類似 C 的函式或明確匯出的類別中指定。 MFC 類別介面無法匯出。
如果 DLL 和應用程式都要使用 MFC,二者均可選擇要使用共用版本的 MFC 程式庫或靜態地連結至程式庫的複本。 應用程式和 DLL 可能都使用其中一個標準版本的 MFC 程式庫。
一般 MFC DLL 有幾個優點:
使用 DLL 的應用程式不一定要使用 MFC,而且不一定要是 Visual C++ 應用程式。
使用靜態連結至 MFC 的一般 MFC DLL 時,DLL 的大小只取決於使用和連結的 MFC 和 C 執行時間常式。
透過動態連結至 MFC 的一般 MFC DLL,使用共用 MFC 版本的記憶體節省可能會相當重要。 不過,您必須使用 DLL 散發共用 DLL、Mfc version.dll > 和 Msvvcrt < version.dll > 。 <
DLL 的設計與如何實作類別無關。 您的 DLL 設計只會匯出至您要的 API。 因此,如果實作變更,一般 MFC DLL 仍然有效。
使用靜態連結至 MFC 的一般 MFC DLL,如果 DLL 和應用程式都使用 MFC,則應用程式沒有問題,該應用程式想要與 DLL 不同的版本,反之亦然。 因為 MFC 程式庫是靜態連結至每個 DLL 或 EXE,所以您擁有什麼版本並不會造成任何問題。
API 限制
部分 MFC 功能會因為技術上的限制,或是因為這些服務通常由應用程式提供,而不適用於 DLL 版本。 若是目前版本的 MFC,唯一不適用的函式是 CWinApp::SetDialogBkColor
。
建置 DLL
編譯靜態連結至 MFC 的一般 MFC DLL 時,必須定義 符號 _USRDLL
和 _WINDLL
。 您的 DLL 程式碼也必須使用下列編譯器參數進行編譯:
/D_WINDLL 表示編譯適用于 DLL
/D_USRDLL 指定您要建置一般 MFC DLL
當您編譯動態連結至 MFC 的一般 MFC DLL 時,您也必須定義這些符號,並使用這些編譯器參數。 此外,符號 _AFXDLL
必須加以定義,而且您的 DLL 程式碼必須使用下列項目進行編譯:
- /D_AFXDLL 指定您要建置一般 MFC DLL,以動態方式連結至 MFC
應用程式和 DLL 之間的介面 (API) 必須明確地匯出。 建議您定義介面為低頻寬,並且可以的話只使用 C 介面。 直接 C 介面比較複雜的 C++ 類別容易維護。
將 API 放在 C 和 C++ 檔案都可包含的個別標頭中。 如需範例,請參閱 MFC 進階概念範例 DLLScreenCap 中的標頭 ScreenCap.h 。 若要匯出函式,請在您的模組定義檔 (.DEF) 的 EXPORTS
區段中輸入那些函式,或者在您的函式定義包括 __declspec(dllexport)
。 使用 __declspec(dllimport)
將這些函式匯入用戶端可執行檔。
您必須在一般 MFC DLL 中動態連結至 MFC 的所有匯出函式開頭新增AFX_MANAGE_STATE宏。 這個巨集會將目前的模組狀態設定為 DLL 的狀態。 若要使用這個巨集,請將以下程式碼行加入至從 DLL 匯出的函式開頭:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
WinMain - > DllMain
MFC 程式庫會定義標準 Win32 DllMain
進入點,以在一般 MFC 應用程式中將 CWinApp 衍生的物件初始化 為 。 將所有 DLL 特定的初始化放在 InitInstance 方法中,如同在一般 MFC 應用程式中一樣。
請注意, CWinApp::Run 機制不適用於 DLL,因為應用程式擁有主要訊息幫浦。 如果您的 DLL 顯示無強制回應對話方塊,或有自己的主框架視窗,則應用程式的主要訊息幫浦必須呼叫呼叫 CWinApp::P reTranslateMessage 的 DLL 匯出常式。
有關這個函式的使用,請參閱 DLLScreenCap 範例。
DllMain
MFC 提供的函式會呼叫 您類別的 CWinApp::ExitInstance 方法,該方法衍生自 CWinApp
DLL 卸載之前。
連結您的 DLL
使用靜態連結至 MFC 的一般 MFC DLL,您必須將 DLL 與 Nafxcwd.lib 或 Nafxcw.lib 連結,以及名為 Libcmt.lib 的 C 執行時間版本。 這些程式庫為預先建置,並且可以透過在執行 Visual C++ 設定時進行指定來加以安裝。
範例程式碼
如需完整的範例,請參閱 MFC 進階概念範例程式 DLLScreenCap。 此範例中的提示有以下幾點注意事項:
DLL 的編譯器旗標和應用程式的編譯器旗標不同。
DLL 的連結程式行和 .DEF 檔和應用程式的連結程式行和 .DEF 檔不同。
使用 DLL 的應用程式不一定要在 C++ 中。
應用程式和 DLL 之間的介面是可由 C 或 C++ 使用的 API,並且使用 DLLScreenCap.def 匯出。
下列範例說明在靜態連結至 MFC 的一般 MFC DLL 中定義的 API。 在此範例中,宣告是括在 C++ 使用者的 extern "C" { }
區塊中。 這有幾項優點。 首先,它可讓非 C++ 用戶端應用程式也能夠使用您的 DLL API。 第二,它降低了 DLL 的額外負荷,因為 C++ 名稱重整 (Name Mangling) 不會套用至已匯出的名稱。 最後,它可讓您更易明確地加入至 .DEF 檔案 (以便於依序匯出),而不需要擔心名稱修飾。
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct TracerData
{
BOOL bEnabled;
UINT flags;
};
BOOL PromptTraceFlags(TracerData FAR* lpData);
#ifdef __cplusplus
}
#endif
API 所使用的結構不是從 MFC 類別衍生,而是在 API 標頭中定義。 這可減少 DLL 和應用程式之間介面的複雜度,並讓 C 程式能夠使用 DLL。