通过静态变量从本机代码访问有状态托管对象
本文关键字:状态 对象 访问 本机代码 静态 变量 | 更新日期: 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 ;
}
问题
- 我必须从C++DLL向C++应用程序公开一个本机API头
- 本机类不能将托管对象作为成员变量
- 目前,如果本机应用程序创建了多个
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) ;
}