一般来说,从DLL导出函数有两种方法。一种是使用.def文件;另一种是使用__declspec(dllexport)。

使用上面两种方法各有优缺点。使用.def文件就是需要额外维护,当导出函数更改名字或者追加导出函数。而使用__declspec(dllexport)则需要注意使用的调用约定,在使用C++编译器时。

调用约定

在使用C++或者在常见的windows API的声明头文件常见的WINAPI,而WINAPA就是__stdcall。在C++还有__cdecl。而__pascal和__thiscall都已忽略了。宏PASCAL也用的是__stdcall。

一般来说,调用约定只关乎参数的压栈和最后的清理工作。还有就是名字修饰。比如:

void func(char, short, int, double)

使用__cdecl调用:

使用C编译器编译后的修饰名字为:_func。清理栈的工作由调用方做。

使用__stdcall和__thiscall调用:

使用C编译器编译后的修饰名字为_func@20。清理栈的工作由被调方做。

使用__fastcall调用:

使用C编译器编译后的修饰名字为@func@20。清理栈的工作由被调方做。

名字修饰

从上面的图也可看见,压栈都是从右到左,而名字修饰的方法却不一样。C编译器的修饰方法相对来说比较简单。以_func@20为例,_是追加的,func就是函数的名字,@是追加的,20为参数的字节数。C++的修饰方法相对来说比较复杂。下图是使用C++编译器产生的名字,使用__declspec(dllexport)和__stdcall。

下图是使用__cdecl编译:

大致一看都差不多,只是在名字后的有个字母不一样,__stdcall得是YG,而__cdecl的是YA。而这也正好指明了C++的名字修饰的规则,简单来说就是:

・名字(可以包含命名空间)

・调用约定

・返回值

・参数列表

调用约定修饰规则:

代号 调用约定
@@YG __stdcall
@@YA __cdecl
@@YI __fastcall

类型修饰规则:

代号 含义
X void
D char
E unsigned char
F short
H int
I unsigned int
J long
K unsigned long(DWORD)
M float
N double
_N bool
U struct
PA pointer
PB const pointer

参数表后以”@Z”标示整个名字的结束,如果该函数无参数,则以”Z”标识结束。

最后一点:如果我们直接使用__declspec(dllexport)导出函数的话,最好使用C编译器。如果直接用C++编译器,导出的函数名就像上面一样。在动态使用DLL时调用GetProcAddress使用原始函数名称一般来说会失败。例如:

GetProcAddress(handle, "func");

所以一般使用C编译器,比如这样:

#ifdef __cplusplus    // If used by C++ code
extern "C" { // we need to export the C interface
#endif __declspec(dllexport) VOID __cdecl func(char, short, int, double)
{
...
} #ifdef __cplusplus
}
#endif

这时,修饰后的名字就是这样:

一般导入函数时也建议这样:

#ifdef __cplusplus
extern "C" {
#endif // _declspec(dllimport) VOID func(char, short, int, double);
// or
VOID func(char, short, int, double); #ifdef __cplusplus
}
#endif

第一种写法在效率上来说会更好点。

参考:http://hi.baidu.com/luosiyong/item/c8664533f56b66c31b9696e3

http://msdn.microsoft.com/en-us/library/k2b2ssfy.aspx

