[置顶] VS2015用C++创建的动态库导出函数名乱码原因分析

        在上一篇博客【在VS2015中用C++创建动态库并用C#调用】中提到,在C# DllImport导入C/C++编写的动态库时函数,要加上CallingConvention = CallingConvention.Cdecl来指定入口点的调用约定。这是因为C/C++编写的动态库默认的入口点约定为_cdecl,而VS默认调用动态库时的约定为_winapi。

        本文将重点介绍下这些入口点的调用约定,并以此来说明函数名乱码的真正原因,并且会在下一篇博客中详细说明如何创建一个可以被其它语言调用的动态库。

(1)按照【在VS2015中用C++创建动态库并用C#调用】博文中1到8步创建测试项目,但是步骤8中的DLLTest.h中添加函数Test1和Test2的导出形式前,不要加EXTERN_C。

[置顶] VS2015用C++创建的动态库导出函数名乱码原因分析_第1张图片

(2)使用Dependency Walker查看导出的动态库DLL

[置顶] VS2015用C++创建的动态库导出函数名乱码原因分析_第2张图片

从上图中可以看到导出的函数名都是乱码,此时可以在乱码上右击选择Undecorate C++ Functions,如下图:


此时函数名会自动变为你想要的函数名,如下图

[置顶] VS2015用C++创建的动态库导出函数名乱码原因分析_第3张图片

(4)下面详细讲解下函数名乱码的原因

           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"。

(5)由上面可以看出C/C++导出的动态库DLL默认的入口点调用约定为__cdecl调用约定,所以C#在调用时需加CallingConvention =           CallingConvention.Cdecl来指定入口点的调用约定

(6)通过在导出函数前加入EXTERN_C,可以将导出的函数名固定为你想要的函数名,更改入口点约定,让导出的动态库可以被其它语言调用,             请浏览下篇博客。

你可能感兴趣的:(C++,dll,动态库,VS2015,函数名乱码)