C++中DLL函数的导出和导入

上传人:ji****72 文档编号:35909830 上传时间:2018-03-22 格式:DOC 页数:8 大小:54.50KB
返回 下载 相关 举报
C++中DLL函数的导出和导入_第1页
第1页 / 共8页
C++中DLL函数的导出和导入_第2页
第2页 / 共8页
C++中DLL函数的导出和导入_第3页
第3页 / 共8页
C++中DLL函数的导出和导入_第4页
第4页 / 共8页
C++中DLL函数的导出和导入_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《C++中DLL函数的导出和导入》由会员分享,可在线阅读,更多相关《C++中DLL函数的导出和导入(8页珍藏版)》请在金锄头文库上搜索。

1、1. 使用使用 DEF 文件从文件从 DLL 导出导出模块定义 (.def) 文件是包含一个或多个描述 DLL 各种属性的 Module 语句的文本文件。如果不使用 _declspec(dllexport) 关键字导出 DLL 的函数,则 DLL 需要 .def 文件。.def 文件必须至少包含下列模块定义语句:文件中的第一个语句必须是 LIBRARY 语句。此语句将 .def 文件标识为属于 DLL。LIBRARY 语句的后面是 DLL 的名称。链接器将此名称放到 DLL 的导入库中。EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。通过在函数名的后面加上 符和一个数

2、字,给函数分配序号值。当指定序号值时,序号值的范围必须是从 1 到 N,其中 N 是 DLL 导出函数的个数。如果希望按序号导出函数,请参见按序号而不是按名称从 DLL 导出函数以及本主题。例如,包含实现二进制搜索树的代码的 DLL 看上去可能像下面这样:LIBRARY BTREEEXPORTSInsert 1Delete 2Member 3Min 4如果使用 MFC DLL 向导创建 MFC DLL,则向导将为您创建主干 .def 文件并将其自动添加到项目中。添加要导出到此文件的函数名。对于非 MFC DLL,必须亲自创建 .def 文件并将其添加到项目中。如果导出 C+ 文件中的函数,必须

3、将修饰名放到 .def 文件中,或者通过使用外部“C”定义具有标准 C 链接的导出函数。如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具或 /MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将 Visual C+ 编译器产生的修饰名放到 .def 文件中,则链接到 DLL 的应用程序必须也是用相同版本的 Visual C+ 生成的,这样调用应用程序中的修饰名才能与 DLL 的 .def 文件中的导出名相匹配。如果生成扩展 DLL 并使用 .def 文件导出,则将下列代码放在包含导出类的头文件的开头和结尾:#undef AFX_DATA#

4、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 的可执

5、行文件在生成时链接到导入库。请注意,MFC 本身使用 .def 文件从 MFCx0.dll 导出函数和类。2. 使用使用 _declspec(dllexport) 从从 DLL 导出导出Microsoft 在 Visual C+ 的 16 位编译器版本中引入了 _export,使编译器得以自动生成导出名并将它们放到一个 .lib 文件中。然后,此 .lib 文件就可以像静态 .lib 那样用于与 DLL 链接。在更新的编译器版本中,可以使用 _declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。_declspec(dllexport) 会将导出指令添加到对

6、象文件中,因此您不需要使用 .def 文件。当试图导出 C+ 修饰函数名时,这种便利最明显。由于对名称修饰没有标准规范,因此导出函数的名称在不同的编译器版本中可能有所变化。如果使用 _declspec(dllexport),仅当解决任何命名约定更改时才必须重新编译 DLL 和依赖 .exe 文件。许多导出指令(如序号、NONAME 和 PRIVATE)只能在 .def 文件中创建,并且必须使用 .def 文件来指定这些属性。不过,在 .def 文件的基础上另外使用 _declspec(dllexport) 不会导致生成错误。若要导出函数,_declspec(dllexport) 关键字必须出现

7、在调用约定关键字的左边(如果指定了关键字)。例如:_declspec(dllexport) void _cdecl Function1(void);若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:class _declspec(dllexport) CExampleExport : public CObject . class definition . ;生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将 _declspec(dllexport) 添加到头文件中的声明中。若要提高代码的可读性,请为 _declspec(dllexport)

