一般来说,从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. web开发学习之旅---html第二天

    一.转义符 一些字符在html中拥有特殊的含义,比如小于号(<)用于定义 HTML 标签的开始.如果我们希望浏览器正确地显示这些字符,我们必须在 HTML 源码中插入转义符. 分类 二.html ...

  2. 深入理解C#中this/partial/null的使用

    一.this关键字作用 1.this表示当前运行中的对象 Eg: public class Person { public int age; public string name; public Pe ...

  3. 20160421javaweb之上传下载小案例---网盘

    一.建立数据库: CREATE TABLE IF NOT EXISTS `netdisk` ( `id` ) NOT NULL AUTO_INCREMENT, `uuidname` ) NOT NUL ...

  4. .NET Entity Framework入门简介及简单操作

    Entity Framework是微软借鉴ORM思想开发自己的一个ORM框架. ORM就是将数据库表与实体对象(相当于三层中的Model类)相互映射的一种思想. 最大的优点就是非常方便的跨数据库平台. ...

  5. ios-异步消息同步问题-典型使用场景: 微信私信界面

    前言 在ios开发中常常会有聊天功能,一般简单聊天功能只传输文字,但是稍微复杂点儿会有图片发送功能了.最全而且可支持扩展的例如微信,qq 聊天功能了.传输方式各有千秋,如get,post,websoc ...

  6. jQuery 源码分析2: jQuery.fn.init

    //jQuery.fn.intit 中使用到的外部变量: // 判断是否为HTML标签或#id rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w ...

  7. switch case实现两个数的算术运算

    方法一: package com.liaojianya.chapter1; import java.util.Scanner; public class SwitchDemo1 { public st ...

  8. java IO文件读写例子(OutputStream,InputStream,Writer,Reader)

    一,File创建文件 File file = new File("D:" + File.separator + "yi.txt"); 代码示例: package ...

  9. 02_天气查询_socket方式模拟_单线程

    [远程请求的B/S模式(客户端/服务器)] TCP: 是一种传输层协议,一种面向连接的协议.经过三次握手客户端和服务器端连接一个连接(通道).提供可靠的数据传输,该协议一般服务质量要求比较高的情况,T ...

  10. 给定任意一个字符串,使用 for in 语句来统计字符出现的个数

    //找出字符串中的数字 var str = 'haj123sdk54hask33dkhalsd879'; /*function findNum(str){ var arr = []; var tmp ...