Pregunta

¿Cómo puedo enviar un objeto administrado a una función nativa para usarlo?

void managed_function()
{
  Object^ obj = gcnew Object();

  void* ptr = obj ??? // How to convert Managed object to void*?

  unmanaged_function(ptr);
}

// The parameter type should be void* and I can not change the type.
// This function is native but it uses managed object. Because type of ptr could not be 
// Object^ I called it "Unmanaged Function".
void unmanaged_function(void* ptr)
{
  Object^ obj = ptr ??? // How to convert void* to Managed object?

  obj->SomeManagedMethods();
}
¿Fue útil?

Solución 2

Después de buscar en Google, leer MSDN y probar algunos códigos, encontré este método para pasar un objeto administrado a una función no administrada.

Estos métodos muestran cómo convertir Object ^ en void * y convertir void * en Object ^.

using namespace System;
using namespace System::Runtime::InteropServices;

void managed_function() 
{ 
  Object^ obj = gcnew Object();

  // Convert Object^ to void*
  GCHandle handle = GCHandle::Alloc(obj);
  IntPtr pointer = GCHandle::ToIntPtr(handle);
  void* ptr = pointer.ToPointer();

  unmanaged_function(ptr);

  handle.Free();
} 

void unmanaged_function(void* ptr) 
{
  // Convert void* to Object^
  IntPtr pointer(ptr);
  GCHandle handle = GCHandle::FromIntPtr(pointer);
  Object^ obj = (Object^)handle.Target;

  obj->SomeManagedMethods();
} 

Nota: si "unmanaged_function" tiene argumentos variables, este método no funcionará.

Otros consejos

El enfoque más limpio y mejor es usar plantilla gcroot .

Una cita de MSDN Cómo: declarar identificadoresen tipos nativos :

La plantilla gcroot se implementa utilizando las instalaciones de la clase de valor System :: Runtime :: InteropServices :: GCHandle, que proporciona "identificadores" en el montón de basura recolectada.Tenga en cuenta que los identificadores en sí no se recolectan como basura y se liberan cuando el destructor de la clase gcroot ya no los usa (este destructor no se puede llamar manualmente).Si crea una instancia de un objeto gcroot en el montón nativo, debe llamar a delete en ese recurso.

Su código de muestra adaptado para usar gcroot (el código se compila y se ejecuta usando VS 2010):

using namespace System;
using namespace System::Runtime::InteropServices;

public ref class SomeManagedObject
{
public:
    String^ data;
    SomeManagedObject()
    {
        data = "Initial Data";
    }
    void SomeManagedMethods()
    {
        data = "Changed Data";
    }
};

void unmanaged_function(void* ptr) 
{
    gcroot<SomeManagedObject^>& obj = *((gcroot<SomeManagedObject^>*)ptr);
    obj->SomeManagedMethods();
} 

void managed_function() 
{ 
    // gcroot handles all allocations/deallocation and convertions
    gcroot<SomeManagedObject^>* pObj = new gcroot<SomeManagedObject^>();

    *pObj = gcnew SomeManagedObject();
    unmanaged_function(pObj);

    delete pObj;
} 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top