连接时怎么指定def 文件,def文件导出dll中的类函数

由DLL或DEF文件生成.LIB文件
Visual & C++ &
开发工具提供了两个命令行工具,一个是dumpbin.exe,另一个是lib.exe。利用这两个工具即可从dll导出其对应的lib。
& 1、在命令行执行: &
& /exports & yourdll.dll
& & & yourdll.def
& yourdll.def &
文件,使之格式与.def文件格式一致 。比如: &
& EXPORTS; &
& & fn1; &
& & fn2; &
& 3、在命令行执行: &
& /def:yourdll.def &
/machine:i386 & /out:yourdll.lib
//为无LIB的DLL制作LIB函数符号输入库
本文介绍了在VC中针对无LIB时的DLL隐式链接,制作可供VC++使用的LIB函数符号输入库。具体步骤如下:
一、使用VC++的工具DUMPBIN将DLL中的导出函数表导出到一定义(.DEF)文件
VideoDeCoder.dll&&
/EXPROTS&&
/OUT:VideoDeCoder.def
二、将导出的.DEF文件整理为一符合.DEF个数的函数导出文件
VideoDeCoder.DEF&&
文件内容如下Dump&&
file&& VideoDeCoder.dll
Type:&& DLL
contains&&
following&&
for&& VideoDeCoder.dll
&&&&&&&&&&&&&&&&&&&&&
0&& characteristics
3D49E48F&&
09:46:55&& 2002
&&&&&&&&&&&&&&&
0.00&& version
&&&&&&&&&&&&&&&&&&&&&
ordinal&& base
&&&&&&&&&&&&&&&&&&&
of&& functions
&&&&&&&&&&&&&&&&&&&
of&& names
RVA&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
00010F60&&
_TM_ClearDecoderBuff@4
&&&&&&&&&&&&&&&&&&
00010E80&&
_TM_CloseDecoder@4
&&&&&&&&&&&&&&&&&&
00010F00&&
_TM_DecodePicture@4
&&&&&&&&&&&&&&&&&&
00010ED0&&
_TM_DecodePictureHeader@4
&&&&&&&&&&&&&&&&&&
00010FD0&& _TM_GetFileEnd@4
&&&&&&&&&&&&&&&&&&
&& _TM_GetUValue@4
&&&&&&&&&&&&&&&&&&
&& _TM_GetVValue@4
&&&&&&&&&&&&&&&&&&
&& _TM_GetYValue@4
&&&&&&&&&&&&&&&&&&
00010E10&&
_TM_OpenDecoder@8
&&&&&&&&&&&&&&&&&
10&&&&&&&&
00010F30&& _TM_ReturnType@4
&&&&&&&&&&&&&&&&&
11&&&&&&&&
00010F90&& _TM_SetFileEnd@8
&&&&&&&&&&&&&&&
2000&& .data
&&&&&&&&&&&&&&&
1000&& .rdata
&&&&&&&&&&&&&&&
1000&& .reloc
&&&&&&&&&&&&&
15000&& .text
按照以下方法整理:
1)添加LIB说明&&
"VideoDeCoder"&&&&&&&&&&&&&&&&&&&&&&&&
;"xx"为DLL名称
DESCRIPTION&&
"VideoDeCoder&& library"
2)去掉导出函数说明端以外的内容,在LIB说明下添加&&
"EXPROTS"&&
说明导出函数&&
LIBRARY&& "VideoDeCoder"
DESCRIPTION&&
"VideoDeCoder&& library"
RVA&&&&&&&&&&&&
&&&&&&&&&&&&&&&
00010F60&&
_TM_ClearDecoderBuff@4
&&&&&&&&&&&&&&&
00010E80&&
_TM_CloseDecoder@4
&&&&&&&&&&&&&&&
00010F00&&
_TM_DecodePicture@
&&&&&&&&&&&&&&&
00010ED0&&
_TM_DecodePictureH
&&&&&&&&&&&&&&&
00010FD0&& _TM_GetFileEnd@4
&&&&&&&&&&&&&&&
&& _TM_GetUValue@4
&&&&&&&&&&&&&&&
&& _TM_GetVValue@4
&&&&&&&&&&&&&&&
&& _TM_GetYValue@4
&&&&&&&&&&&&&&&
00010E10&&
_TM_OpenDecoder@8
&&&&&&&&&&&&&&
10&&&&&&&&
00010F30&& _TM_ReturnType@4
&&&&&&&&&&&&&&
11&&&&&&&&
00010F90&& _TM_SetFileEnd@8
所有的函数放至行首,去掉&&
数据,留下函数的序号&&
"ordinal"&&
,在序号前加上&&
"_导出函数名@参数字节和&&
此种格式(__stdcall&&
方式调用导出的函数符号是&&
"函数名称@参数字节和").&&
最后形成.DEF文件如下:&&
LIBRARY&& "VideoDeCoder"
DESCRIPTION&&
"VideoDeCoder&& library"
TM_ClearDecoderBuff@4&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_CloseDecoder@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_DecodePicture@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_DecodePictureHeader@4&&&&&&&&&&&&&&&&&&&&
TM_GetFileEnd@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_GetUValue@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_GetVValue@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_GetYValue@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_OpenDecoder@8&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_ReturnType@4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
TM_SetFileEnd@8&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
三、使用VC++的LIB工具,带/DEF:(.def文件名)&&
/MACHINE:IX86(80X86机器),就输出符合VC++格式的的LIB文件了.
EXAMPLE:LIB&&
/DEF:VideoDeCoder.def&&
/MACHINE:IX86
接时带上LIB文件链接;注意的是当有些动态库DUMPBIN的只有函数名,无"@nn"的参数格式,如C++Builder写的DLL,输出就只有
函数名符号,链接时就会报错:&&
LNK2002:unresolved&&
external&&
"functionname@nn"&&
提示程序中引入的函数符号无法识别,这时只要将DEF文件中相应的函数名称改为functionname@nn方式,重新建立LIB,重新链接即可.
def文件格式
以下摘自MSDN,希望有帮助。不过在VC下编程好像用不着自己定义DEF文件: &
& 模块定义 & (.def)
& 模块定义 & (.def)
& 文件为链接器提供有关被链接程序的导出、属性及其他方面的信息。生成
& DLL & 时,.def &
文件最有用。由于存在可代替模块定义语句使用的链接器选项,通常不需要 & .def
& 文件。也可以将__declspec(dllexport) &
用作指定导出函数的手段。 &
& 在链接器阶段可以使用 &
/DEF(指定模块定义文件)链接器选项调用 & .def &
& 如果生成的 & .exe &
文件没有导出,使用 & .def &
文件将使输出文件较大并降低加载速度。 &
& 模块定义语句的规则 &
& 下列语法规则适用于 & .def
& 文件中的所有语句。其他适用于特定语句的规则与各语句一起加以说明。
& 语句、属性关键字和用户指定的标识符区分大小写。 &
& 包含空格或分号 & (;)
& 的长文件名必须用引号 & (")
& 引起。 & &
& 使用一个或多个空格、制表符或换行符,将语句关键字同其参数分开和将各语句分开。指定参数的冒号
& (:) & 或等号 &
(=) & 两旁有零个或多个空格、制表符或换行符。 &
& 如果使用 & NAME &
或 & LIBRARY &
语句,则这些语句必须位于所有其他语句之前。 & &
& 在 & .def &
文件中,SECTIONS & 和 & EXPORTS
语句可以出现多次。每个语句都可以采用多个规范,各规范间必须用一个或多个空格、制表符或换行符分开。语句关键字必须在第一个规范的前面出现一次,并且可
以在每个附加规范的前面重复。 & &
& 许多语句都具有等效的 & LINK
& 命令行选项。有关其他详细信息,请参阅相应的 & LINK
& 选项说明。 &
& .def & 文件中的注释由每个注释行开始处的分号
指定。注释不能与语句共享一行,但可以在多行语句的规范间出现。(SECTIONS & 和
& EXPORTS & 为多行语句。)
& 以十进制或十六进制为基础指定数值参数。 &
& 如果字符串参数与保留字匹配,则必须用双引号 & (")
& 将字符串参数引起。 &
& DESCRIPTION & "text"
& 该语句将字符串写入 & .rdata
& 节。将指定的 & text
& 用单引号或双引号(' & 或
& ")引起。若要在字符串中使用引号(单引号或双引号),请用其他类型的标记括住字符串。
& 在模块定义文件中,DESCRIPTION &
仅在生成虚拟设备驱动程序 & (VxD) & 时有效。
& EXETYPE:dynamic & |
& dev386 &
& 在模块定义文件中,EXETYPE & 仅在生成虚拟设备驱动程序
时有效。如果生成虚拟设备驱动程序时在模块定义文件中没有指定 & EXETYPE,并且如果没有指定
& /EXETYPE & 链接器选项,则静态加载
& (dev386) & 生效。
& EXPORTS &
& definitions &
& EXPORTS & 语句引入了一个由一个或多个
& definitions(导出的函数或数据)组成的节。每个定义必须在单独一行上。EXPORTS
& 关键字可以在第一个定义所在的同一行上或在前一行上。.def &
文件可以包含一个或多个 & EXPORTS & 语句。
& 导出 & definitions
& 的语法为: &
& entryname[=internalname] &
[@ordinal & [NONAME]] & [PRIVATE]
& [DATA] &
& entryname &
是要导出的函数名或变量名。这是必选项。如果导出的名称与 & DLL
& 中的名称不同,则通过 & internalname
& 指定 & DLL &
中导出的名称。例如,如果 & DLL & 导出函数
& func1(),要将它用作 & func2(),则应指定:
& EXPORTS &
& func2=func1 &
& @ordinal & 允许指定是序号而不是函数名将进入
& DLL & 的导出表。这有助于最小化
& DLL & 的大小。.LIB
& 文件将包含序号与函数之间的映射,这使您得以像通常在使用 &
DLL & 的项目中那样使用函数名。 &
& 可选的 & NONAME &
关键字允许只按序号导出,并减小结果 & DLL &
中导出表的大小。但是,如果要在 & DLL & 上使用
& GetProcAddress,则必须知道序号,因为名称将无效。
& 可选的 & PRIVATE
& 关键字禁止将 & entryname
& 放到由 & LINK &
生成的导入库中。它对同样是由 & LINK &
生成的图像中的导出无效。 &
& 可选的 & DATA &
关键字指定导出的是数据,而不是代码。例如,可以导出数据变量,如下所示: &
& EXPORTS &
& i & DATA
& 当对同一导出使用 & PRIVATE
& 和 & DATA &
时,PRIVATE & 必须位于 & DATA
& 的前面。 &
& 有三种导出定义的方法,按照建议的使用顺序依次为: &
& 源代码中的 & __declspec(dllexport)
& 关键字 & &
& .def & 文件中的 &
EXPORTS & 语句 &
& LINK & 命令中的 &
/EXPORT & 规范 &
& 所有这三种方法可以用在同一个程序中。LINK &
在生成包含导出的程序时还创建导入库,除非生成中使用了 & .exp
& 文件。 &
& EXPORTS & 节的示例:
& EXPORTS &
& DllCanUnloadNow &
& PRIVATE & &
& DllWindowName & =
& Name & &
& & & DATA
& DllGetClassObject &
& NONAME & &
& PRIVATE &
& DllRegisterServer &
& DllUnregisterServer
& 注意,使用 & .def &
文件从 & DLL & 中导出变量时,不需要在变量上指定
& __declspec(dllexport)。但是,在任何使用
& DLL & 的文件中,仍必须在数据声明上使用
& __declspec(dllimport)。 &
& LIBRARY &
[library][BASE=address] &
& 该语句通知 & LINK &
创建 & DLL。LINK & 同时还创建导入库,除非生成中使用了
& .exp & 文件。
& library & 参数指定
& DLL & 的名称。也可以使用
& /out & 链接器选项指定
& DLL & 输出名。
& BASE=address & 参数设置操作系统用来加载
& DLL & 的基址。该参数重写
& 0x & 的默认
& DLL & 位置。有关基址的详细信息,请参阅
& /BASE & 选项说明。
& 请记住,在生成 & DLL
& 时使用 & /DLL &
链接器选项。 &
& /HEAP:reserve[,commit] &
& HEAPSIZE & 所展示的功能与
& /HEAP & 链接器选项相同。
[application][BASE=address] &
& 该语句指定主输出文件的名称。另一种指定输出文件名的方法是使用
& /out & 链接器选项,而另一种设置基址的方法是使用
& /BASE & 链接器选项。如果两种方法都指定了,则
& /OUT & 重写 &
NAME。 & &
& 如果生成 & DLL,NAME
& 将只影响 & DLL &
& SECTIONS &
& definitions &
& SECTIONS & 语句引入了一个由一个或多个
definitions(关于项目输出文件各节的访问说明符)组成的节。每个定义必须在单独一行上。SECTIONS
& 关键字可以在第一个定义所在的同一行或前一行上。.def &
文件可以包含一个或多个 & SECTIONS & 语句。
& 该 & SECTIONS &
语句为图像文件中的一节或多节设置属性,并可用于重写每种节类型的默认属性。 &
& definitions & 的格式为:
& .section_name & specifier
& 此处,.section_name &
为程序图像中的节名,specifier & 为下列一个或多个访问修饰符:
& EXECUTE &
& READ & &
& SHARED &
& 用空格分开修饰符名。例如: &
& SECTIONS &
& .rdata & READ
& SECTIONS & 标记
& definitions &
节列表的开始位置。每个定义必须在单独一行上。SECTIONS &
关键字可以在第一个定义所在的同一行或前一行上。.def & 文件可以包含一个或多个
& SECTIONS & 语句。支持
& SEGMENTS & 关键字作为
& SECTIONS & 的同义词。
& Visual & C++ &
的早期版本支持: &
& section & [CLASS
& 'classname'] & specifier
& 出于兼容性考虑,支持 & CLASS
& 关键字,但忽略了它。 &
& 另一种指定节属性的方法是使用 & /SECTION
& 选项。 &
& STACKSIZE & reserve[,commit]
& 该语句设置堆栈的大小(以字节为单位)。另一种设置堆栈的方法是使用堆栈分配
& (/STACK) & 选项。有关
& reserve & 和 &
commit & 参数的详细信息,请参阅关于该选项的文档。 &
& 该选项对 & DLL &
& STUB:filename &
& 当用于生成虚拟设备驱动程序 & (VxD)
& 的模块定义文件时,STUB & 允许指定包含将在
& VxD & 中使用的 &
IMAGE_DOS_HEADER & 结构(在 & WINNT.H
& 中定义)而不是默认头的文件名。 &
& 另一种指定 & filename
& 的方法是使用 & /STUB
& 链接器选项。 &
& 在模块定义文件中,STUB & 仅在生成虚拟设备驱动程序
& (VxD) & 时有效。
& VERSION & major[.minor]
& 该语句通知 & LINK &
将一个数字放到 & .exe & 文件或
& DLL & 的头中。major
& 和 & minor &
参数是从 & 0 & 到 &
65,535 & 的范围内的十进制数。默认值为 & 0.0
& 另一种指定版本号的方法是使用版本信息 & (/VERSION)
& 选项。 & &
& VXD & filename
& 允许指定虚拟设备驱动程序 & (VxD)
& 的名称。默认情况下,VxD &
获取与第一个对象文件相同的名称。 &
& 另一种指定虚拟设备驱动程序版本的方法是使用 & /VXD
& 链接器选项,另一种命名输出文件的方法是使用 & /out
& 选项。 &
& 在模块定义文件中,VXD & 仅在生成虚拟设备驱动程序
& (VxD) & 时有效。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。DLL中导出函数的声明有两种方式:
一种方式是:在函数声明中加上__declspec(dllexport);
另外一种方式是:采用模块定义(.def)文件声明,(.def)文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。
方式一:在函数声明中加上__declspec(dllexport)
/// 在动态链接库程序中
/// 声明动态链接库(**.dll)的对外接口函数TestFuction
extern &C& __declspec(dllexport) int TestFuction(int nType,char *strPath,std::vector&string& &vecData)
&&&////do anything here////
&&&return 0;
/// 在外部希望调用动态链接库的程序中
/// 加载动态链接库(**.dll)并调用其对外接口TestFuction
void func()
&&//typedef与函数TestFuction类型相同的函数指针为TESTDLL
&&typedef int (_cdecl * TESTDLL)(int nType,char *strPath,std::vector&string& &vecData);
&&HINSTANCE
&&//加载动态链接库**.dll
&&hmod =::LoadLibrary(_TEXT(&dll相对路径&));
&&if(NULL == hmod)
&&&&&TRACE(&加载**.dll失败&);
&&//定义一个与函数TestFuction类型相同的函数指针lpproc
&&//搜索**.dll中函数名为TestFuction的对外接口
&&lpproc = (TESTDLL)GetProcAddress (hmod,&TestFuction&);
&&//如果搜索成功
&&if(NULL != lpproc)
&&&&&int nType = 0;
&&&&&char* strPath = &Data&;
&&&&&std::vector&string& vecD
&&&&&//通过函数指针lpproc调用**.dll的接口函数TestFuction
&&&&&int nResult = (*lpproc)(nType,strPath,vecData);
&&//在恰当的时候释放动态链接库**.dll
&&FreeLibrary(hmod);
方式二:采用模块定义(.def)文件声明
首先创建 一个DLL程序(DllTestDef)
int __stdcall Add(int numa, int numb)
&&&&&return (numa + numb);
int __stdcall Sub(int numa, int numb)
&&&&&return (numa - numb);
然后创建一个.def的文件,在里面加上
;DllTestDef.lib : 导出DLL函数
;作者:----
LIBRARY DllTestDef
最后创建一个测试程序:.cpp文件如下:
#include &iostream&
#include &windows.h&
typedef int (__stdcall *FUN)(int, int);
HINSTANCE hI
int main()
&&&&&&&hInstance = LoadLibrary(&DLLTestDef.dll&);
&&&&&&&if(!hInstance)
&&&&&&&&&&&cout && &Not Find this Dll& &&
&&&&&&&fun = (FUN)GetProcAddress(hInstance, MAKEINTRESOURCE(1));
&&&&&&&if (!fun)
&&&&&&&&&&&&&&cout && &not find this fun& &&
&&&&&&&cout && fun(1, 2) &&
&&&&&&&FreeLibrary(hInstance);
&&&&&&&return 0;
.def文件的规则为:
(1)LIBRARY语句说明.def文件相应的DLL;
(2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);
(3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。
(4)使用__declspec(dllexport)和使用.def文件是有区别的。
如果你的DLL是提供给VC用户使用的,你只需要把编译DLL时产生的.lib提供给用户(Lostyears: 使用.def就不能以隐式即通过.lib直接引用导出函数),
它可以很轻松地调用你的DLL。但是如果你的DLL是供VB、PB、Delphi用户使用的,那么会产生一个小麻烦。
因为VC++编译器对于__declspec(dllexport)声明的函数会进行名称转换,如下面的函数:
__declspec(dllexport) int __stdcall Add()
会转换为,这样你在VB中必须这样声明:
Declare Function Add Lib &DLLTestDef.dll& Alias && () As Long
@后面的数由于参数类型不同而可能不同。这显然不太方便。所以如果要想避免这种转换,就要使用.def文件方式导出函数了。(Lostyears: dll可以通过Dependcy查看导出函数名称。如果不想加.def[因为加.def不能使用隐式加载]又想防止编译器进行名称改编,那么加上extern &C&和采用c/c++编译器默认的__cdecl调用方式,函数名就不会改编,这样就可以通过动态加载,如:
extern &C&
& int& __cdecl Add(int, int); // 这里去掉__cdecl是等同的
typedef int (__cdecl* pfnAdd)(int, int);
HMODULE hLoad = ::LoadLibrary(_T(&Add.dll&));
pfnAdd f = (pfnAdd)::GetProcAddress(hLoad, &Add&);
则直接添加.lib,直接用Add。
转载:/enterBeijingThreetimes/archive//1792099.html
另外可参考如下,我觉得总结得也不错:
/luosiyong/item/88a97b0e3bd0eeb
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1008次
排名:千里之外
(3)(1)(1)(1)DLL使用def文件导出函数,符号还是修饰了-中国学网-中国IT综合门户网站-提供健康,养生,留学,移民,创业,汽车等信息
> 信息中心 >
DLL使用def文件导出函数,符号还是修饰了
来源:互联网 发表时间: 19:41:01 责任编辑:王亮字体:
为了帮助网友解决“DLL使用def文件导出函数,符号还是修饰了”相关的问题,中国学网通过互联网对“DLL使用def文件导出函数,符号还是修饰了”相关的解决方案进行了整理,用户详细问题包括:模块定义文件中:LIBRARY&MathEXPORTS&Add实际函数定义:int&Add(int&arm1,&int&arm2){return&1;}PE&导出表:图片传不上来,就先手写吧,Add&=&@ILT+110&?Add@@YAHHH@Z&这是什么问题呢?照理说应该是不修饰啊,而且改用extern&"C"&_declspec(dllexport)&也是会修饰,难道是调用约定的问题么?,具体解决方案如下:解决方案1:UPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUP解决方案2:UPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUP解决方案3:dll&导出函数名的那些事关键字: VC++& 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&TestDllEXPORTSMyFunction在&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&TestDllEXPORTSMyFunction在&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&TestDllEXPORTSMyFunctionLIBRARY&用来指定动态链接库内部名称。该名称与生成的动态链接库名一定要匹配,这句代码不是必须的。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(动态库)导出函数名乱码含义C++编译时函数名修饰约定规则:&&__stdcall调用约定:&&1、以"?"标识函数名的开始,后跟函数名;&&2、函数名后面以"@@YG"标识参数表的开始,后跟参数表;&&3、参数表以代号表示:&&X--void&&D--char&&E--unsigned&char&&F--short&&H--int&&I--unsigned&int&&J--long&&K--unsigned&long&&M--float&&N--double&&_N--bool&&....&&PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;&&4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;&&5、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。&&其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如&&&&&&&&&&&&&&&&&&&&&&int&Test1(char&*var1,&unsigned&long)-----"?Test1@@YGHPADK@Z"&&&&&&&&&&&&&&&&&&&&&&void&Test2()-----"?Test2@@YGXXZ"&&__cdecl调用约定:&&规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。&&__fastcall调用约定:&&规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。&&如果要用DEF文件输出一个"C++"类,则把要输出的数据和成员的修饰名都写入.def模块定义文件&&所以...&&&通过def文件来导出C++类是很麻烦的,并且这个修饰名是不可避免的解决方案4:引用&3&楼&zhao4zhong1&的回复:dll&导出函数名的那些事关键字: VC++& 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&TestDllEXPORTSMyFunction在&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&TestDllEXPORTSMyFunction在&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&TestDllEXPORTSMyFunctionLIBRARY&用来指定动态链接库内部名称。该名称与生成的动态链接库名一定要匹配,这句代码不是必须的。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(动态库)导出函数名乱码含义C++编译时函数名修饰约定规则:&&__stdcall调用约定:&&1、以"?"标识函数名的开始,后跟函数名;&&2、函数名后面以"@@YG"标识参数表的开始,后跟参数表;&&3、参数表以代号表示:&&X--void&&D--char&&E--unsigned&char&&F--short&&H--int&&I--unsigned&int&&J--long&&K--unsigned&long&&M--float&&N--double&&_N--bool&&....&&PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;&&4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;&&5、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。&&其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如&&&&&&&&&&&&&&&&&&&&&&int&Test1(char&*var1,&unsigned&long)-----"?Test1@@YGHPADK@Z"&&&&&&&&&&&&&&&&&&&&&&void&Test2()-----"?Test2@@YGXXZ"&&__cdecl调用约定:&&规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。&&__fastcall调用约定:&&规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。&&如果要用DEF文件输出一个"C++"类,则把要输出的数据和成员的修饰名都写入.def模块定义文件&&所以...&&&通过def文件来导出C++类是很麻烦的,并且这个修饰名是不可避免的真服了您,能不能好好说话
1个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答
相关文章:
<a href="/cse/search?q=<inputclass="s-btn"type="submit"text="<inputclass="s-btn"type="submit"text="<buttonhidefocusclass="s-btnjs-ask-btn"text="我要提问
<a href="/cse/search?q=

我要回帖

更多关于 dll导出函数查看器 的文章

 

随机推荐