C++互操作:如何从本地C++调用非静态的C#类?

7
我有一个用本地C ++编写的大型应用程序。我还有一个用C#编写的类需要调用。
如果C#类是静态的,那么它就很简单(网上有很多例子)-只需编写混合C ++ / CLI包装器,导出接口即可完成。
然而,C#类是非静态的,并且不能更改为静态类,因为它具有接口(如果尝试使C#类静态,则编译器将生成错误)。
有人遇到过这个问题吗 - 如何将非静态的C#类导出到本地C ++?

更新2010-11-09

最终解决方案:尝试了COM,这个方法效果很好,但不支持结构体。因此,我选择了一个C++/CLI包装器,因为我绝对需要能够在C++和C#之间传递结构体。我基于这里的代码编写了一个混合模式的.dll包装器:

由于目标类是非静态的,所以我必须使用单例模式来确保我只实例化了一个目标类的副本。这确保了一切都足够快,以满足规格要求。

如果您希望我发布演示项目,请与我联系(尽管公平地说,我正在从C++调用C#,而现在大多数人都想从C#调用C++)。


我知道几周后我会需要这个,所以我对答案非常感兴趣。 - dwo
该死,那是一个像电锯一样的转折点。就在问题的最后,当你最没有想到的时候! - Tyler Durden
3个回答

10

C++/CLI或COM interop与非静态类和静态类一样有效。使用C++/CLI,您只需引用包含非静态类的程序集,然后可以使用gcnew获取对新实例的引用。

您为什么认为这对于您的非静态类不可能呢?

编辑:这里有示例代码here

using namespace System;

public ref class CSquare
{
private:
    double sd;

public:
    CSquare() : sd(0.00) {}
    CSquare(double side) : sd(side) { }
    ~CSquare() { }

    property double Side
    {
    double get() { return sd; }
    void set(double s)
    {
        if( s <= 0 )
        sd = 0.00;
        else
        sd = s;
    }
    }

    property double Perimeter { double get() { return sd * 4; } }
    property double Area { double get() { return sd * sd; } }
};

array<CSquare ^> ^ CreateSquares()
{
    array<CSquare ^> ^ sqrs = gcnew array<CSquare ^>(5);

    sqrs[0] = gcnew CSquare;
    sqrs[0]->Side = 5.62;
    sqrs[1] = gcnew CSquare;
    sqrs[1]->Side = 770.448;
    sqrs[2] = gcnew CSquare;
    sqrs[2]->Side = 2442.08;
    sqrs[3] = gcnew CSquare;
    sqrs[3]->Side = 82.304;
    sqrs[4] = gcnew CSquare;
    sqrs[4]->Side = 640.1115;

    return sqrs;
}

我决定使用COM。顺便问一下,您知道C++/CLI包装器在C#中实例化非静态类的示例吗?无论我尝试什么,都无法避开编译器错误,并且网络上的所有示例都是针对静态类而不是其他类型的类。 - Contango
非常好,谢谢。为了完整起见,您所引用的源代码是为MSVS 2003设计的,除非升级到MSVS 2005,否则无法使用。有关说明和更新的源代码,请访问http://msdn.microsoft.com/en-us/magazine/cc163602.aspx(感谢@Sergey)。 - Contango
最终选择了C++/CLI来支持结构体。请参见主问题中的编辑。 - Contango

3

我能想到两个选择。

  1. 将这个类作为COM对象公开,然后从C++中作为COM对象使用。
  2. 创建一个静态的C#类,该类公开用于与非静态C#类交互的接口。

我决定使用COM,它完美地运行了。非常感谢您花时间回答这个问题 - 非常感激。 - Contango

1

我几年前调查过这个主题:我想要在不使用/clr关键字编译的本机代码中使用log4net和Npgsql库。

这个技巧背后的主要思想由Paul DiLascia在他的两篇杰出文章中描述:

Visual Studio 2005中的托管代码

使用我们的ManWrap库在本机C++代码中获得最佳.NET效果

该解决方案中的主要思想是gcroot智能指针和intptr_t在内存中具有完全相同的表示。我们创建一个名为GCROOT(T)的宏,在托管代码中使用gcroot,在未管理的代码中使用intptr_t,并创建带有本机接口和托管实现的DLL,并从本机代码中使用此dll。

对于我来说,很容易为我的托管类创建一些适配器,并在本机C++世界中使用它们以及即使没有/clr关键字编译我的源代码。


我看了一下你提到的代码,它看起来非常容易使用:我将实现COM和上面的代码,并编辑我的原始问题以进行更正。非常感谢! - Contango

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接