Search code examples
c++-cliinteropmarshallingunmarshalling

How to efficiently marshal array of objects to native function using C++/CLI


I have array of objects holding primitive types and enums; how do I marshal a pointer to this data to a native function with the signature native_func(void* ptr[]).

array<System::Object^>^ values = gcnew array<System::Object>(64);

// ... populate the managed array with primitives ...

// data is pinned and won't be moved by the GC
pin_ptr<object> pinned = &values[0]; 

// not sure what do here... data is corrupted in the native code
native_func((void**)pinned); 

Thanks!

EDIT. My second attempt was to do the following:

pin_ptr<object> pinned = &values[0]; 
void* testArray[64];
for (auto i = 0; i < values->Length; i++)
{
    testArray[i] = (void*)Marshal::UnsafeAddrOfPinnedArrayElement(values, i);
}
native_func(testArray);

Now, the addresses stored in testArray are getting passed correctly to the native side but the contents of the memory is not what I am expecting. What am I doing wrong now?


Solution

  • Enums are not blittable so marshaling an array of objects require special consideration (i.e. you can't just pin_ptr the array and pass it over the native/managed boundary). I decided to use a VARIANT to hold the primitive & enum values and did so with the following code:

    // allocate a managed array of size 64 (it's enough for my application)
    array<System::Object^>^ values = gcnew array<System::Object>(64);
    
    // stack allocate a native array of size 64 
    VARIANT nativeValueArray[64] = {}; 
    
    // ... populate the managed array ...
    
    for (auto i = 0; i < values->Length; i++)
    {
        Marshal::GetNativeVariantForObject(values[i], (IntPtr)(void*)&nativeValueArray[i]);
    }
    
    // pass the array of native VARIANTS to the native function "native_function"
    native_function(nativeValueArray);
                
    

    The native function's signature became

    void native_function(VARIANT values[]);
    

    There might be a more efficient way to do this but this is what I was able to come up with. Please let me know if you have a more efficient way to accomplish what am I doing.