Dll 导出函数那些破事
经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。
VC++支持两种语言:即C/C++,这也是造成DLL导出函数差异的根源
我们用VS2008新建个DLL工程,工程名为“TestDLL”
把默认的源文件后缀 .CPP改为.C(C文件)
输入测试代码如下:
01 int _stdcall MyFunction(int iVariant)
02 {
03 return 0;
04 }
为了导出上面这个函数,我们有以下几个方法:
1. 使用传统的模块定义文件 (.def)
新建一个 后缀为.def的文本文件(这里建一个TestDll.Def),文件内容为:
LIBRARY TestDll
EXPORTS
MyFunction
在 Link 时指定输入依赖文件:/DEF:"TestDll.Def"
2. Visual C++ 提供的方便方法
在01行的int 前加入 __declspec(dllexport) 关键字
通过以上两种方法,我们就可以导出MyFunction函数。
我们用Dependency查看导出的函数:
第一种方法导出的函数为:
MyFunction
![]()
第二种方法导出的函数为:
_MyFunction@4
![]()
__stdcall会使导出函数名字前面加一个下划线,后面加一个@再加上参数的字节数,比如_MyFunction@4的参数(int iVariant)就是4个字节 __fastcall与 __stdcall类似,不过前面没有下划线,而是一个@,比如@MyFunction@4 __cdecl则是始函数名。
小结:如果要导出C文件中的函数,并且不让编译器改动函数名,用def文件导出函数。
下面我们来看一下C++文件
我们用VS2008新建个DLL工程,工程名为“TestDLL”
默认的源文件后缀为 .CPP (即C++文件)。
输入测试代码如下:
01 int _stdcall MyFunction(int iVariant)
02 {
03 return 0;
04 }
为了导出上面这个函数,我们有以下几个方法:
3. 使用传统的模块定义文件 (.def)
新建一个 后缀为.def的文本文件(这里建一个TestDll.Def),文件内容为:
LIBRARY TestDll
EXPORTS
MyFunction
在 Link 时指定输入依赖文件:/DEF:"TestDll.Def"
4. Visual C++ 提供的方便方法
在01行的int 前加入 __declspec(dllexport) 关键字
通过以上两种方法,我们就可以导出MyFunction函数。
我们用Dependency查看导出的函数:
第一种方法导出的函数为:
MyFunction
第二种方法导出的函数为:
?MyFunction@@YGHH@Z
可以看到 第二种方法得到的 导出函数名 并不是我们想要的,如果在exe中用显示方法(LoadLibrary、GetProcAddress)调用 MyFunction 肯定会失败。
但是用引入库(*.LIB)的方式调用,则编译器自动处理转换函数名,所以总是没有问题。
解决这个问题的方法是:
用VC 提供的预处理指示符 “#pragma” 来指定链接选项。
如下:
#pragma comment(linker, "/EXPORT:MyFunction=?MyFunction@@YGHH@Z")
这时,就会发现导出的函数名字表中已经有了我们想要的MyFunction。但我们发现原来的那个 ?MyFunction@@YGHH@Z 函数还在,这时就可以把 __declspec() 修饰去掉,只需要 pragma 指令即可。
而且还可以使如下形式:
#pragma comment(linker, "/EXPORT:MyFunction=_MyFunction@4,PRIVATE")
PRIVATE 的作用与其在 def 文件中的作用一样。更多的#pragram请查看MSDN。
小结:如果要导出C++文件中的函数,并且不让编译器改动函数名,用def文件导出函数。
同时可以用#pragma指令(C 中也可以用)。
总结:
C++编译器在生成DLL时,会对导出的函数进行名字改编,并且不同的编译器使用的改编规则不一样,因此改编后的名字也是不同的(一般涉及到C++ 中的重载等)。
如果利用不同编译器分别生成DLL和访问DLL的exe程序,后者在访问该DLL的导出函数时就会出现问题。如上例中函数MyFunction在C++编译器改编后的名字是?MyFunction@@YGHH@Z。我们希望编译后的名字不发生改变,这里有几种方法。
第一种方法是通过一个称为模块定义文件DEF来解决。
LIBRARY TestDll
EXPORTS
MyFunction
LIBRARY 用来指定动态链接库内部名称。该名称与生成的动态链接库名一定要匹配,这句代码不是必须的。
EXPORTS说明了DLL将要导出的函数,以及为这些导出函数指定的符号名。
第二种是定义导出函数时加上限定符:extern "C"
如:#define DLLEXPORT_API extern "C" _declspec(dllexport)
但extern "C"只解决了C和C++语方之间调用的问题(extern “C” 是告诉编译器,让它按C的方式编译),它只能用于导出全局函数这种情况 而不能导出一个类的成员函数。
同时如果导出函数的调用约定发生改变,即使使用extern "C",编译后的函数名还是会发生改变。例如上面我们加入_stdcall关键字说明调用约定(标准调用约定,也就是WINAPI调用约定)。 #define DLLEXPORT_API extern "C" _declspec(dllexport) 01 DLLEXPORT_API int _stdcall MyFunction(int iVariant)
02 {
03 return 0;
04 } 编译后函数名MyFunction改编成了_MyFunction@4
通过第一种方法模块定义文件的方式DLL编译后导出函数名不会发生改变。
![]()
Dll 导出函数那些破事的更多相关文章
- dll 导出函数名的那些事
dll 导出函数名的那些事 关键字: VC++ DLL 导出函数 经常使用VC6的Dependency或者是Depends工具查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导 ...
- DLL导出函数和类的定义区别 __declspec(dllexport)
DLL导出函数和类的定义区别 __declspec(dllexport) 是有区别的, 请看 : //定义头文件的使用方,是导出还是导入 #if defined(_DLL_API) #ifndef D ...
- AFX_MANAGE_STATE(AfxGetStaticModuleState())DLL导出函数包含MFC资源
AFX_MANAGE_STATE(AfxGetStaticModuleState()) 先看一个例子: .创建一个动态链接到MFC DLL的规则DLL,其内部包含一个对话框资源.指定该对话框ID如下: ...
- C# 遍历DLL导出函数
C#如何去遍历一个由C++或E语言编写的本地DLL导出函数呢 不过在这里我建议对PE一无所知的人 你或许应先补补这方面的知识,我不知道为什么PE方面的 应用在C#中怎么这么少,我查阅过相关 C#的知识 ...
- dll导出函数的两种方式的比较
最初的网页链接已经挂了, 在此贴一个中间的转载链接 https://blog.csdn.net/zhazhiqiang/article/details/51577523 一 概要 vs中导出 dll的 ...
- 动态链接库DLL导出函数并导入使用
动态链接库DLL导出函数并导入使用 本文完全参考自<vs2008制作dll笔记,回带值样例>. 首先制作DLL文件,在vs2010中新建Win32控制台项目,选择DLL选项,简历头文件,源 ...
- 使用dumpbin命令查看dll导出函数及重定向输出到文件【轉】
查看dll导出函数,一般使用Viewdll等第三方工具. VS开发环境中,可以查看32位和64位的dll.具体使用方法如下: 1. 进入VS开发环境,然后Tools -> Visual stud ...
- 使用dumpbin命令查看dll导出函数及重定向输出到文件(VS自带)
以前查看dll导出函数,一般使用Viewdll等第三方工具.但由于Viewdll采用dephi编写,因此仅能查看32位的dll.其实微软已经帮我们提供一个查看dll导出函数的命令,嵌在VS开发环境中, ...
- DLL导出函数
使用DEF文件从DLL导出 模块定义(.def)文件时包含一个或多个描述DLL各种属性的Module语句的文本文件.如果不使用_declspec(dllexport)关键字导出DLL的函数,则DLL需 ...
随机推荐
- intel32指令中文版
http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User's%20Guide/mergedProjects/analyzer_ec/mer ...
- AngularJS过滤排序思路
本篇主要整理使用AngularJS进行过滤排序的思路. 在controller中,$scope的persons字段存储数组. $scope.persons = [ { "name" ...
- 使用C#的泛型队列Queue实现生产消费模式
本篇体验使用C#的泛型队列Queue<T>实现生产消费模式. 如果把生产消费想像成自动流水生产线的话,生产就是流水线的物料,消费就是某种设备对物料进行加工的行为,流水线就是队列. 现在,要 ...
- iPhone上将短信内容发送到指定邮箱的方法
iPhone上将短信内容发送到指定邮箱的方法 迄今为止,移动应用安全基本聚焦在以下几个方面,一是移动设备管理BYOD(bring your own device),二是移动恶意软件分析,三是移动设备用 ...
- Mysql 根据id查所有父级或子级
mysql递归查询,mysql中从子类ID查询所有父类(做无限分类经常用到) 由于mysql 不支持类似 oracle with ...connect的 递归查询语法 之前一直以为类似的查询要么用存储 ...
- SharePoint 删除废弃站点步骤
前言 在SharePoint的日常使用中,经常会有一些废弃的站点需要删除,比如测试站点或者不再使用的站点等,我们应该如何去删除这些站点呢?下面,我们就为大家介绍. 正文 进入SharePoint服务器 ...
- UITableViewCell图片视差效果
UITableViewCell图片视差效果 效果 源码 https://github.com/YouXianMing/Animations 细节 OffsetImageCell.m OffsetCel ...
- 用SDWebImage加载FLAnimatedImage
用SDWebImage加载FLAnimatedImage 效果 源码 https://github.com/YouXianMing/Animations // // GifPictureControl ...
- wdcp支持两种安装方式
v3.2版本已发布,支持多PHP版本共存共用,支持SSL证书,更多可看论坛 v3版讨论区 更多安装说明请看 http://www.wdlinux.cn/bbs/thread-57643-1-1.htm ...
- Android Lint简介
Android Lint是SDK Tools 16 (ADT 16)之后才引入的工具,通过它对Android工程源代码进行扫描和检查,可发现潜在的问题,以便程序员及早修正这个问题.Android Li ...