欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

__declspec(dllexport)和def文件导出dll方法

程序员文章站 2022-06-24 22:30:26
...

一,__ declspec(dllexport):
将一个函数声名为导出函数,通常它和extern“C”合用,形式如下:

extern "C"
{
    __declspec(dllexport) void FUNCTION()
    {
    }
}

由于C ++存在函数重载,因此__declspec(dllexport)FUNCTION(int,int)会被装饰,例如被装饰成为function_int_int,而且不同的编译器decorate的方法不同,造成了在用GetProcAddress的的取得FUNCTION地址时的不便,使用外部的“C”时,上述的装饰不会发生,因为ç没有函数重载。

二,MSDN:
可以使用__declspec(dllexport)关键字从DLL导出数据,函数,类或类成员函数,若要导出函数,__ declspec(dllexport)关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:

__ declspec (dllexport)void __cdecl Function1(void);

若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:
class __declspec(dllexport)CExampleExport:public CObject 
{... class definition ...};

生成DLL时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将__declspec(dllexport)的添加到头文件中的声明。
若要提高代码的可读性,请为__declspec(DLLEXPORT )定义一个宏并对正在导出的每个符号使用该宏:
#define DllExport __declspec(dllexport)

三,__ declspec(dllexport)与.def
模块定义(.def)文件是包含一个或多个描述各种DLL属性的模块语句的文本文件
.2,添加__declspec(dllexport)是为了提供不使用.def文件从.EXE或.DLL导出函数的简单方法
.3,如果不使用__declspec(dllimport)或__declspec(dllexport)导出DLL函数,则DLL需要.def文件
.4,并不是任何时候选择添加__declspec(dllexport)而放弃.def的方式都是好的。如果DLL是提供给VC ++用户使用的,只需要把编译DLL时产生的.lib提供给用户,它可以很轻松地调用你的DLL。但是如果DLL是供VB,PB,Delphi用户使用的,那么会产生一个小麻烦。因为VC ++对于__declspec(dllexport)声明的函数会进行名称转换,如下面的函数:

__ declspec(dllexport)int __stdcall IsWinNT()  
     会转换为IsWinNT @ 0,这样你在VB中必须这样声明: 
     声明函数IsWinNT Lib“my.dll”别名“IsWinNT @ 0”()As Long  
     @的后面的数由于参数类型不同而可能不同。这显然不太方便。所以如果要想避免这种转换,就要使用.DEF文件方式。

在C ++中,我们可以通过  __declspec(DLLEXPORT)  将函数导出,例如:

    _declspec dllexport int add(int a,int b);

在这种方式下,如果调用该DLL的是一个C ++程序(同一个编译器的版本)是没有问题的。但是,如果调用该DLL是一个其它语言的程序(如C#,VB),则会出错。究其原因,是因为在C ++中存在函数的重载,允许函数重名,因此在编译器生成的DLL的时候,为了区别重名的程序,其会将进行一定算法进行名称转换。例如,对于前面的添加函数,实际的函数名称是如下形式。

    __declspec(dllexport)和def文件导出dll方法

因此,我们直接通过函数名add是无法找到该函数的,从而导致调用失败。为了解决这一问题,我们往往在函数前面再加一个extern “C”, 使用C方式的函数命名规则。

    extern “C” _declspec dllexport int add(int a,int b);

这样函数的名称就成加了。

    __declspec(dllexport)和def文件导出dll方法

这样,我们就需要在每一个函数签名加上extern ”C“ _declspec dllexport  这一长串声明。为了简化这一过程, MS引入了高清文件网求方便我们操作。

使用默认值文件比较简单,只需要在项目中添加一个DEF文件,然后把我们要导出的函数放在DEF文件中即可。

    __declspec(dllexport)和def文件导出dll方法

DEF文件的简单示例如下:

    LIBRARY
    EXPORTS
        添加

最后记得在链接器选项中选中使用的DEF文件(默认情况下,添加DEF文件时会自动加上该选项,无需手动更改)。

    __declspec(dllexport)和def文件导出dll方法

这样,我们的函数无需加那一堆前缀,仍然可以使用默认的INT 添加(诠释一个,INT B);形式,导出但后的方式然的英文Ç形式的函数定义。

    __declspec(dllexport)和def文件导出dll方法

最后指得一提的是,一般的C / C ++默认的调用方式是__cdecl,这种方式下需要调用方对函数清栈。如果对外提供API供其它非C ++程序使用时,调用方会无法清栈而出错(C#会直接报函数声明不匹配的错误)。因此,对外提供api时还应该将接口声明为__stdcall,让api函数自己清栈。这也是Windows API前面都加上了一个WINAPI的宏的原因

def文件还有许多其它的高级用法,要进一步了解的话,可以参看一下MS的官方文档:http//msdn.microsoft.com/zh-cn/library/28d6s79h( v = vs.80).aspx