信息: 在代码中使用 _declspec(dllimport) 和 _declspec(dllexport)

文章翻译 文章翻译
文章编号: 132044 - 查看本文应用于的产品
展开全部 | 关闭全部

本文内容

概要

这篇文章补充了下面 Microsoft 知识库中相应的文章中介绍的信息:
107501信息: __export 按 __declspec Visual c + + 32-位中替换
本文讨论的优点和您的应用程序中使用 _declspec(dllimport) 和 _declspec(dllexport) 的机制。

更多信息

32 位版本的 Visual c + + 使用 _declspec(dllimport) 和 $ _declspec(dllexport) 来替换以前的 Visual c + + 的 16 位版本中使用该 __export 关键字。

您不需要使用您的代码的 _declspec(dllimport) 正确,编译,但这样做所以允许编译器以生成更好的代码。编译器将能够生成更好的代码,因为它肯定知道或不函数是否存在在 DLL 中,因此编译器可以生成跳过正常的间接寻址级别的代码会跨 DLL 边界的函数调用中出现。

使用正确的.def 文件导出部分,_declspec(dllexport) 不是必需的。_declspec(dllexport) 已添加到提供了一种从.exe 或.dll 导出函数,而无需使用.def 文件的简便方法。

本文的其余部分提供了相当低级别、 全面讨论这些问题。

Win32 可移植可执行文件格式旨在最大限度地减少必须能接触到修复的导入的页面数。若要执行此操作它将任何程序的所有导入地址放在一个称为导入地址表的位置。这就允许访问这些导入时修改只能有一个或两个页加载程序。

使用函数调用 _declspec(dllimport)

在下面的代码示例假定 func1 驻留在独立于.exe 文件包含 main () 函数的 DLL 中的函数。

_declspec(dllimport),不给出此代码:
void main(void) {
    func1();
}
				
编译器生成类似下面的代码:
call func1
				
和链接器将为该调用到类似于下面这样:
call 0x4000000         ; The address of 'func1'.
				
func1 存在另一个 DLL 中,如果链接器无法解析此直接因为它无法知道什么 func1 的地址。在 16 位环境中链接器将此代码地址添加到该加载程序在运行时用正确的地址修补该.exe 中的列表。在 32 位环境中链接器生成的它不会知道该地址的 thunk。在 thunk 如下所示:
   0x40000000:    jmp DWORD PTR __imp_func1
				
__imp_func1 此处是 func1 的插槽中导入地址表.exe 文件的地址。链接器因此已知的所有地址。若要更新在加载时,一切就会正常工作的.exe 文件的导入地址表仅有加载程序。

因此,使用 _declspec(dllimport) 是更好的因为它是更好的如果链接器不生成一个 thunk,如果没有到。thunk 使代码更大 (RISC 系统上可以是几个说明) 并可能降低您的高速缓存的性能。如果您通知编译器函数是 DLL 中,它可以为您生成间接调用。

因此,现在此代码:
__declspec(dllimport) void func1(void);

void main(void) {
    func1();
}
				
生成此指令:
call DWORD PTR __imp_func1
				
没有没有 thunk 和没有的 jmp 指令使代码更小、 更快。

另一方面,对于 DLL 内部的函数调用,您不希望不必使用间接调用。您已经知道函数的地址。时间和空间所需加载和存储前一个间接调用函数的地址,因此直接调用总是更快、 更小。您只想从外部调用的 DLL 函数时,请使用 __declspec(dllimport) DLL 本身。不要在一个 DLL 内部的函数上使用 __declspec(dllimport),生成该 DLL 时。

使用 _declspec(dllexport)

Microsoft 推出了 __export 16 位编译器版本允许编译器自动生成导出名称,并将它们放在.lib 文件中。此.lib 文件可被用像静态.lib DLL 与链接。

Microsoft 添加 __declspec(dllexport) 继续这种便利。其目的是将导出指令添加到对象文件,因此您不需要.def 文件。

当试图导出修饰 c + + 函数名时,这种便利是最明显。对名称修饰没有标准规范因此导出函数的名称可能会更改不同的编译器版本。如果您使用 _declspec(dllexport),重新编译 DLL 和依赖的.exe 文件只有在才需要帐户的任何命名约定更改。

例如,仅在一个.def 文件中进行序号、 NONAME,或专用,并没有方法来指定这些属性没有.def 文件的情况下,许多导出指令。但是,使用 _declspec(dllexport) 除了使用.def 文件并不会导致生成错误。

作为一个引用搜索 Win32 WINBASE.H 头文件。它包含首选 __declspec(dllexport) 和 __declspec(dllimport) 用法示例。

