【问题标题】:Embedding standard C++ into a .NET application将标准 C++ 嵌入到 .NET 应用程序中
【发布时间】:2011-06-15 17:38:36
【问题描述】:

我想用标准的、独立于平台的 C++ 编写一个算法库。

然后我可以采用相同的 C++ 代码并将其编译为 .NET,以便 C# 应用程序可以使用该库吗? 如果没有,实现这种互操作的最简单方法是什么?

【问题讨论】:

    标签: .net visual-c++ c++-cli interop managed-c++


    【解决方案1】:

    您不能直接在 C# 和标准 C++ 之间进行接口。但是,您可以在 C++/CLI 包装器中使用您的 C++ 库,这使得该功能在 .NET 托管代码(以及 C#)中可用。

    只需将包装器编写为 C++/CLI 库,它公开一个 .NET API 并包含标准 C++ 库中的代码(但不幸的是,据我所知,这不能静态链接)。

    【讨论】:

      【解决方案2】:

      您可以通过三种方式公开您的库,以便从托管代码中轻松调用:

      • 为它编写一个包含public ref class 的 C++/CLI 包装器 - C# 代码将调用此类的方法,而后者将调用您的库的本机方法
      • 将库中的 C 样式函数公开为 DLL - C# 代码将使用 P/Invoke 调用函数
      • 用 C++ 编写一个使用您的库的 COM 组件,并通过添加对它的 COM 引用从 C# 代码调用它。

      第三个,COM,我只是为了完整起见。这不会是我的第一选择。或者我的第三个。 COM 组件是否存在是一回事,为此编写它是另一回事。

      在前两个之间,还有谁可以使用这个库是一个问题。如果 C# 代码是唯一使用它的代码,那就做你喜欢的。但是例如,您可能有 15 或 20 个设置各种属性的本机方法,然后是执行实际工作的 goexecute 方法。因为托管本机互操作是有成本的,所以我会告诉您编写一个 C++/CLI 函数,它接受 20 个参数,调用各种本机函数,然后调用 goexecute。这为您提供了一个更厚实的界面而不是繁琐的界面,并降低了您的互操作成本。

      【讨论】:

        【解决方案3】:

        您可以使用 pinvoke 从任何 .NET 语言调用本机 C/C++ 库。这是来自MSDN 的快速教程。您还可以在 C++ 中创建一个 COM dll,您可以使用 COM Interop 从 C# 中直接引用它。除非您需要 COM 的优势,否则 pinvoke 是一条更容易走的路。

        当然,正如 Konrad 所说,您使用托管 C++ 解决方案包装 C++ dll。

        例如,查看http://www.pinvoke.net/ 以获取有关如何从 C# 调用 win32 api 的示例。

        从上面的 MSDN 链接(根据下面的评论修改):

        using System;
        using System.Runtime.InteropServices;
        
        class PlatformInvokeTest
        {
            [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
            public static extern int puts(
                [MarshalAs(UnmanagedType.LPStr)]
                string m);
            [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
            internal static extern int _flushall();
        
        
            public static void Main() 
            {
                puts("Hello World!");
                _flushall();
            }
        }
        

        【讨论】:

        • 可以调用原生C库,C++库伪装成C库。你不能 #include <vector> 并从 C# 中破解。
        • 我从来没有声称你可以。最初的问题询问如何与本机库进行互操作。我提出的解决方案完全有效。
        • 您的 P/Invoke 签名不正确 -- puts_flushall 使用 __cdecl 调用约定导出,但 DllImport 属性使用 __stdcall,除非您另外指定。 (我知道该错误是从您链接到的 MSDN 页面复制的,但您也可以在 IMO 此处修复它。)
        • @ildjarn:感谢您的信息。我检查了一下,有趣的是,没有任何示例显示使用这些方法中的任何一种指定的调用约定(至少我看到了)。我使用两种调用约定测试了示例代码并且都有效。我将修改答案以具有适当的约定。这会影响性能吗?
        • 在某些平台上,CLR 会抛出堆栈不平衡的异常,在其他平台上,它能够自动纠正不平衡。我怀疑更正不是免费的...关于 showing 调用约定,这是 not 显示的事实,这在此处进行了说明 - C/C++ 的默认值是__cdecl 和 .NET P/Invoke 的默认值是 __stdcall,鉴于双方均未指定任何内容,因此必须使用默认值。
        猜你喜欢
        • 2012-12-06
        • 1970-01-01
        • 2011-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多