【问题标题】:Bidirectional communication beetwen C# code and unmanaged C++ libC# 代码和非托管 C++ 库之间的双向通信
【发布时间】:2012-06-03 12:00:14
【问题描述】:

我想将 C++ 库与来自 C# 的非托管代码一起使用。我在stackoverflow上发现了一些帖子是如何做到的。以这种方式它可以工作,但我需要一些解决方案来在 C# 代码中从 C++ 类定义抽象函数(具体来说 - 我的库 C++ 函数必须在 C# 中调用函数)。

问候 卡米尔

【问题讨论】:

    标签: c# c++ visual-studio-2008 visual-c++ unmanaged


    【解决方案1】:

    很酷的问题。要了解这个想法,您应该考虑以下一般情况。您有一个大型 C++ 项目,并且希望使用脚本对其进行扩展。在您的情况下,“脚本”是 .NET/CLR。

    你有:

    namespace Native {
    
    class NativeInterface
    {
    public:
        /// Yes, no implementation here, in the "native world"
        virtual void NativeMethod() = 0;
    
        /// Some other method(s) you'd like to call
        virtual void ConcreteMethod() { cout << "Hello" << endl; }
    };
    
    } // namespace Native
    

    您必须为 Native::NativeInfterface 制作 C++/CLI 包装器:

    namespace Managed
    {
        ref class NativeInterface
        {
        public:
           virtual void NativeMethod() abstract;
    
           virtual void ConcreteMethod() { NativeObj->ConcreteMethod(); }
        public:
           Native::NativeInterface* NativeObj;
        };
    } /// namespace managed
    

    你想用 C# 做:

    namespace Managed {
    
    public class MyNETImplementation: NativeInterface
    {
        override void NativeMethod()
        {
           DoTheStuff_UsingNativeCode(); // possibly, call the ConcreteMethod
        }
    }
    
    } // namespace Managed
    

    关键是您想将指向 MyNETImplementation 的“指针”传递到本地世界的某个地方。

    因此,您应该在 C++/CLI 中实现棘手的 NativeInterfaceImpl 类,该类将保存对 MyNETImplementation 的托管引用,并将调用适当的方法。

    第一次尝试:

    namespace Managed {
    
    /// C++/CLI in mixed-mode assembly
    class NativeInterfaceImpl: public NativeInterface
    {
    public:
       NativeInterfaceImpl(Managed::NativeInterface^ Obj) { ManagedObj = Obj; }
    
       /// Native implementation to call the managed class
       virtual void NativeMethod()
       {
          Obj->NativeMethod();
       }
    public:
       gcroot<Managed::NativeInterface^> ManagedObj;
    };
    
    } // namespace Managed
    

    是的,这很棘手,关于如何传递参数有很多问题,但本网站详细考虑了编组问题。

    忘记添加如何使用指向 NativeInterfaceImpl 的托管指针。如果使用“gcnew”关键字分配它们,则必须在使用前“固定”它们。

    Managed::NativeInterface^ obj = gcnew NativeInterfaceImpl( gcnew MyNETImplementation() );
    pin_ptr<NativeInterface> pinned = obj;
    
    /// void SomeNativeFunction(NativeInterface*);
    SomeNativeFunction( pinned );
    

    编辑(最后润色):

    有几个参考资料有些过时(它们与托管 C++ 相关,而不是 C++/CLI),但仍然很容易适应。

    Calling managed code from unmanaged

    Second version of managed<->unmanaged calls

    【讨论】:

    • 是的,做一个 C++/CLI 桥 :=)
    • 看起来在常见问题解答中太难了 :) 但它看起来还可以,而且效果很好。
    • 维克多感谢您的回答。我正在尝试使用您的建议,但我有一个问题。我想最后一个代码源(你使用 gcnew 的地方)应该在 C# 部分实现。但在 C# 中,我不能使用 gcnet 和 ^ 之类的指针。如果我理解正确,你能告诉我吗?
    • 不,“gcnew”是一个 C++/CLI 结构。您必须在 C++/CLI 中编写“工厂方法”并从 C# 中使用它。 '^' 符号是一个引用(垃圾收集对象)。在 C# 中,类的任何实例 is 在 C++/CLI 术语中都是“引用类”。因此,在 C# 中,您只需使用“新”即可。 Managed.NativeInterface obj = new NativeInterfaceImpl(new MyNETInterfaceImpl())。明白了吗?
    【解决方案2】:

    具体来说——我的库 C++ 函数必须调用 C# 中的函数)。

    这完全没问题,把函数指针上交,但是……

    但我需要一些解决方案来定义 C# 中 C++ 类的抽象函数

    没办法。您所能做的就是实现与 dll 的互操作 - 而不是使用甚至没有标准化的“编译器工件”(编译器之间有所不同)。

    坐下来,学习 C++,C++ 中的子类 - 这可以由 C++ 管理(现在是 C++/CLR),因此您可以从那里很好地调用托管代码。

    但是不,您不能对存储在 .NET 中的 C++ 编译器“.lib”工件中的类进行子类化。

    【讨论】:

    • 你可以,但这很棘手。从 UnrealEngine 中调用 UnrealScript。您可以用脚本语言定义类,这些类可以从 C++ 的类派生。 .NET(C++/CLI,C#)和“本机”C++ 也是如此。这很难,但请参阅我的“解决方法”问题。
    • 我理解这个问题的方式是类继承,而不是“假类”,也就是接口实现。这可能有效,但除此之外 - 这太脏而无法调试。
    • 我没有否决你的答案,因为你是对的,我也对:) 当然,托管/非托管代码的直接混合(在继承方面)是不可能的,但我相信这个通往托管世界的“桥梁”是 OP 想要的。我使用脚本语言完成了这项工作,并且与 .NET 进行了很多互操作,所以这是我的解决方法。
    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-06
    相关资源
    最近更新 更多