DLL导出与调用约定的更多相关文章

  1. C/C++:函数的编译方式与调用约定以及extern “C”的使用

    转自:https://www.cnblogs.com/qinfengxiaoyue/archive/2013/02/04/2891908.html 函数在C++编译方式与C编译方式下的主要不同在于:由 ...

  2. DLL中调用约定和名称修饰(一)

    DLL中调用约定和名称修饰(一) 调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议.这种协议规定了该语言的函数中的参数传送方式.参数是否可变和由谁来 ...

  3. 【原创+整理】简述何为调用约定,函数导出名以及extern C

    何为调用约定 调用约定指的是函数在调用时会按照不同规则,翻译成不同的汇编代码.这和参数的压栈顺序和栈的清理方式相关,也就是说不同的调用约定,这些方式会做相应改变.一般编译器是以默认的调用约定编译一份代 ...

  4. C/C++/动态链接库DLL中函数的调用约定与名称修饰

    参见:http://blog.twofei.com/cc/impl/calling-convension.html 调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用 ...

  5. DLL导出函数和类的定义区别 __declspec(dllexport)

    DLL导出函数和类的定义区别 __declspec(dllexport) 是有区别的, 请看 : //定义头文件的使用方,是导出还是导入 #if defined(_DLL_API) #ifndef D ...

  6. C++调用约定和名字约定

    C++调用约定和名字约定 转自http://www.cppblog.com/mzty/archive/2007/04/20/22349.html 调用约定:__cdecl __fastcall与 __ ...

  7. dll 导出函数名的那些事

    dll 导出函数名的那些事 关键字: VC++  DLL  导出函数 经常使用VC6的Dependency或者是Depends工具查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导 ...

  8. c++builder调用VC的dll以及VC调用c++builder的dll

    解析__cdecl,__fastcall, __stdcall 的不同:在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式. 比如说__cdecl,它是标准的c方法的堆栈调用方式,就 ...

  9. dll的概念 dll导出变量 函数 类

    1. DLL的概念 DLL(Dynamic Linkable Library),动态链接库,可以向程序提供一些函数.变量或类.这些可以直接拿来使用. 静态链接库与动态链接库的区别:   (1)静态链接 ...

随机推荐

  1. mysql的having语句

    mysql> use qq; Database changed mysql> #查询本店价比市场价省的钱,并且要求省钱200元以上的取出来 mysql> select goods_i ...

  2. 使用ICSharpZipLib将文件夹压缩为zip文件

    序言:     在我接触Git和SVN之前,我最常用的保存数据的办法就是把文件夹压缩成一个zip文件,添加上时间戳.下面是我在学习C#的文件操作之后做的一个练习,使用开源的ICSharpZipLib来 ...

  3. Android获取屏幕尺寸大小

    官方API: A structure describing general information about a display, such as its size, density, and fo ...

  4. OC - 7.Foundation框架的简单介绍

    OC语言-07-OC语言-Foundation框架   结构体 NSRange/CGRange 用来表示一个元素在另一个元素中的范围,NSRange等价于CGRange 包含两个属性: NSUInte ...

  5. iOS 制作发布证书,发布到App Store

    ---恢复内容开始--- 1.登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 2.在 iOS Provisioning Portal中,点击App IDs ...

  6. iOS-开发记录-UIView属性

    UIView属性 1.alpha 设置视图的透明度.默认为1. // 完全透明 view.alpha = ; // 不透明 view.alpha = ; 2.clipsToBounds // 默认是N ...

  7. Less 官方文档学习笔记

    LESS 是css的一种扩展,它的编辑器是基于node.js 的less.js,将less文件编译成css文件(可压缩). 其中的概念: 变量:定义变量来代替某个值,只能编译一次,本质是“常量”.例如 ...

  8. C# Unix时间戳转换为时间

    在做一些接口的时候,比如返回数据中有一个时间的属性,它的值是使用Unix时间戳表示的,当我们处理它(保存到本地或者格式化前台展示)时需要转换成日期时间,在此就需要根据时间戳转换为日期时间 (注:Uni ...

  9. Launch a Batch File With Windows Installer

    Quote from: http://flexerasoftware.force.com/articles/en_US/HOWTO/Q111515 Synopsis This article desc ...

  10. wap开发之滑动事件(swipe、tap、swipeleft、swiperight)等

    最近一直找在wap端可以实现的swipe等滑动事件的方法,开始研究了jquery-mobile,zepto,结果由于jqm太大.zepto有不少缺陷.为此研究了zepto,想把里面的swipe事件独立 ...