通过静态变量从本机代码访问有状态托管对象

本文关键字:状态 对象 访问 本机代码 静态 变量 | 更新日期: 2023-09-27 18:30:13

我有一个本机C++应用程序和一个C#DLL。我的本机C++应用程序需要访问C#DLL的功能。为了做到这一点,我创建了一个混合模式的C++DLL。我的设计基本上和这个一样。换句话说:

我有一个由混合C++DLL使用的C#DLL,它由本机C++应用程序使用。以下是我正在做的事情的简化版本:

C#DLL

using System;
namespace CSDLL
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person() : this("Bob", 30)
        {
        }
        public Person(String name, Int32 age)
        {
            Name = name;
            Age = age;
        }
        public override string ToString()
        {
            return String.Format("<Person Name='"{0}'" Age='"{1}'"/>", Name, Age);
        }
    }
}

C++DLL

Person.h:适用于本机应用程序的头文件

#include <string>
namespace CPPDLL
{
    class __declspec(dllexport) Person
    {
    public:
        Person () ;
        Person (const std::string &name, int age);
        void PrintPerson () const ;
    };
}

Person.cpp:混合代码实现注意静态变量person

#include "Person.h"
namespace CPPDLL
{
    ref class Wrap 
    {
    public: 
        static CSDLL::Person ^person = gcnew CSDLL::Person () ;
    };
    Person::Person ()
    {
    }
    Person::Person (const std::string &name, int age)
    {
        System::String ^csName = gcnew System::String (name.data ()) ;
        Wrap::person = gcnew CSDLL::Person (csName, age) ;
    }
    void Person::PrintPerson () const
    {
        System::Console::WriteLine (Wrap::person) ;
    }
}

本机C++应用程序示例

#include "Person.h"
int main ()
{
    CPPDLL::Person person ("Billy", 5) ;
    person.PrintPerson () ;
    return 0 ;
}

问题

  1. 我必须从C++DLL向C++应用程序公开一个本机API头
  2. 本机类不能将托管对象作为成员变量
  3. 目前,如果本机应用程序创建了多个CPPDLL::Person实例,那么它们都将在同一个CSDLL::Person^实例上工作。因为本机类不能有托管数据成员,所以我不确定有什么明显的方法可以解决这个问题

问题

有没有一种简单/明显的方法可以让CPPDLL::Person的每个实例都使用自己的CSDLL::Person^副本?

通过静态变量从本机代码访问有状态托管对象

问题是为混合C++中的每个CPPDLL::Person实例创建一个C#CSDLL::Person实例。作为本机类中的CPPDLL::Person,它不能直接持有托管对象的引用,但您可以通过GCHandle来完成,它提供了一种从非托管内存访问托管对象的方法。

你可以这样更改代码:

在CPPDLL::Person的声明中,您添加了一个整数成员变量,该变量充当指向托管对象的指针。

    namespace CPPDLL
{
    class __declspec(dllexport) Person
    {
    private:
        int m_personPtr;
    public:
        Person () ;
        Person (const std::string &name, int age);
        void PrintPerson () const ;
    };
}

CPPDLL::Persion的实现如下:

ref class Wrap 
    {
    public: 
        static int CreatePerson(const std::string &name, int age)
        {
            System::String ^csName = gcnew System::String (name.data ()) ;
            CSDLL::Person ^person = gcnew CSDLL::Person (csName, age) ;
            //pin the manage object and return the handle as int values
            GCHandle^ handle = GCHandle::Alloc(person, GCHandleType.Pinned);
            IntPtr^ ptr = handle->AddrOfPinnedObject();
            return ptr->ToInt32();
        }
        static void Release(int p)
        {
            //unpin the manage object and release it.
            GCHandle^ handle = GCHandle::FromIntPtr(gcnew IntPtr(p));
            if (handle != nullptr)
                handle->Free();
        }
    };
    Person::Person ()
        :m_personPtr(0)
    {
    }
    Person::Person (const std::string &name, int age)
    {
        m_personPtr = Wrap::CreatePerson(name, age);
    }
    Person::~Person ()      
    {
        Wrap::Release(m_personPtr);
    }
    void Person::PrintPerson () const
    {
        System::Console::WriteLine (Wrap::person) ;
    }