DLL 的 export 是指将 DLL 中的函数和数据输出到其它程式中,以供其使用。 DLL 的 import 是指使用 DLL 的程式引入 DLL 中的函数和数据。

 


DLL export


 


DLL 中包含有一个表,称为 export table (以下简称 ET ),其中包含了 DLL 中可以被外部程式使用的所有函数和数据的名字。只有记录在 ET 中的函数和数据才可以被外部程式所使用(如果没有 .DEF 文件的话),其它所有没有记录在 ET 中的函数和数据都被视为是 DLL 私有的。因此,要将 DLL 中的函数和数据 export 只有两个方法:


 


l          为 DLL 创建一个 .DEF 文件(模块定义文件),并在 build 该 DLL 时使用这个 .DEF 文件。使用这种方法使你可以将函数按序号 export 。


 


l          在 DLL 中想要 export 的函数和数据定义前添加 _declspec ( dllexport )关键字(对于函数和变量定义,加在最前面;对于 class 定义,加在 class 关键字后),这样该函数和数据就会被添加到 ET 中。使用这种方法函数将按名字 export 。


 


在 WINDOWS 下,无论使用上述的哪一种方法,都必须要将 export 函数声明为 _stdcall 。


 


关于 C C++ 的兼容问题


 


如果要写 C 和 C++ 兼容的 DLL ,因为在 C 和 C++ 下使用了不同的名字修饰规则以及不同的调用约定,所以,如果 DLL 是用 C 编写和编译的,则在用于 C++ 模块时,函数的声明前应加上 extern “C” 关键字,以告诉 LINKER 使用 C 外部连接(即按照 C 名字修饰规则在外部模块中寻找函数);反之,如果 DLL 是用 C++ 编写和编译的,则在用于 C 模块时,函数的声明前要加上 extern “C++” 关键字。 VC++ 通过 _cplusplus 宏来标识 C++ 程式。如果是 C++ 程式, VC 编译器就会为你定义 _cplusplus 宏。所以在 DLL 中可以使用如下的技术来解决兼容问题:


 

#ifdef _cplusplus
 

  

 
extern “C” {
 

  

 
#endif
 

  

 
// 
 将所有的函数声明放在这里
 

  

 
#ifdef _cplusplus
 

  

 
}
 

  

 
#endif

 


.DEF 文件

 


         .DEF 文件是包含了 DLL 模块信息的文本文件。其语法结构如下:


 

LIBRARY         DLL file name
 

  

 
         DESCRIPTION         “descriptions”
 

  

 
         EXPORTS
 

  

 
                  Function names        @nums


         LIBRARY 为关键字,后面紧跟关联的 DLL 文件名; DESCRIPTION 后为可选的描述字符串,除了增加可读性外没什么用处; EXPORTS 后是 export 函数的列表,首先是函数名,然后是 @ 符号,后紧跟一十进制数,为该函数的标号,范围从 1 到 DLL 可 export 函数的总数。注意,这里的名字是经过名字修饰后的函数名字,如果是 DLL 是用 C++ 写的话,那么就很郁闷了。


 


         如果是扩展 DLL ( extension DLL ),并且通过 .DEF 文件 export ,那么必须在头文件中添加如下的语句:


            #undef AFX_DATA


#define AFX_DATA AFX_EXT_DATA
// 头文件中的其它内容
#undef AFX_DATA
#define AFX_DATA


 


这些语句确保一些 MFC 中内部使用的变量被 export 到外部程式中。例如:在 class 中通过 DECLARE_DYNAMIC 获得的 CRuntimeClass 变量。否则 DLL 将会无法正确地编译和连接,或外部程式无法正确连接到该 DLL 。


 


DLL import


 


         外部程式的一个源文件要使用 DLL 中的函数和数据,就像要使用外部模块中的函数和数据一样,必须首先给出函数和数据的声明;对于 class 则要给出类的定义。这就称为 import 。对于 VC 编译器, Import DLL 的函数和数据的语法与一般的声明类似,但要在前面加上 _declspec ( dllimport )关键字(对于函数和变量声明,加在最前面;对于 class 定义,加在 class 关键字后)。如果是函数,则该关键字是可选的,但使用该关键字有可能会导致编译器产生较高效的代码。但对于变量和 class ,则必须使用该关键字。


 


         通过使用以下的技术,可以编写在 .LIB 文件和外部程序源文件通用的头文件:


#ifdef _EXPORTING
#define CLASS_DECLSPEC    __declspec(dllexport)
#else
#define CLASS_DECLSPEC    __declspec(dllimport)
#endif


 


编译器提供的 _EXPORTING 宏可以用于标式该源文件来自 DLL 文件还是外部程式。