DllImport修饰名问题-无法找到入口点

5

我有一个奇怪的问题,我有一个C++ DLL,我正在使用DLL导入将其导入到C#库中。如果我指定入口点,一切都按预期工作,这是一个示例:

internal static class UnsafeMethods
{
    [DllImport("GoodSchool.dll", EntryPoint = @"?AddNum@@YAHHH@Z")]
    public static extern int AddNum(int num1, int num2);
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(UnsafeMethods.AddNum(4,5));
    }
}

然而,如果我使用类似于这里的简化导入方式:
[DllImport("GoodSchool.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AddNum(int num1, int num2);

我遇到了一个熟悉的错误信息:

未处理的异常:System.EntryPointNotFoundException: 在 DLL 'GoodSchool.dll' 中找不到名为 'AddNum' 的入口点

我使用 depends 工具验证了该方法是否已正确公开,并解码注释以验证参数和命名惯例 - 一切看起来都很好。

C++ 中的函数签名非常简单:

  __declspec(dllexport) int AddNum(int num1, int num2); 

有没有建议如何在不提供修饰名称为入口点的情况下,在C#中调用该方法?我做错了什么?我不想使用"C"导出,因为我的理解是,修饰函数名可以完全用于DllImport。

你有充分的理由不想使用"extern C"声明吗?"因为我认为你没有必要"并不是一个令人信服的理由。 - JerKimball
我正在使用C++代码中的这个DLL,它在那里可以正常工作,所以我想保持它现在的状态。 - Sebastian K
2个回答

7

C++对函数名进行重载来解决函数名重复的问题。毕竟,如果DLL有

__declspec(dllexport) int AddNum(int num1); 
__declspec(dllexport) int AddNum(int num1, int num2); 

AddNum指的是什么?

?AddNum@@YAHHH@Z符号是未托管DLL中公开的名称修饰(也称为装饰)名称。

https://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B

你的DLL没有导出名为AddNum的东西。


是的,但我认为既然我们在属性后提供了函数声明,编译器就有足够的信息来重现修饰名称。 - Sebastian K
@SebastianK - P/Invoke 不涉及 C# 编译器 - 它是 CLR 服务。无论如何,C# 编译器不知道如何执行 C++ 名称重整,并且没有 C++ 名称重整的标准。任何编译器(或同一编译器的不同版本)都可以进行不同的名称重整。 - shf301
@SebastianK:理论上,CLR可以识别DLL包含的混淆VC++入口点,并将其映射到C#符号,但它选择不这样做。其中一个原因可能是如果有任何函数重载,它仍然会出现问题。 - Eric J.
@EricJ。维基百科上的链接已失效,您可以将其替换为:https://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B - Joezer
感谢提供更新的链接。如果您对更改有信心,直接编辑新的URL通常是可以的。 - Eric J.
显示剩余2条评论

6
装饰后的函数名称可与DllImport一起使用,您正在这样做,因此没有问题。但是,这要求您在导入中指定装饰后的函数名称。就链接器(静态或动态)而言,未装饰的名称不存在-AddNum只是库未公开的符号。
如果您想达到以下目的:

在C#中调用此方法而无需提供Entry Point的名称?

那么您不能让C ++首先混淆名称。 您可以C ++代码中指定带装饰的名称DllImport, 或者使用extern“C”链接。 您必须选择其中之一。

确切地说 - 说得好。编译器并不是神奇的 - 它无法推断您尝试引用哪个非托管函数,仅因为名称混淆并不普遍。 - JerKimball
好的,很有道理 - 我以为名称修饰更多是一个标准 - 它仅取决于调用约定、返回类型和参数。 - Sebastian K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接