dll导出函数的两种方式的比较
最初的网页链接已经挂了, 在此贴一个中间的转载链接
https://blog.csdn.net/zhazhiqiang/article/details/51577523
一 概要
vs中导出 dll的方法有两种: 一种是使用__declspec(dllexport), 另一种就是使用.def文件方式,
这两种方式的最主要区别是在导出函数的名字上, 其次还有一些操作的灵活性上以及功能的强弱
二 一个具体的例子
1 __declspec(dllexport) 方式
首先对C和C++编译(extern "C")与调用约定(__cdecl、__stdcall、__fastcall)进行组合测试:
<1> C++编译
__declspec(dllexport) int add(int, int);

__declspec(dllexport) int __cdecl add(int, int);

__declspec(dllexport) int __stdcall add(int, int);

__declspec(dllexport) int __fastcall add(int, int);

对于C++编译器的函数名修饰规则:不管__cdecl, __fastcall还是__stdcall调用方式,函数修饰名都是以"?"开始,后面是函数在名字,再后面是函数返回类型和参数类型按照代号拼出的参数表。对于__stdcall方式,参数表的开始标示是"@@YG”,对于__cdecl方式则是"@@YA”,对于__fastcall方式则是"@@YI”.
参数表后以"@Z”标示整个名字的结束,如果该函数无参数,则以"Z”标识结束。
<2> C编译
extern "C" __declspec(dllexport) int add(int, int);

extern "C" __declspec(dllexport) int __cdecl add(int, int);

extern "C" __declspec(dllexport) int __stdcall add(int, int);

extern "C" __declspec(dllexport) int __fastcall add(int, int);

<3> 备注
__declspec(dllexport)的位置:
To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified.
For example:
__declspec(dllexport) void __cdecl Function1(void);
To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:
class __declspec(dllexport) CExampleExport : public CObject
{ class definition };
2 def文件导出方式(项目中添加一个def后缀的文件, 然后在项目属性->连接器->所有选项->模块定义文件)
具体到测试实例,我们的def文件内容如下:
LIBRARY "win"
EXPORTS
add @1
其中LIBRARY指定dll的模块名称,即dll名字,EXPORTS后的每一行指定一个导出函数名字,这个名字和头文件中的声明一致,后面可以跟@序号指定该函数的序号(这个是可选的,后面按序号导入函数的时候再详细说)。
然后再测试一下__stdcall和__fastcall是否会对导出函数改名,测试结果如下,均未改名:
extern "C" int __stdcall add();

extern "C" int __fastcall add();

另外一种方案是在代码中给链接器指定导出函数名字:
extern "C" __declspec(dllexport) int __fastcall add(int a, int b);
#pragma comment(linker, "/export:add=@add@8")
这里告诉链接器,导出一个函数名为add的函数,函数入口点和@add@8相同

这样,我们既可以使用add,也可以使用@add@8了。
__stdcall方式和这类似,为add=_add@8。
【按序号而不是按名称从dll导出函数】
http://msdn.microsoft.com/zh-cn/library/e7tsx612%28VS.80%29.aspx
def文件定义如下:
LIBRARY "win"
EXPORTS
add @1 NONAME

