从 c# 调用 c++ 库

Posted

技术标签:

【中文标题】从 c# 调用 c++ 库【英文标题】:Call c++ library from c# 【发布时间】:2010-06-02 14:00:35 【问题描述】:

这个问题似乎与之前的问题重复。我已经阅读了一系列帖子,但对我的情况并不完全清楚。

我有一个使用motics IDE 创建的c++ 库。我必须能够将此库用于 c# 项目。

有人在交给我之前一直在做这个项目。目前,有 2 层可以实现这一点。首先,一个 c++ 项目包括带有 c++ 包装器的完整库。该项目创建一个 dll 作为输出。然后将此 c++ dll 提供给 c# 项目,该项目具有对 c++ dll 的 dllimport 调用。这个 c# 项目再次创建了一个 dll。最后,为了在 c# 应用程序中使用该库,我必须包含对这两个 dll 的引用。

这是让它工作的正确方法吗?我在想可能应该有一种方法来简化这个过程。

有人可以帮我解答这个问题吗?

【问题讨论】:

How do I call native C++ from C#? 的可能重复项 【参考方案1】:

鉴于您使用的是 C++ 库,我假设它利用了类等 C++ 语义,而不仅仅是公开过程。如果是这种情况,那么这通常是通过手动创建的托管 C++ 互操作库来完成的。

基本上,您可以在 Visual Studio 中创建托管 C++ 库,引用现有 C++ 库,并围绕现有 C++ 类创建托管包装器。然后,您在 C# 项目中引用此(托管)C++ 程序集,并将原始(非托管)C++ 库包含在您的 C# 程序集中,就像放置在构建目录中的文件一样。

这是必需的,因为无法通过 P/Invoke (DllImport) 调用引用 C++ 类之类的内容。

如果您的基础库只是一系列函数,那么您可以通过 P/Invoke 函数在 C# 项目中直接引用它。

无论哪种方式,都必须包含上述所有库(对于第一种,非托管 C++ 库、托管 C++ 程序集和 C# 项目,或者对于第二种,非托管 C++ 库和 C# 项目)在任何引用它们的项目中。您不能将非托管库静态链接到托管程序集。

【讨论】:

+1,但我想指出,除非您使用 .NET 1.1,否则“托管 C++”现在称为“C++/CLI”,并且有 huge 两者之间的差异。 另外,我认为您的意思是“您不能动态链接非托管库”。 静态链接是使用该库的唯一方法。 非常感谢....正如您所提到的,非托管库确实有类和接口。在这种情况下,我相信我必须有一个 c++ 包装器和一个 c# 包装器才能在我的 c# 应用程序中使用非托管 c++ 库,对吧?现在 c++ 包装器完成了创建类实例和实现接口的任务,对吗?我有另一个问题。提供 extern "C" 和 _dllexport 功能是非托管库的工作吗?目前还没有,但我可以把它作为下一个项目的要求,所以只是想确定一下。 @Batul:对于你的第一个问题,是的;您需要在 C++/CLI 中创建一个使用经典 C++ 类型的包装类(感谢@Randolpho 对术语的澄清)。对于您的第二个问题,是的,如果您想走DllImport 路线,那么您的非托管库需要公开extern "C" 函数,以便它们可以在完全托管的(C#、VB.NET 等)中使用。部件。请注意,我们在谈论两个不同的事情;通常您要么使用 C++/CLI 程序集作为包装器您导出过程函数并DllImport它们在您的托管代码中 哦,现有的实现使用这两种方法。在我之前从事此工作的人创建了一个 c++ 包装器并导出了函数。然后,他还使用 C# 中的 DllImport 来访问这些函数。感谢您的澄清。现在,考虑到非托管 c++ lib 具有类和接口,可以选择 DllImport 吗?另外,如果我创建 c++/cli 包装器,那么这是否意味着我可以简单地将其添加为 c# 应用程序中的引用 n 按原样使用它?无需使用 DllImport?非常抱歉问了这么多问题,但非常感谢您的耐心等待。【参考方案2】:

似乎您的包装器太多了,但也许有人正在实现某种外观或添加属性或其他东西。托管和非托管之间的基本连接将是“平面”函数调用的 DllImport(不是成员函数)或 C++/CLI 代码调用成员函数。如果包装器是 C++/CLI,那么它最容易编写(只包含 C++ 库的头文件)并且最容易调用(C# 代码只是添加一个 .NET 引用并照常进行)所以如果它是我的首选该项目有 C++ 专业知识。

听起来无论你从谁那里接手,都在艰难地做这件事。如果方法少于 20 种,我建议重新开始。

【讨论】:

重新开始对我来说也是最好的解决方案,但是一旦我开始,无论我看什么,都只指出当前的解决方案是正确的方法。我从您的建议中了解到,还有一个 c++ 包装器来处理非托管 c++ lib 中的类,然后在 c# 中使用 dllImport 调用。我说的对吗? 如果您添加 C++/CLI 包装器,它可以将您从 P/Invoke (DllImport) 中拯救出来。基本上您的 C++/CLI 代码可以“包含标头,链接到库”来使用您的本机代码。 C++/CLI 代码中的任何 public ref class Foo 都可以从 C# 调用,根本没有互操作机制 - 只需添加一个引用并使用它。 谢谢凯特。从我目前所读到的,DllImport 需要非托管库中的平面结构,即没有类和接口。但是我的非托管库有类和接口,这是否意味着我不能使用 DllImport?如果是这样,那么创建 c++/cli 包装器是唯一的方法吗? 在 C++ 领域几乎没有“唯一的方法”。只是更好的方法。围绕你的类编写一个扁平的包装器以便你可以使用 DllImport 似乎不是一个好计划。我更喜欢 C++/CLI 方法。【参考方案3】:

可以使用:

DllImport

class Example

    // Use DllImport to import the Win32 MessageBox function.
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

    static void Main()
    
        // Call the MessageBox function using platform invoke.
        MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
    

【讨论】:

以上是关于从 c# 调用 c++ 库的主要内容,如果未能解决你的问题,请参考以下文章

(71)C#里怎么样调用C++动态连接库的代码

从 c++ wrap 调用 c# 方法

创建 C++ Dll,并从 C# 调用它

从 c# 项目 System.AccessViolationException 调用 c++ char*

C#总结调用C++动态库

从非托管 c++ 调用 C# 函数(通过托管包装器)