利用微软的dumpbin.exe我们可以方便的查看dll中的函数名字,为了能利用命令行,我们要首先把C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin设置为path环境变量,这个时候运行命令:
dumpbin -exports xx.dll
此时会出现一个问题,说是缺少mspdb100.dll ,这个时候我们从C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE中复制mspdb100.dll,运行上面的命令,发现OK,可以看到dll中的函数名字,但是问题在此时就又出现了,我们重新编译程序,会出现这样的错误:
fatal error C1902: 程序数据库管理器不匹配;请检查安装
这个时候我们把刚才复制过来的mspdb100.dll删除,然后再重新编译程序,发现错误就没了,难道以后要用dumpbin就必须这么麻烦吗,添加,然后删除?
答案是有的,我们需要从C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE把mspdbsrv.exe也复制到bin里面,这样再重新编译的时候就不会出错了?
不过还是不理解微软要这么做,放了一个exe在bin里面,却不把相关的依赖文件放进去?
实例程序:
addF.h
#ifndef _ADDFULL_H #define _ADDFULL_H extern "C" _declspec(dllexport) int add(int x,int y); _declspec(dllexport) int sub(int x,int y); _declspec(dllexport) int _stdcall mul(int x,int y); #endif
#include "stdafx.h" #include "addF.h" int add(int x,int y) { return x + y; } int sub(int x,int y) { return x - y; } int _stdcall mul(int x,int y) { return x * y; }
从图上我们可以明显的看到dll中的函数名字,其中用 extern “C” 声明的函数,其名字和函数原来的名字一样,add;
其余两个函数的名称在导出时候就多了前缀和后缀,因为他们是C++的编译方式,其中函数的前缀后缀还是有所不同 的,先说
_declspec(dllexport) int sub(int,int),它的函数调用方式是缺省的_cdel,所以函数名字被解析为 ?sub@@YAHHH@Z,其中YA代表_cdel调用,YA后面第一个字母H代表函数的
返回类型是int,后面两个H代表函数的两个int形参,@z代表函数的结束。
_declspec(dllexport) int _stdcall mul(int,int)它的函数调用方式是_stdcall,函数名字被解析为?mul@@YGHHH@Z,其中YG代表_stdcall,剩下的意思跟_cdel中的一样。
所以说在这点还是要注意的。
另谈函数的调用方式对函数名字的影响:
C++,C中的两种调用方式,默认的是_cdecl,另外一个是stdcall,如果我们用默认的_cdecl来调用的话就,如下所示:
extern "C" _declspec(dllexport) int add(int x,int y); extern "C" _declspec(dllexport) int sub(int x,int y); _declspec(dllexport) int _stdcall mul(int x,int y);函数导出的名字就会是:
如果是:
extern "C" _declspec(dllexport) int add(int x,int y); extern "C" _declspec(dllexport) int sub(int x,int y); extern "C" _declspec(dllexport) int _stdcall mul(int x,int y);那么结果就会是:
这说明在stdcall调用方式下,如果加上extern “C”,那么函数名字就会变成 _funcName@Num,其中的num代表参数占用的字节数,
但是如果不加extern “C”的话,函数名字就完全是C++中的那种添加前后缀的形式
在cdecl调用方式下,如果加上extern “C”,函数导出的名字就和函数原本的名字一样,(这一点是两种调用方式不同点所在)
去掉extern “C”,那么函数名字就是C++中的添加前后缀(这点和stdcall的结果一样)。