函数名称和Hint都不见了。
这样也可以用来隐藏dll中一些重要函数。
隐藏了函数名称,在应用程序中使用序号来导入函数:
#include <windows.h>
#include <stdio.h>
int main()
{
typedef int (* AddFunc)(int, int);
HMODULE hModule = LoadLibrary("dll.dll");
AddFunc add = (AddFunc)GetProcAddress(hModule, MAKEINTRESOURCE(1)); //注意这里序号的指定方式
printf("%d\n", add(1, 2));
return 0;
}
三 总结:
1 __declspec(dllexport)
若要输出类的所有成员:数据or函数,__declspec(dllexport)要放在类名左边声明:
class __declspec(dllexport) Class1{}
如果类没有数据成员,__declspec(dllexport)放在class关键字前声明就会被编译器忽略,就没有lib生成,如下:
__declspec(dllexport) class Class1{}
使用 __declspec(dllexport) 非常方便,因为不必考虑维护 .def 文件和获取导出函数的修饰名。例如,如果您设计的 DLL 供自己控制的应用程序使用,则此方法很适用。如果通过新的导出函数重新生成 DLL,还必须重新生成应用程序,因为如果使用不同版本的编译器进行重新编译,则导出的 C++ 函数的修饰名可能会发生变化。
使用 .DEF 文件的优缺点(zz)
在 .def 文件中导出函数使您得以控制导出序号。当将附加的导出函数添加到 DLL 时,可以给它们分配更高的序号值(高于任何其他导出函数)。当您进行此操作时,使用隐式链接的应用程序不必与包含新函数的新导入库重新链接。这非常重要,例如,在设计将由许多应用程序使用的第三方DLL 时。可以通过添加附加功能不断地增强 DLL,同时确保现有应用程序继续正常使用新的 DLL。MFC DLL 是使用 .def 文件生成的。
DLL 的 .def 文件中的导出名相匹配。
dll导出函数的两种方式的比较的更多相关文章
- (转)DLL中导出函数的两种方式(dllexport与.def文件)
DLL中导出函数的两种方式(dllexport与.def文件)http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792 ...
- 【转】DLL中导出函数的两种方式(dllexport与.def文件)
DLL中导出函数的两种方式(dllexport与.def文件) DLL中导出函数的声明有两种方式: 一种方式是:在函数声明中加上__declspec(dllexport):另外一种方式是:采用模块定义 ...
- DLL中导出函数的两种方式(dllexport与.def文件)
DLL中导出函数的声明有两种方式: 一种方式是:在函数声明中加上__declspec(dllexport): 另外一种方式是:采用模块定义(.def)文件声明,(.def)文件为链接器提供了有关被链接 ...
- DLL声明导出函数的两种方式
DLL中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport):另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出.属 ...
- C++ DLL导出函数的两种方法(导出序号那种方法,别人看不到函数名)
第一种就直接导出函数名如下代码: #ifdef__cplusplus #define TEXPORT extern "c" _declspec(dllexport) #dlse # ...
- C#调用C++ DLL动态库的两种方式
第一种方式:C++导出函数, c#dllimport 的方式 在很多地方都看到过,如[dllimport "user32.dll"]这种代码,调用windows API,就是通过这 ...
- vue项目中导出PDF的两种方式
参考大家导出的方式,基本上是如下两种: 1.使用 html2Canvas + jsPDF 导出PDF, 这种方式什么都好,就是下载的pdf太模糊了.对要求好的pdf这种方式真是不行啊! 2.调用浏览器 ...
- JS定义函数的两种方式:函数声明和函数表达式
函数声明 关于函数声明的方式,它的一个重要的特性就是函数声明提升(function declaration hoisting),意思是在执行代码之前会先读取函数声明.这就意味着可以把函数声明放在调用它 ...
- JS调用函数的两种方式
<script type="text/javascript"> window.onload = init; //onload 表示页面全部加载完毕后,再调用init() ...
随机推荐
- Java中String类常用方法(字符串中的子字符串的个数)
重点内容 4种方法: 1.int indexOf(String str)返回第一次出现的指定子字符串在此字符串中的索引. 2.int indexOf(String str, int startInde ...
- HTML标记语言
一.html的文档结构 html含义为超文本标记语言,html文档重要由4个标签来组成就是<html> <head> <title> <body> ...
- slurm作业提交系统常用命令
写下自己的关于slurm感悟一二 与各人pc不同,slurm的基本架构是,一个中专节点,之后有很多局域网ip对应不同的计算节点,在中专节点敲命令,命令中可以指定需要用到哪些计算节点 1. 查看有哪些分 ...
- springBoot 自动配置原理--自己新建一个 starter
上篇我们说到 springboot 和 SSM 框架的区别,今天我们就看看 springboot 到底为我们做了哪些事情,让我们开发变得如此简单. springboot 中起着重要作用的是 start ...
- conts、var 、let的区别
1.const定义的变量不可以直接修改,通过 this.a = 'kkk' 进行修改, 而且必须初始化. 2.var定义的变量可以修改,如果不初始化会输出undefined 3.let是块级作用域,函 ...
- Springboot 部署到linux(二)
之前写了一篇部署的文章,但是打包时会运行所有的单元测试,如果不想测试的话,可以采用这种方式. 第一部分:打包 1.pom.xm添加配置 <plugin> <groupId>or ...
- jq ajax数据交互
get 与 post 的区别 了解和使用 get和post是HTTP与服务器交互的方式, 说到方式,其实总共有四种:put,delete,post,get. 他们的作用分别是对服务器资源的增,删,改, ...
- Python之字符串函数str()
str()方法使Python将非字符串值表示为字符串: age = 23 message = "Happy" + str(age) +"rd Birthday"
- socks5代理转http代理
Convert-Shadowsocks-into-an-HTTP-proxy apt-get install polipo service polipo stop polipo socksParent ...
- PTA1
1-1 数组定义中,数组名后是用方括号括起来的常量表达式,不能用圆括号. (1分) [T ] F 1-2 在C语言中能逐个地使用下标变量,也能一次引用整个数组. (1分) T [F]因为它有首地址 1 ...