使用 AFX_EXT_CLASS 导出和导入

扩展 DLL 使用 AFX_EXT_CLASS 宏导出类;链接到扩展 DLL 的可执行文件使用该宏导入类。 用于生成扩展 DLL 的相同头文件可通过 AFX_EXT_CLASS 宏与链接到 DLL 的可执行文件一起使用。

在 DLL 的头文件中,将 AFX_EXT_CLASS 关键字添加到类的声明中,如下所示:

class AFX_EXT_CLASS CMyClass : public CDocument
{
// <body of class>
};

当定义了预处理器符号 _AFXDLL_AFXEXT 时,该宏被 MFC 定义为 __declspec(dllexport)。 但当定义了 _AFXDLL 而未定义 _AFXEXT 时,该宏被定义为 __declspec(dllimport)。 定义后,预处理器符号 _AFXDLL 指示共享 MFC 版本正在由目标可执行文件(DLL 或应用程序)使用。 当 _AFXDLL_AFXEXT 都定义了时,这指示目标可执行文件是扩展 DLL。

由于从扩展 DLL 导出时,AFX_EXT_CLASS 被定义为 __declspec(dllexport),因此可以导出整个类,而不必将该类的所有符号的修饰名放到 .def 文件中。 此方法由 MFC 示例 DLLHUSK 使用。

虽然使用此方法可以避免创建 .def 文件和类的所有修饰名,但由于名称可以按序号导出,因此创建 .def 文件的效率更高。 若要使用 .def 文件导出方法,请将下列代码放在头文件的开头和结尾处:

#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA

警告

导出内联函数时要小心,因为它们有可能导致版本冲突。内联函数扩展到应用程序代码中;因此,如果以后重写内联函数,除非重新编译应用程序本身,否则内联函数不会被更新。通常,不用重新生成使用 DLL 函数的应用程序就可以更新 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 的 Helper 宏实际声明或定义数据成员。 因此,还必须从 DLL 导出这些数据成员。

例如,当生成扩展 DLL 时,DECLARE_DYNAMIC 宏的定义如下:

#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

备注

如果导出整个类而非选定的类成员,静态数据成员将自动导出。

你希望做什么?

您想进一步了解什么?

请参见

概念

从 DLL 导出