c++中dll函数的导出和导入_第1页
c++中dll函数的导出和导入_第2页
c++中dll函数的导出和导入_第3页
c++中dll函数的导出和导入_第4页
c++中dll函数的导出和导入_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1. 使用 DEF 文件从 DLL 导出 模块定义 (.def) 文件是包含一个或多个描述 DLL 各种属性的 Module 语句的文本文件。如果不使用 _declspec(dllexport) 关键字导出 DLL 的函 数,则 DLL 需要 .def 文件。 .def 文件必须至少包含下列模块定义语句: 文件中的第一个语句必须是 LIBRARY 语句。此语句将 .def 文件标识为 属于 DLL。LIBRARY 语句的后面是 DLL 的名称。链接器将此名称放到 DLL 的导入库中。 EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。 通过在函数名的后面加上 符和一个数字,给函数分配序号值。当指定序号 值时,序号值的范围必须是从 1 到 N,其中 N 是 DLL 导出函数的个数。如 果希望按序号导出函数,请参见按序号而不是按名称从 DLL 导出函数以及本 主题。 例如,包含实现二进制搜索树的代码的 DLL 看上去可能像下面这样: LIBRARY BTREE EXPORTS Insert 1 Delete 2 Member 3 Min 4 如果使用 MFC DLL 向导创建 MFC DLL,则向导将为您创建主干 .def 文件并将其自动添加到项目中。添加要导出到此文件的函数名。对于非 MFC DLL,必须亲自创建 .def 文件并将其添加到项目中。 如果导出 C+ 文件中的函数,必须将修饰名放到 .def 文件中,或者通 过使用外部“C”定义具有标准 C 链接的导出函数。如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具或 /MAP 链接器选项来获取 修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将 Visual C+ 编译器产生的修饰名放到 .def 文件中,则链接到 DLL 的应用程序必须也是用 相同版本的 Visual C+ 生成的,这样调用应用程序中的修饰名才能与 DLL 的 .def 文件中的导出名相匹配。 如果生成扩展 DLL 并使用 .def 文件导出,则将下列代码放在包含导出类 的头文件的开头和结尾: #undef AFX_DATA #define AFX_DATA AFX_EXT_DATA / #undef AFX_DATA #define AFX_DATA 这些代码行确保内部使用的 MFC 变量或添加到类的变量是从扩展 DLL 导出(或导入)的。例如,当使用 DECLARE_DYNAMIC 派生类时,该宏扩 展以将 CRuntimeClass 成员变量添加到类。省去这四行代码可能会导致不能 正确编译或链接 DLL,或在客户端应用程序链接到 DLL 时导致错误。 当生成 DLL 时,链接器使用 .def 文件创建导出 (.exp) 文件和导入库 (.lib) 文件。然后,链接器使用导出文件生成 DLL 文件。隐式链接到 DLL 的 可执行文件在生成时链接到导入库。 请注意,MFC 本身使用 .def 文件从 MFCx0.dll 导出函数和类。 2. 使用 _declspec(dllexport) 从 DLL 导出 Microsoft 在 Visual C+ 的 16 位编译器版本中引入了 _export,使 编译器得以自动生成导出名并将它们放到一个 .lib 文件中。然后,此 .lib 文 件就可以像静态 .lib 那样用于与 DLL 链接。 在更新的编译器版本中,可以使用 _declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。_declspec(dllexport) 会将导出指令添 加到对象文件中,因此您不需要使用 .def 文件。 当试图导出 C+ 修饰函数名时,这种便利最明显。由于对名称修饰没有 标准规范,因此导出函数的名称在不同的编译器版本中可能有所变化。如果使 用 _declspec(dllexport),仅当解决任何命名约定更改时才必须重新编译 DLL 和依赖 .exe 文件。 许多导出指令(如序号、NONAME 和 PRIVATE)只能在 .def 文件中创 建,并且必须使用 .def 文件来指定这些属性。不过,在 .def 文件的基础上另 外使用 _declspec(dllexport) 不会导致生成错误。 若要导出函数,_declspec(dllexport) 关键字必须出现在调用约定关键 字的左边(如果指定了关键字)。例如: _declspec(dllexport) void _cdecl Function1(void); 若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的 左边,如下所示: class _declspec(dllexport) CExampleExport : public CObject . class definition . ; 生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件, 并将 _declspec(dllexport) 添加到头文件中的声明中。若要提高代码的可读 性,请为 _declspec(dllexport) 定义一个宏并对正在导出的每个符号使用该 宏: #define DllExport _declspec( dllexport ) _declspec(dllexport) 将函数名存储在 DLL 的导出表中。如果希望优化 表的大小,请参见按序号而不是按名称从 DLL 导出函数。 注意:将 DLL 源代码从 Win16 移植到 Win32 时,请用 _declspec(dllexport) 替换 _export 的每个实例。 作为参考,请在 Win32 Winbase.h 头文件中搜索。它包含 _declspec(dllimport) 的用法示例。 3. 使用 AFX_EXT_CLASS 导出和导入 扩展 DLL 使用 AFX_EXT_CLASS 宏导出类;链接到扩展 DLL 的可执行 文件使用该宏导入类。用于生成扩展 DLL 的相同头文件可通过 AFX_EXT_CLASS 宏与链接到 DLL 的可执行文件一起使用。 在 DLL 的头文件中,将 AFX_EXT_CLASS 关键字添加到类的声明中, 如下所示: class AFX_EXT_CLASS CMyClass : public CDocument / ; 当定义了预处理器符号 _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 / #undef AFX_DATA #define AFX_DATA 警告:导出内联函数时要小心,因为它们有可能导致版本冲突。内联函数 扩展到应用程序代码中;因此,如果以后重写内联函数,除非重新编译应用程 序本身,否则内联函数不会被更新。通常,不用重新生成使用 DLL 函数的应 用程序就可以更新 DLL 函数。 4. 导出类中的个别成员 有时,您可能希望导出类中的个别成员。例如,如果导出 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),并在生成客户端可执行文件时将 AFX_DATA 定义为 _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。 注意:如果导出整个类而非选定的类成员,静态数据成员将自动导出。 5. 使用 .DEF 文件的优缺点 在 .def 文件中导出函数使您得以控制导出序号。当将附加的导出函数添 加到 DLL 时,可以给它们分配更高的序号值(高于任何其他导出函数)。当 您进行此操作时,使用隐式链接的应用程序不必与包含新函数的新导入库重新 链接。这非常重要,例如,在设计将由许多应用程序使用的第三方 DLL 时。 可以通过添加附加功能不断地增强 DLL,同时确保现有应用程序继续正常使用 新的 DLL。MFC DLL 是使用 .def 文件生成的。 使用 .def 文件的另一个优点是:可以使用 NONAME 属性导出函数,该 属性仅将序号放到 DLL 的导出表中。对具有大量导出函数的 DLL,使用 NONAME 属性可以减小 DLL 文件的大小。有关编写模块定义语句的信息, 请参见模块定义语句的规则。有关序号导出的更多信息,请参见按序号而不是 按名称从 DLL 导出函数。 使用 .def 文件的主要缺点是:在 C+ 文件中导出函数时,必须将修饰 名放到 .def 文件中,或者通过使用外部 “C”用标准 C 链接定义导出函数, 以避免编译器进行名称修饰。 如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具 或 /MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器 特定的。如果将 Visual C+ 编译器产生的修饰名放到 .def 文件中,则链接 到 DLL 的应用程序必须也是

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论