使用 AFX_EXT_CLASS 匯出和匯入
MFC 擴充 DLL 會使用巨集 AFX_EXT_CLASS 匯出類別;連結至 MFC 延伸模組 DLL 的可執行檔會使用巨集匯入類別。 使用 AFX_EXT_CLASS 巨集,用來建置 MFC 延伸模組 DLL 的相同頭檔可以與連結至 DLL 的可執行檔搭配使用。
在 DLL 的標頭檔中,將 AFX_EXT_CLASS 關鍵詞新增至類別的宣告,如下所示:
class AFX_EXT_CLASS CMyClass : public CDocument
{
// <body of class>
};
當預處理器符號_AFXDLL
和 _AFXEXT
定義時,MFC 會定義這個__declspec(dllexport)
巨集。 但是,巨集的定義是當 __declspec(dllimport)
已定義且_AFXEXT
未定義時_AFXDLL
。 定義時,預處理器符號 _AFXDLL
表示目標可執行檔正在使用共用版本的MFC(DLL 或應用程式)。 _AFXDLL
定義 和 _AFXEXT
時,這表示目標可執行檔是MFC擴充 DLL。
因為 AFX_EXT_CLASS
從 MFC 延伸模組 DLL 匯出時定義為 __declspec(dllexport)
,因此您可以匯出整個類別,而不需要將該類別的所有符號裝飾名稱放在 .def 檔案中。
雖然您可以使用此方法避免建立 .def 檔案和 類別的所有裝飾名稱,但建立 .def 檔案會更有效率,因為名稱可以藉由序數導出。 若要使用導出的 .def 檔案方法,請將下列程式代碼放在頭檔開頭和結尾:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA
警告
匯出內嵌函式時請小心,因為它們可能會造成版本衝突的可能性。 內嵌函式會展開至應用程式程序代碼;因此,如果您稍後重寫函式,除非重新編譯應用程式本身,否則它不會更新。 一般而言,DLL 函式可以更新,而不需重建使用這些函式的應用程式。
匯出類別中的個別成員
有時候您可能會想要匯出類別的個別成員。 例如,如果您要匯出 CDialog
衍生類別,您可能只需要匯出建構函式和 DoModal
呼叫。 您可以在 AFX_EXT_CLASS
需要匯出的個別成員上使用 。
例如:
class CExampleDialog : public CDialog
{
public:
AFX_EXT_CLASS CExampleDialog();
AFX_EXT_CLASS int DoModal();
...
// rest of class definition
...
};
因為您不再匯出 類別的所有成員,因此可能會因為 MFC 巨集的運作方式而遇到其他問題。 MFC 的數個協助程式巨集實際上會宣告或定義數據成員。 因此,這些數據成員也必須從 DLL 導出。
例如, DECLARE_DYNAMIC
建置 MFC 擴充 DLL 時,巨集的定義如下:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
以 static AFX_DATA
開頭的行是在類別內宣告靜態物件。 若要正確匯出這個類別並從用戶端可執行檔存取運行時間資訊,您必須匯出此靜態物件。 因為靜態物件是以 修飾詞 AFX_DATA
宣告,所以您只需要在建置 DLL 時定義 AFX_DATA
__declspec(dllexport)
, __declspec(dllimport)
並在建置用戶端可執行檔時將其定義為 。 因為 AFX_EXT_CLASS
已經以此方式定義,因此您只需要重新定義 AFX_DATA
與類別定義周圍的相同 AFX_EXT_CLASS
。
例如:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_CLASS
class CExampleView : public CView
{
DECLARE_DYNAMIC()
// ... class definition ...
};
#undef AFX_DATA
#define AFX_DATA
因為 MFC 一律在其 AFX_DATA
巨集內定義之數據項上使用 符號,所以這項技術適用於所有這類案例。 例如,它適用於 DECLARE_MESSAGE_MAP
。
注意
如果您要匯出整個類別,而不是類別的選取成員,則會自動匯出靜態數據成員。