详解C++动态库导出函数名乱码及解决刚接触C++,在尝试从 dll 中导出函数时,发现导出的函数名都“乱码”了。
导出过程如下:
新建⼀个Win32项⽬:
新建的解决⽅案⾥有⼏个导出的⽰例:
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准⽅法。此 DLL 中的所有⽂件都是⽤命令⾏上定义的 DLLEXPORT_EXPORTS
// 符号编译的。在使⽤此 DLL 的
// 任何其他项⽬上不应定义此符号。这样,源⽂件中包含此⽂件的任何其他项⽬都会将
// DLLEXPORT_API 函数视为是从 DLL 导⼊的,⽽此 DLL 则将⽤此宏定义的
// 符号视为是被导出的。
#ifdef DLLEXPORT_EXPORTS
#define DLLEXPORT_API __declspec(dllexport)
#else
#define DLLEXPORT_API __declspec(dllimport)
#endif
// 此类是从 dllExport.dll 导出的
class DLLEXPORT_API CdllExport {
public:
CdllExport(void);
// TODO: 在此添加您的⽅法。
};
extern DLLEXPORT_API int ndllExport;
DLLEXPORT_API int fndllExport(void);
于是我什么都不做,直接⽣成,并且在C#⾥导⼊看看能否调⽤,嗯……错误来了:
不到⼊⼝点?难道是没导出么?我们⽤“Dependency Walker”来看看:
Oh, shit, WTF is this? 导出是导出了,不过怎么都乱码了?
右键选择“Undecorate C++ Functions”之后才出现了真⾯⽬:
不过我们的⽬的是要在C#中使⽤,⽽不是⽤眼睛在 Dependency ⾥⾯看啊!嗯,既然⼊⼝点的名字都变了,要不我们在 C#中⼿动指定⼊⼝点试试?
不错,成功了,我们终于可以使⽤ C++ 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++类是很⿇烦的,并且这个修饰名是不可避免的
虽然有约定的含义,但这也真够⿇烦的!我不禁想,我们之前导⼊ User32.dll,Shell32.dll 等等这些动态库的函数的时候,那些EntryPoint没见这么⿇烦啊,怎么回事?还是万能的百度……“在到处函数之前加上“extern "C"”就⾏了!”,我们来试试:
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准⽅法。此 DLL 中的所有⽂件都是⽤命令⾏上定义的 DLLEXPORT_EXPORTS
// 符号编译的。在使⽤此 DLL 的
// 任何其他项⽬上不应定义此符号。这样,源⽂件中包含此⽂件的任何其他项⽬都会将
// DLLEXPORT_API 函数视为是从 DLL 导⼊的,⽽此 DLL 则将⽤此宏定义的
// 符号视为是被导出的。
#ifdef DLLEXPORT_EXPORTS
#define DLLEXPORT_API __declspec(dllexport)
#else
#define DLLEXPORT_API __declspec(dllimport)
#endif
// 此类是从 dllExport.dll 导出的
class DLLEXPORT_API CdllExport {
public:
CdllExport(void);
/
/ TODO: 在此添加您的⽅法。
};
extern "C" DLLEXPORT_API int ndllExport;
extern "C" DLLEXPORT_API int fndllExport(void);
注意和之前对⽐,最后两⾏有变化。编译⽣成,运⾏ C# 项⽬:
没有指定 EntryPoint 了,成功!
以上所述是⼩编给⼤家介绍的C++ 动态库导出函数名乱码及解决详解整合,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。在此也⾮常感谢⼤家对⽹站的⽀持!