【问题标题】:Exposing C++ unmanaged code class pointers to C# with C++/CLI使用 C++/CLI 向 C# 公开 C++ 非托管代码类指针
【发布时间】:2021-07-26 16:27:00
【问题描述】:

为我对 C++/CLI 的基本知识表示歉意,但它是最近才作为必需品介绍给我的。我正在尝试使用 C++/CLI 为非托管 C++ 库创建一个包装器。我已经关注this helpful guide 并且可以确认它(以某种方式)可以解决问题。我遇到的问题是 C++ 指针公开了对非托管库中公共类的访问。在我的 CPP 库中,我使用它们通过访问单个入口点类来调用多个类的方法。在 C# 中,我无法访问应该可以通过这些类指针访问的方法。我收到一条错误消息,指出“该成员由于其保护级别而无法访问”,并且“->”指针未授予对 公开类 成员的访问权限。

我的代码如下所示:

UnmanagedCode::ClassA

...
// some code
...
public:
    void doSomething() { ... };
    ClassB* classB() { return classB.get(); };
private:
    std::unique_ptr<ClassB> classB_ {};

C++/CLI 包装器

public ref class WrapperClass: public ManagedObject<UnmanagedCode::ClassA>
{
public:
    WrapperClass() : ManagedObject(new UnmanagedCode::ClassA) {}; // template class code in the hyperlink
    ~WrapperClass() {};
    void doSomething() { m_Instance->doSomething(); };
    UnmanagedCode::ClassB* classB() { return m_Instance->classB(); };
};

C#程序

class Program
{
    static void Main(string[] args)
    {
        WrapperClass w = new WrapperClass();
        w.doSomething(); // this works fine
        w.classB(); // here is where I am getting the error
    }
}

【问题讨论】:

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


    【解决方案1】:

    我认为您需要为每个类提供一个包装器以使其在 c# 中有用。

    即要返回 classB,您可以编写类似

    MyClassBWrapper^ GetClassB(){ return gcnew MyClassBWrapper(m_Instance->classB());
    

    虽然您可以在托管代码中乱用指针,但它需要不安全的代码,并且使用起来非常麻烦。如果你正在编写一个 c++/cli 包装器,你应该提供一个完全托管的 API。除了(可选地)对图像或类似的大型数据块使用指针之外,可能会有例外。

    【讨论】:

    • 我在CPP中访问ClassB成员的方式如下:classA->classB()->someMethod()。也许对我来说最好的选择是直接公开“someMethod()”?
    • @szumial 这是另一种可能性。这在一定程度上取决于您的 API 设计。
    【解决方案2】:

    我的 C# 知识,不如我的 C++,只是作为一个注释。 我不太明白你在这里做什么:

    UnmanagedCode::ClassB* classB() { return m_Instance->classB(); };
    

    此行返回一个指向 ClassB 对象的指针,您可以在 C# 中检索该对象。据我所知,这将要求 ClassB 也是一个托管对象,否则,我认为您不能在对象上调用函数,而无需为不安全的函数指针创建委托。

    如果我理解你的问题是正确的,我认为这样的东西可以用 C++ 解决你的问题:

    void* classB() { return static_cast<void*>(m_Instance->classB()); };
    void doSomethingWithClassB(void* instance) {static_cast<ClassB*>(instance)->doSomethingWithClassB();}
    

    然后在 C# 中:

        class Program
        {
            static void Main(string[] args)
            {
                WrapperClass w = new WrapperClass();
                w.doSomething();
                unsafe
                {
                    void* classb = w.classB();
                    w.doSomethingWithClassB(classb);
                }
            }
    

    【讨论】:

    • 看来,为了访问非托管 ClassB 的成员,我需要将其单独包装在 C++/CLI 中,对吗?
    • 是的,我会这么认为。您也许可以将每个函数包装为委托,但是,我只知道如何使用 c++ dll 来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2015-10-20
    • 2012-10-10
    • 2011-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多