参考自:http://bbs.csdn.net/topics/330169671

 

__declspec(dllexport):导出符号,也就是定义需要导出函数的dll中给导出函数的函数声明前面加上导出符号,表示该方法可以导出给其他DLL或者exe使用;

__declspec(dllimport)导入符号,也就是在使用该函数的DLL或者exe中需要在该函数的函数声明前面加上该符号,表示该函数方法是从其他库导入的。

 

我们编写一个DLL库一般都是用来给其他DLL或者exe程序调用的。当我们编写DLL库时,要想把该库中的函数导出来给其他DLL或者exe使用,

一般有两种方式:一是在声明该函数的声明函数前面加上导出符号__declspec(dllexport);二是在.def文件中写上导出函数。

因为导出函数的头文件一般既要给导出DLL使用,又要给调用该导出DLL函数的DLL或者EXE使用。而导出DLL库给其他DLL或者EXE程序使用的时候,函数是相当于导入该DLL或者EXE的,

所以其头文件的声明中的__declspec(dllexport)导出符号改成__declspec(dllimport)导入符号。

为了方便使用和维护同一分头文件,所以在导出函数的头文件中加上

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

这段代码。

我们在该导出DLL的编译选项定义中定义宏 #define _EXPORTING,而在调用该导出函数DLL的其他DLL或者exe的编译选项中不定义宏_EXPORTING。

那么导出头文件和导入头文件就可以只维持一份头文件了,有利于维护。

 

关于导入头文件中要把__declspec(dllexport)改成 __declspec(dllimport)问题

一、关于 __declspec(dllimport)我刚才找了一下,有人写过相关的文章,大意是说,不用这个也链接器也能工作,不过用它更好。原文是说:
不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。 

 

隐式使用dll时,不加__declspec(dllimport)完全可以,使用上没什么区别,只是在生成的二进制代码上稍微有点效率损失。

1、不加__declspec(dllimport)时,在使用dll中的函数时,编译器并不能区别这是个普通函数,还是从其它dll里导入的函数,所以其生成的代码如下:
call 地址1
地址1:
   jmp  实际函数地址

2、有__declspec(dllimport)时,编译器知道这是要从外部dll导入的函数,从而在生成的exe的输入表里留有该项,以便在运行exe,PE载入器加载exe时对输入地址表IAT进行填写,这样生成的代码如下:
call dword ptr[输入表里哪项对应的内存地址] (注意:现在就不需要jmp stub了)

 

二、导入全局、静态或者类成员变量需要__declspec(dllimport)。

#define DllImport   __declspec(dllimport) 

DllImport int  j;

__declspec(dllexport)是用于避免需要自己写DEF文件的。编译器会为被__declspec(dllexport)修饰的函数自动添加一个导出函数入口。如果你在其他模块中包含__declspec(dllexport)的头文件,这些项目的导出表中也会生成一个同名导出函数。

posted on 2016-05-11 23:14  言止予思  阅读(4278)  评论(0编辑  收藏  举报