Como Hans Passantwishes aquí está el escenario mío. Tengo una aplicación de modo mixto en la que el código nativo hace todo el trabajo mientras respeta el rendimiento y el código administrado es responsable únicamente de la GUI. También los usuarios participarán escribiendo su código de propiedad de C#. Tengo C++ para clases nativas, C# para GUI y código de usuario y C++/Cli para clases de contenedor entre. Entre todas mis clases de C++ hay una que hace% 90 de los cálculos y se crea un parámetro diferente cada vez. Llamémoslo NativeClass. Hay un aprx. 2000 instancias de este NativeClass y tengo que encontrar la instancia correcta relacionada con algún parámetro antes de hacer el cálculo. Así que ideé un hash_map, con parámetros que son el código hash, para este propósito. Cuando obtengo un parámetro, busco la instancia correcta en hash_map, la encuentro y llamo a algunos de sus métodos.
Cuando los usuarios contribuyen a los cálculos escribiendo código C# y esta clase ejecuta estos códigos mediante devoluciones de llamada. Esto es trivial, pero a veces necesito cierta información sobre las clases .Net que los usuarios construyeron. Así que tengo que adjuntar ese ManagedClass específico a NativeClass de alguna manera. Mi primera solución es usar GChandle.Alloc() y transferir la dirección de los controladores. Pero hay algunos concerns sobre GC que no harán su trabajo correctamente. Hans recomendó Marshal.AllocCoTaskMem() y Marshal.StructureToPtr() para asignar objetos administrados en la memoria no administrada, sin embargo, creo que esto es válido para las clases de clase de valor o las estructuras. ¿Qué hay de las clases de ref? ¿Cómo puedo pasar una referencia a NativeClass mientras evito que se recolecten GC y hacer que GC funcione correctamente al mismo tiempo?GCHandle, Marshal, memoria administrada y no administrada: Para fijar o No para marcar
Aquí hay un código de ejemplo:
class NativeClass
{
private:
int AddressOfManagedHandle;
public:
static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
{
// return NativeClass associated with SomeParameter from NativeClassHashMap;
}
NativeClass(int addr, int SomeParameter) : AddressOfManagedHandle(addr)
{
}
int GetAddress(){return AddressOfManagedHandle;}
void DoCalculation(){
// CALCULATIONS
}
};
public ref class ManagedClass : MarshalByRefObject
{
private:
NativeClass* _nc;
//GCHandle handle;
void FreeManagedClass()
{
Marshal::FreeHGlobal(IntPtr(_nc->GetAddress()));
//if(handle.IsAllocated)
//handle.Free();
delete _nc;
}
public:
ManagedClass()
{
IntPtr addr = (Marshal::AllocHGlobal(Marshal::Sizeof(this))); // Error
Marshal::StructureToPtr(this,addr,true);
//handle = GCHandle.Alloc(this);
//IntPtr addr = handle.ToIntPtr();
_nc = new NativeClass(addr.ToInt32());
}
~ManagedClass() {FreeManagedClass();}
!ManagedClass() {FreeManagedClass();}
int GetAddress() {return _nc->GetAddress();};
static ManagedClass^ GetManagedClass(int SomeParameter)
{
int addr = NativeClass::GetNativeClassFromHashMap(SomeParameter)->GetAddress();
//Object^obj = GCHandle::FromIntPtr(IntPtr(addr)).Target;
Object^ obj = Marshal::PtrToStructure(IntPtr(addr), ManagedClass::typeid);
return dynamic_cast<ManagedClass^>(obj);
}
};
lo siento que no es demasiadooooooooooooo larga y todavía clara.
Debe utilizar IntPtr en lugar de int para almacenar punteros nativos. De lo contrario, su código puede bloquearse en Windows de 64 bits. – Elmue
No debe liberar la memoria en otra clase. Escriba un destructor (finalizador) ~ NativeClass() que llama a FreeHglobal(). – Elmue