在数据中使用 _declspec(dllexport) 和 _declspec(dllimport)

在数据的情况下使用 _declspec(dllimport) 是间接的移除层的一个方便的时候项。当您从 DLL 导入数据时,您仍必须通过导入地址表。_declspec(dllimport) 之前在 Win32 天内这意味着您不得不请记住在从 DLL 导出访问数据时执行一个额外的间接寻址级别:
// project.h
#ifdef _DLL     // If accessing the data from inside the DLL
   ULONG ulDataInDll;

else            // If accessing the data from outside the DLL
   ULONG *ulDataInDll;
#endif
				
然后,您会将数据导出在.def 文件中:
// project.def
LIBRARY project
EXPORTS
    ulDataInDll   CONSTANT
				
和 DLL 的外部进行访问:
if (*ulDataInDll == 0L) {
   // Do stuff here
}
				
时您将数据作为 __declspec(dllimport),编译器自动生成间接寻址代码为您。您再也不必担心上述步骤。如所述,以前并不使用 _declspec(dllimport) 声明对数据生成 DLL 时。若要访问该数据对象在 DLL 中的函数将不会使用导入地址表。因此,您不需要额外的存在的间接寻址级别。

若要将数据从 DLL 中会自动导出使用此声明:
__declspec(dllexport) ULONG ulDataInDLL;
				

使用.def 文件

如果您选择使用 __declspec(dllimport) 和.def 文件,您应更改.def 文件使用 CONSTANT 的位置的数据以减少不正确的编码将导致问题的可能性:
// project.def
LIBRARY project
EXPORTS
    ulDataInDll   DATA
				
以下图表显示了为什么:
Keyword     Emits in the import lib     Exports
CONSTANT    __imp_ulDataInDll           ulDataInDll
            __ulDataInDll

DATA        __imp_ulDataInDll           ulDataInDll
				
使用 _declspec (dllimport) 和 CONSTANT 列出 __imp_ 版本和未修饰的名创建以允许在显式链接下.lib DLL 导入库中。使用 _declspec(dllimport) 和数据列表只是 __imp_ 版本的名称。

如果您使用 CONSTANT,下面的代码构造之一可能被用来访问该 ulDataInDll:
__declspec(dllimport) ULONG ulDataInDll; /*prototype*/ 
   if (ulDataInDll == 0L)   /*sample code fragment*/ 
				
-或者-
ULONG *ulDataInDll;      /*prototype*/ 
if (*ulDataInDll == 0L)  /*sample code fragment*/ 
				
但是,如果您使用.def 文件中的数据,使用下面的定义编译的代码可以访问变量 ulDataInDll:
__declspec(dllimport) ULONG ulDataInDll;
if (ulDataInDll == 0L)   /*sample code fragment*/ 
				
持续使用是更危险,因为如果您忘记使用额外的间接寻址级别,您可能会访问该变量--不在变量自身的导入地址表的指针。由于导入地址表当前由只读由 Microsoft 编译器和连接器,这种类型的问题可以经常清单作为访问冲突。

如果它发现 CONSTANT.def 文件中的这种情况下,当前的 Visual c + + 链接器将发出警告。使用 CONSTANT 唯一的真正原因是如果您不能重新编译头文件没有在其中列出 dllimport 原型上的某些对象文件。

参考

在 Visual c + + 联机丛书提供大量的文档上 dllexport 和 dllimport 存储类属性。这包括编程技术参考的"创建 dll 的 Win32"一章中的"的 dllexport 和 dllimport 属性"和"使用 dllimport 和 c + + 中的 dllexport"主题中的 c + + 语言参考中,"特定于 Microsoft 的修饰符"一章和"导出符号"主题。 有关完整列表相关的主题搜索联机丛书"dllimport"或"dllexport"。

有关详细的信息,请参阅下面 Microsoft 知识库中相应的文章:
90530如何从 DLL 或应用程序中导出数据
107501信息: __export 按 __declspec Visual c + + 32-位中替换

属性

文章编号: 132044 - 最后修改: 2003年12月2日 - 修订: 2.0
这篇文章中的信息适用于:
  • Microsoft Visual C++ 1.0 专业版
  • Microsoft Visual C++ 2.0 Professional Edition
  • Microsoft Visual C++ 2.1
  • Microsoft Visual C++ 4.0 标准版
  • Microsoft Visual C++ 5.0 企业版
  • Microsoft Visual C++ 5.0 专业版
关键字:?
kbmt kbcode kbcompiler kbinfo KB132044 KbMtzh
机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 132044
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。
不再更新的 KB 内容免责声明
本文介绍那些 Microsoft 不再提供支持的产品。因此本文按“原样”提供,并且不再更新。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com