【问题标题】:Compiling existing C++ code with /clr and then calling it from C#使用 /clr 编译现有 C++ 代码,然后从 C# 调用它
【发布时间】:2015-03-11 08:56:26
【问题描述】:

我有一些 C++ 代码:

namespace Compute {
  class __declspec(dllexport) IProgressCB {
  public:
    virtual void progress(int percentCompleted) = 0;
  };

  double __declspec(dllexport) compute(IProgressCB *progressCB, ...);
}

我在 Visual Studio 2008 中打开“公共语言运行时支持 (/clr)”的情况下创建“compute.dll”。

我想从 C# 调用此代码。

接下来我创建一个 C# 控制台应用程序并添加 compute.dll 作为参考。 然后我尝试继承/实现 IProgressCB:

public class Progress : Compute.IProgressCB
{
    public void progress(int percentCompleted)
    {
        Console.WriteLine(percentCompleted + "% completed.");
    }
}

但是 VS 的自动完成功能找到了“Compute”命名空间,但没有找到其中的任何类或函数!? 当我尝试编译时;它抱怨 IProgressCB 不公开。 如果我在声明 IProgressCB 之前写 public ,它会抱怨无法从密封类型 'Compute.IProgressCB' 派生。

我在这里做错了什么? 我想采用现有的 C++ 代码,不对其进行修改,而是使用 /clrc 编译它,然后从 C# 中使用它。这不可能吗?

【问题讨论】:

    标签: c# visual-c++ c++-cli


    【解决方案1】:

    “不做任何修改”是可能的,但您需要一个中间 C++/CLI 层来包装现有代码。 C# 和其他 CLR 语言只能“看到”托管类型,即 ref 类、值类等。只需将 /clr 应用于现有代码库,您将无法摆脱不编写额外的 C++ 代码。

    【讨论】:

    • 所以 /clr 提供了一种将现有代码从 C++ 移植到 .net 的方法,而不是一种在非托管 C++ 中维护一个可用于非托管 C++ 和 .net 的通用代码库的方法?
    • @Andreas:C++/CLI 提供了一种在 .NET 中使用现有代码的方法。您必须编写新的 C++/CLI 代码,但该代码可以理解并仅适用于 .NET 和原生世界,因此您无需重写现有行为,您可以委托给现有代码。
    • 事实上,按照 Ben 的建议(以及我提到的),您甚至根本不需要使用 /CLR 编译现有代码。
    • 没错,但这是一种不同的策略:在现有 C++ 库周围引入 C++/CLI 包装器。阅读您的建议后(谢谢!);这就是我要做的。但是,可以在其中包含用于非托管 C++ 和使用 /clr 编译的托管 C++ 的宏的代码。不过,这会相当混乱。所以在我看来 /clr 是一种简化从非托管 C++ 移植到托管 C++ 的方法,而 C++/CLI 包装器是一种从托管 C++ 使用现有非托管 C++ 的方法。
    • (这里我使用“托管 C++”来表示在 .net 中运行的 C++/CLI,而不是臭名昭著的 C++/CLI 前身)。
    【解决方案2】:

    IProgressCB 必须是托管类才能在 C# 中可见。

    public ref class IProgressCB
    {
        // ...
    };  
    

    这样做,IProgressCB 的工作方式将与以前完全不同,尤其是内存管理现在完全不同。

    您可以使用 C++/CLI 为现有的非托管类编写托管包装器,但不要期望您可以通过在编译器开关中添加“/clr”直接从 C# 使用非托管 C++ 类。阅读这篇文章

    http://weblogs.asp.net/kennykerr/archive/2005/07/12/Mixing-Native-and-Managed-Types-in-C_2B002B00_.aspx

    了解如何将数据从一个世界传输到另一个世界,反之亦然。

    【讨论】:

      【解决方案3】:

      显然 C++-CLI(C++ 托管扩展的继承者)不是(类似于)C++。命名空间成员的可见性只是差异的一小部分。

      最大的麻烦将是 ref 类的非确定性破坏。

      我建议

      1. 首先阅读 CLR 程序集
      2. 别再想 C++了:
      3. Grok 垃圾回收
      4. Grok 标头依赖项、pImpl idom 和 gcroot
      5. 现在,尝试从头开始使用 C++-CLI 库来包装原生库

      1-2 年[1]丰富经验之后,您将能够知道将原生 C++ 库 1:1 移植到C++-CLI

      [1] -- 好吧,也许你学得很快 :)

      【讨论】:

      • 你的意思是 C++/CLI 而不是托管 C++?
      • 但它们的意思不同。 “托管 C++”一直被用来指代 VC7.0 中引入的中止和极其错误的“C++ 托管扩展”(想想__gc 关键字),在 VC7.1 中进行了一些修复,然后完全放弃在 VC8 中,当它意识到设计问题有多深时。即使用户不关心历史,鼓励使用正确的术语,它也会使与专家的交流更容易。
      • 是的,我的意思是 C++/CLI,对于令人困惑的词语选择感到抱歉。
      猜你喜欢
      • 2010-10-25
      • 1970-01-01
      • 2021-09-01
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-09
      相关资源
      最近更新 更多