1. 详解C++ 动态库导出函数名乱码及解决

     更新时间:2019年03月13日 14:34:47   作者:luochenlong   我要评论

    这篇文章主要介绍了C++ 动态库导出函数名乱码及解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    刚接触C++,在尝?#28304;?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--表示?#21018;耄?#21518;面的代号表明?#21018;?#31867;型,如果相同类型的?#21018;?#36830;续出现,以"0"代替,一个"0"代表一次重复;    
      4、参数表的第一项为该函数的返回值类型,其后?#26469;?#20026;参数的数据类型,?#21018;?#26631;?#23545;?#20854;所指数据类型前;    
      5、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。    
      其格式为"?[email protected]@YG*****@Z"或"?[email protected]@YG*XZ",例如    
                          int Test1(char *var1, unsigned long)-----?[email protected]@[email protected]

                         void Test2()-----"?[email protected]@YGXXZ" 
      __cdecl调用约定:    
      规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。    
      __fastcall调用约定:    
      规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。  

      如果要用DEF文件输出一个"C++"类,则把要输出的数据?#32479;?#21592;的修饰名都写入.def模块定义文件    
      所以...   通过def文件来导出C++类是很麻烦的,并且这个修饰名是不可避免的

    虽然有约定的含义,但这也真够麻烦的!我不禁想,我们之前导入 User32.dll,Shell32.dll 等等这些动态库的函数的时候,那些EntryPoint没见这么麻烦啊,怎么回事?还是万能的百度……“在到处函数之前加上“extern "C"?#26412;?#34892;了!”,我们来试试:

    // 下列 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++ 动态库导出函数名乱码及解决详解整合,希望对大家有所帮助,如果大家有任?#25105;?#38382;请给我留言,小编会及时回复大家的。在此也非常?#34892;?#22823;家对脚本之家网站的支持!

    您可能?#34892;?#36259;的文章:

    相关文章

    最新评论

    山东群英会开奖查询