1

我有一个带有方法“Foo()”的 C++ Dll“TheFoo.dll”

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

Foo();

我相信该方法确实具有:

 __declspec( dllexport )

因此,通过阅读我对 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();

        }



    }
}

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

Unable to find an entry point named 'Foo' in DLL 'C:\MyFolder\TheFoo.dll'.

任何想法为什么找不到它?

4

3 回答 3

10

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();

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

于 2012-09-26T00:19:46.467 回答
4

您应该提供有关 C++ 的更多信息。尝试extern "C" __declspec(dllexport)改用。C++ 以奇怪的名称导出,因此使用extern "C"可以避免这种情况。

于 2012-09-25T22:39:52.077 回答
1

如果你没有在你的 dll 中声明它为 extern "C",那么它的名字可能已经被“损坏”了。您可以使用 Dependency Walker 之类的工具来查看您的 dll 导出的符号。

于 2012-09-25T22:40:06.460 回答