C#P\Invoke DLL没有进入C++的入口点?

00j*_*0jt 1 c# pinvoke dllimport

我有一个C++ Dll"TheFoo.dll",方法是"Foo()"

我可以通过简单地调用以下方法访问使用此方法的其他C++代码:

Foo();
Run Code Online (Sandbox Code Playgroud)

我相信该方法确实具有:

 __declspec( dllexport )
Run Code Online (Sandbox Code Playgroud)

所以,随着我对P/Invoke的阅读,我想我应该能够简单地从我的C#代码中调用相同的方法:

namespace PInvokeExample1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

        }


        [DllImport(@"C:\MyFolder\TheFoo.dll")]
        public static extern
            void Foo();

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Foo();

        }



    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我收到一个错误:

Unable to find an entry point named 'Foo' in DLL 'C:\MyFolder\TheFoo.dll'.
Run Code Online (Sandbox Code Playgroud)

任何想法为什么没有找到?

Han*_*ant 9

C++语言支持重载,就像C#一样.您可以导出函数void Foo(int)和函数void Foo(double).显然,这两个函数不能同时导出为"Foo",DLL的客户端不知道选择哪一个.所以事实并非如此.

C++编译器通过修饰函数的名称来解决这个问题.添加额外的字符使Foo(int)与Foo(double)不同.您可以通过Dumpbin.exe /exports foo.dll从Visual Studio命令提示符运行来查看这些修饰名称,该命令提示符列出了导出函数的名称.假设你的声明是相关的,你会看到?Foo@@YAXXZ.

所以C#程序中的相应声明应该是:

    [DllImport("foo.dll", EntryPoint = "?Foo@@YAXXZ", 
               ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
    private static extern void Foo();
Run Code Online (Sandbox Code Playgroud)

有一些方法可以更改C++函数声明,使C#声明更容易.这实际上不是一个好主意,这些装饰名称实际上有助于捕捉错误.