8、 定义一个宏并对正在导出的每个符号使用该宏:#define DllExport _declspec( dllexport ) _declspec(dllexport) 将函数名存储在 DLL 的导出表中。如果希望优化表的大小,请参见按序号而不是按名称从 DLL 导出函数。注意:将 DLL 源代码从 Win16 移植到 Win32 时,请用 _declspec(dllexport) 替换 _export 的每个实例。作为参考,请在 Win32 Winbase.h 头文件中搜索。它包含 _declspec(dllimport) 的用法示例。3. 使用使用 AFX_EXT_CLASS 导出和导入导出

9、和导入扩展 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 时,

10、该宏被定义为 _declspec(dllimport)。定义后,预处理器符号 _AFXDLL 指示共享 MFC 版本正在由目标可执行文件(DLL 或应用程序)使用。当 _AFXDLL 和 _AFXEXT 都定义了时,这指示目标可执行文件是扩展 DLL。由于从扩展 DLL 导出时,AFX_EXT_CLASS 被定义为 _declspec(dllexport),因此可以导出整个类,而不必将该类的所有符号的修饰名放到 .def 文件中。此方法由 MFC 示例 DLLHUSK 使用。虽然使用此方法可以避免创建 .def 文件和类的所有修饰名,但由于名称可以按序号导出,因此创建 .def 文件的效率更高

11、。若要使用 .def 文件导出方法,请将下列代码放在头文件的开头和结尾处:#undef AFX_DATA#define AFX_DATA AFX_EXT_DATA/ #undef AFX_DATA#define AFX_DATA警告:导出内联函数时要小心,因为它们有可能导致版本冲突。内联函数扩展到应用程序代码中;因此,如果以后重写内联函数,除非重新编译应用程序本身,否则内联函数不会被更新。通常,不用重新生成使用 DLL 函数的应用程序就可以更新 DLL 函数。4. 导出类中的个别成员导出类中的个别成员有时,您可能希望导出类中的个别成员。例如,如果导出 CDialog 派生类,可能只需要导出构造

12、函数和 DoModal 调用。可以对需要导出的个别成员使用 AFX_EXT_CLASS。例如:class CExampleDialog : public CDialogpublic:AFX_EXT_CLASS CExampleDialog();AFX_EXT_CLASS int DoModal();./ rest of class definition.;您不再导出类的所有成员,但由于 MFC 宏的工作方式,您可能会遇到其他问题。几个 MFC 的 Helper 宏实际声明或定义数据成员。因此,还必须从 DLL 导出这些数据成员。例如,当生成扩展 DLL 时,DECLARE_DYNAMIC 宏的

13、定义如下:#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 修饰符声明的,因此只需

14、在生成 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_CLASSclass CExampleView : public CViewDECLARE_DYNAMIC()/ . class definition .;#undef AFX_DATA

15、#define AFX_DATAMFC 总是在其宏的内部定义的数据项上使用 AFX_DATA 符号,因此此技术适用于所有这类情况。例如,它适用于 DECLARE_MESSAGE_MAP。注意:如果导出整个类而非选定的类成员,静态数据成员将自动导出。5. 使用使用 .DEF 文件的优缺点文件的优缺点在 .def 文件中导出函数使您得以控制导出序号。当将附加的导出函数添加到 DLL 时,可以给它们分配更高的序号值(高于任何其他导出函数)。当您进行此操作时,使用隐式链接的应用程序不必与包含新函数的新导入库重新链接。这非常重要,例如,在设计将由许多应用程序使用的第三方 DLL 时。可以通过添加附加功能

16、不断地增强 DLL,同时确保现有应用程序继续正常使用新的 DLL。MFC DLL 是使用 .def 文件生成的。使用 .def 文件的另一个优点是:可以使用 NONAME 属性导出函数,该属性仅将序号放到 DLL 的导出表中。对具有大量导出函数的 DLL,使用 NONAME 属性可以减小 DLL 文件的大小。有关编写模块定义语句的信息,请参见模块定义语句的规则。有关序号导出的更多信息,请参见按序号而不是按名称从 DLL 导出函数。使用 .def 文件的主要缺点是:在 C+ 文件中导出函数时,必须将修饰名放到 .def 文件中,或者通过使用外部“C”用标准 C 链接定义导出函数,以避免编译器进行名称修饰。如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具或 /MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将 Visual C+ 编译器产生的修饰名放到 .def 文件中,则链接到 DLL 的应用程序必须也是用相同版本

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号