使用def文件简化dll导出
2014-02-17 12:17
267 查看
在C++中,我们可以通过 __declspec(dllexport) 将函数导出为Dll中供其它程序使用,例如:
_declspec(dllexport)
int add(int a,
int b);
在这种方式下,如果调用该dll的是一个c++程序(同一个编译器的版本)是没有问题的。但是,如果调用该dll是一个其它语言的程序(如C#、VB),则会出错。究其原因,是因为在C++中存在函数的重载,允许函数重名,因此在编译器生成dll的时候,为了区别重名的程序,会将其进行一定算法进行名称转换。例如,对于前面的add函数,实际的函数名称是如下形式。
![](http://images.cnitblog.com/blog/12132/201305/04111909-75b38087d67f4d309a7c7a570a0ef22f.png)
因此,我们直接通过函数名add是无法找到该函数的,从而导致调用失败。为了解决这一问题,我们往往在函数前面再加一个extern
"C",使用C方式的函数命名规则。
extern
"C"
_declspec(dllexport)
int add(int a,
int b);
这样函数的名称就成add了。
![](http://images.cnitblog.com/blog/12132/201305/04111910-2dd2b1b3481e4216b66312353cb9db19.png)
这样,我们就需要在每一个函数签名加上"extern
"C"
_declspec(dllexport)"这一长串声明。如果需要导出的函数较多则显得非常繁琐,也非常难看。为了简化这一过程,MS引入了DEF文件方便我们操作。
使用Def文件比较简单,只需要在项目中添加一个def文件,然后把我们要导出的函数放在def文件中即可。
![](http://images.cnitblog.com/blog/12132/201305/04111910-81f15098e7c44a179107366a41b5c12d.png)
Def文件的简单示例如下:
LIBRARY
EXPORTS
add
最后记得在链接器选项中选中使用的def文件(默认情况下,添加def文件时会自动加上该选项,无需手动更改)。
![](http://images.cnitblog.com/blog/12132/201305/04111910-7c06f06a0897480cae55847b5e28cd0a.png)
这样,我们的函数无需加那一堆前缀,仍然可以使用默认的int add(int a,
int b);形式,但导出后的方式依然是C形式的函数定义。
![](http://images.cnitblog.com/blog/12132/201305/04111910-c86919058500408b9243d3fc12787edd.png)
最后指得一提的是,一般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。
_declspec(dllexport)
int add(int a,
int b);
在这种方式下,如果调用该dll的是一个c++程序(同一个编译器的版本)是没有问题的。但是,如果调用该dll是一个其它语言的程序(如C#、VB),则会出错。究其原因,是因为在C++中存在函数的重载,允许函数重名,因此在编译器生成dll的时候,为了区别重名的程序,会将其进行一定算法进行名称转换。例如,对于前面的add函数,实际的函数名称是如下形式。
![](http://images.cnitblog.com/blog/12132/201305/04111909-75b38087d67f4d309a7c7a570a0ef22f.png)
因此,我们直接通过函数名add是无法找到该函数的,从而导致调用失败。为了解决这一问题,我们往往在函数前面再加一个extern
"C",使用C方式的函数命名规则。
extern
"C"
_declspec(dllexport)
int add(int a,
int b);
这样函数的名称就成add了。
![](http://images.cnitblog.com/blog/12132/201305/04111910-2dd2b1b3481e4216b66312353cb9db19.png)
这样,我们就需要在每一个函数签名加上"extern
"C"
_declspec(dllexport)"这一长串声明。如果需要导出的函数较多则显得非常繁琐,也非常难看。为了简化这一过程,MS引入了DEF文件方便我们操作。
使用Def文件比较简单,只需要在项目中添加一个def文件,然后把我们要导出的函数放在def文件中即可。
![](http://images.cnitblog.com/blog/12132/201305/04111910-81f15098e7c44a179107366a41b5c12d.png)
Def文件的简单示例如下:
LIBRARY
EXPORTS
add
最后记得在链接器选项中选中使用的def文件(默认情况下,添加def文件时会自动加上该选项,无需手动更改)。
![](http://images.cnitblog.com/blog/12132/201305/04111910-7c06f06a0897480cae55847b5e28cd0a.png)
这样,我们的函数无需加那一堆前缀,仍然可以使用默认的int add(int a,
int b);形式,但导出后的方式依然是C形式的函数定义。
![](http://images.cnitblog.com/blog/12132/201305/04111910-c86919058500408b9243d3fc12787edd.png)
最后指得一提的是,一般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。
相关文章推荐
- 使用def文件简化dll导出
- 使用def文件简化dll导出
- 使用def文件简化dll导出
- 使用def文件简化dll导出
- 使用def文件简化dll导出
- 使用 DEF (模块定义) 文件从 DLL 导出函数和类
- 使用Def文件导出Dll文件
- 使用def文件从dll导出和_declspec(dllexport)导出区别以及调用示例
- [DLL]使用def文件从dll导出
- 使用def文件从dll导出和_declspec(dllexport)导出区别以及调用示例
- 动态库dll使用module.def文件导出函数(像静态库一样使用)
- 使用 DEF 文件导出 DLL
- 使用Def文件导出dll
- 使用 DEF 文件导出 DLL
- 创建用于非Visual C++工具的DLL——VB调用C++ DLL为何必须使用def文件
- 用.DEF文件导出DLL中的函数
- def文件格式(DLL导出)
- dll的def文件与__declspec(dllexport)导出函数方式比较
- 用DEF文件从DLL中导出C++类
- VS20XX使用DEF文件来生成DLL与Lib