Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CLI/C++: void* to System::Object

This is a similar question to this SO post, which I have been unable to use to solve my problem. I have included some code here, which will hopefully help someone to bring home the message that the other posting was getting at.

I want to write a CLI/C++ method that can take a void pointer as a parameter and return the managed object (whose type I know) that it points to. I have a managed struct:

public ref struct ManagedStruct { double a; double b;};

The method I am trying to write, which takes a void pointer to the managed struct as a parameter and returns the struct.

ManagedStruct^ VoidPointerToObject(void* data)
{   
    Object^ result = Marshal::PtrToStructure(IntPtr(data), Object::typeid);
    return (ManagedStruct^)result;
}

The method is called here:

int main(array<System::String ^> ^args)
{   
    // The instance of the  managed type is created:
    ManagedStruct^ myData = gcnew ManagedStruct();
    myData->a = 1;  myData->b = 2;      

    // Suppose there was a void pointer that pointed to this managed struct
    void* voidPtr = &myData;

    //A method to return the original struct from the void pointer
    Object^ result = VoidPointerToObject(voidPtr);  
    return 0;
}

It crashes in the VoidPointerToObject method on calling PtrToStructure , with the error: The specified structure must be blittable or have layout information

I know this is an odd thing to do, but it is a situation I have encountered a few times, especially when unmanaged code makes a callback to managed code and passes a void* as a parameter.

like image 250
Rory Avatar asked Dec 05 '22 20:12

Rory


1 Answers

(original explanation below)

If you need to pass a managed handle as a void* through native code, you should use

void* voidPtr = GCHandle::ToIntPtr(GCHandle::Alloc(o)).ToPointer();

// ...

GCHandle h = GCHandle::FromIntPtr(IntPtr(voidPtr));
Object^ result = h.Target;
h.Free();

(or use the C++/CLI helper class gcroot)


Marshal::PtrToStructure works on value types.

In C++/CLI, that means value class or value struct. You are using ref struct, which is a reference type despite use of the keyword struct.

A related problem:

void* voidPtr = &myData;

doesn't point to the object, it points to the handle.

In order to create a native pointer to data on the managed heap, you need to use pinning. For this reason, conversion between void* and Object^ isn't as useful as first glance suggests.

like image 58
Ben Voigt Avatar answered Feb 23 '23 03:02

Ben Voigt