Dumpbin显示奇怪的方法名称(在MS Visual C++中生成导出功能)

Sec*_*ret 1 dll pinvoke cdecl dllexport dumpbin

我在VS中创建了新的Win32项目,并为此目的选择了动态库(*.dll).

我在主文件中定义了一些导出函数:

__declspec(dllexport)
int TestCall(void)
{
    int value = 4 / 2;
    std::cout << typeid(value).name() << std::endl;
    return value;
}

__declspec(dllexport)
void SwapMe(int *first, int *second)
{
    int tmp = *first;
    *first = *second;
    *second = tmp;
}
Run Code Online (Sandbox Code Playgroud)

当我看到dumpin/exports时,我得到了:

ordinal hint RVA      name

      1    0 00001010 ?SwapMe@@YAXPEAH0@Z
      2    1 00001270 ?TestCall@@YAHXZ
Run Code Online (Sandbox Code Playgroud)

我正在调用C#这样的版本:

[DllImport(@"lib1.dll", EntryPoint = "?TestCall@@YAHXZ",
CallingConvention = CallingConvention.Cdecl)]
static extern int TestCall();
Run Code Online (Sandbox Code Playgroud)

这不是使用导出方法的正确形式.我在C++ DLL项目中为导出方法生成这样的名称失败了吗?

Han*_*ant 6

这是正常的,C++编译器将名称修饰应用于函数.C++语言支持函数重载,就像C#一样.所以你可以写一个Foo(int)和一个Foo(double)函数.显然,它们不能同时作为名为"Foo"的函数导出,客户端代码不知道要调用哪一个.因此额外的字符对名称进行编码,以使其对于重载是唯一的.

您可以通过声明函数来关闭它extern "C",C语言不支持重载,因此不需要相同类型的装饰.

但如果不这样做,实际上会更好.因为它也是捕捉错误的绝佳方式.就像更改C++代码中的函数声明但忘记修改C#代码中的pinvoke声明一样.现在,您将可以轻松诊断"未找到Entrypoint"异常,而不是非描述性且非常难以诊断AccessViolationException.这不一定要在C++代码中引发,堆栈不平衡也会导致C#代码崩溃.查找装饰名称有点痛苦,但通过要求链接器创建映射文件(/ MAP选项)来改进它.