有关本主题的最完整且最新的信息可在 dllexport、dllimport 中找到。
有关扩展的存储类修饰符的语法的特定信息,请参阅扩展的存储类特性。 --------- 定义和声明 (C) DLL 接口引用已知由系统中的某程序导出的所有项(函数和数据);即所有被声明为 dllimport 或 dllexport 的项。 DLL 接口中包含的所有声明都必须指定 dllimport 或 dllexport 特性。 但是,定义仅可指定 dllexport 特性。 例如,以下函数定义产生了一个编译器错误: #define DllImport __declspec( dllimport ) 以下代码也会产生错误: #define DllImport __declspec( dllimport ) DllImport int i = 10; /* Error; this is a definition. */ 但是,这是正确的语法: #define DllImport __declspec( dllimport ) DllExport int i = 10; /* Okay: this is an export definition. */ 使用 dllexport 意味着定义,而使用 dllimport 则意味着声明。 必须使用带 extern 的 dllexport 关键字来强制进行声明;否则,会进行隐式定义。 #define DllImport __declspec( dllimport ) extern DllImport int k; /* These are correct and imply */ ---------- 定义带有 dllexport 和 dllimport 的内联 C 函数 可以定义为将函数与 dllexport 特性内联。 在这种情况下,将始终实例化并导出该函数,无论程序中是否有模块引用该函数。 假定该函数由另一个程序导入。 还可以定义为内联使用 dllimport 特性声明的函数。 在这种情况下,函数可以展开(遵从 /Ob(内联)编译器选项规范),但决不实例化。 具体而言,如果采用内联导入函数的地址,则返回驻留在 DLL 中的函数地址。 此行为与采用非内联导入函数的地址相同。 内联函数中的静态本地数据和字符串在 DLL 和客户端之间保持的标识与它们在单一程序(即,没有 DLL 接口的可执行文件)中保持的一样。 在提供导入的内联函数时谨慎操作。 例如,如果更新 DLL,请不要假定该客户端将使用更改后的 DLL 版本。 若要确保加载 DLL 的适当版本,请重新生成 DLL 的客户端。 ----------- dllimport/dllexport 的规则和限制 如果你没有使用 dllimport 或 dllexport 特性声明函数,则此函数被视为不是 DLL 接口的一部分。 因此,函数的定义必须存在于该模块或同一程序的另一个模块中。 若要使函数成为 DLL 接口的一部分,您必须将其他模块中函数的定义声明为 dllexport。 否则,在构建客户端时,将生成链接器错误。 如果程序中的单个模块包含对同一函数的 dllimport 和 dllexport 声明,则 dllexport 特性优先于 dllimport 特性。 但是,会生成编译器警告。 例如: #define DllImport __declspec( dllimport ) DllExport void func1( void ); /* Warning; dllexport takes precedence. */ 无法利用使用 dllimport 特性声明的数据对象的地址来初始化静态数据指针。 例如,下面的代码将生成错误: #define DllImport __declspec( dllimport ) int *pi = &i; /* Error */ 如果利用使用 dllimport 声明的函数的地址来初始化静态函数指针,会将指针设置为 DLL 导入 thunk(将控制权转移给函数的代码存根)的地址,而不是函数的地址。 此赋值不生成错误消息: #define DllImport __declspec( dllimport ) static void ( *pf )( void ) = &func1; /* No Error */ 由于包含对象声明中的 dllexport 特性的程序必须为该对象提供定义,因此您可以利用 dllexport 函数的地址初始化全局或局部静态函数指针。 同样,您可以利用 dllexport 数据对象的地址初始化全局或局部静态数据指针。 例如: #define DllImport __declspec( dllimport ) DllExport int i; int *pi = &i; /* Okay */ static void ( *pf )( void ) = &func1; /* Okay */ |
|