Marching an array of strings from managed code

I have a managed function with the following declaration (for both the interface and the implementation):

[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] String[] ManagedFunction() { String[] foo = new String[1]; foo[0] = "bar"; return foo; } 

There is also a native C ++ interface with the same methods as the managed interface; inside this interface, this method has the following declaration:

 void ManagedFunction(SAFEARRAY* foo); 

This function is called by native code as follows:

 void NativeFunction(ManagedBinding binding) { CComSafeArray<BSTR> cComSafeArray; cComSafeArray.Create(); LPSAFEARRAY safeArray = cComSafeArray.Detach(); binding.comObject->ManagedFunction(safeArray); } 

I'm not sure what I'm doing wrong, but after my managed function was called, safeArray seems to have garbage values, something is wrong when you return the return value back to native code. Can anyone with more experience than me, with the .Net internet, please shed some light on this? Also, it might be appropriate to mention that I had no problem returning a ValueType from my managed function ( boolean , if you're interested), something about returning a String array is a mess. Thanks!

+6
source share
2 answers

Well, finally, I got him to work. I created a SAFEARRAY managed view called ManagedSafeArray (stolen here: http://social.msdn.microsoft.com/Forums/en-US/clr/thread/6641abfc-3a9c-4976-a523-43890b2b79a2/ ):

 [StructLayout(LayoutKind.Sequential)] struct ManagedSafeArray { public ushort dimensions; // Count of dimensions in the SAFEARRAY public ushort features; // Flags to describe SAFEARRAY usage public uint elementSize; // Size of an array element public uint locks; // Number of times locked without unlocking public IntPtr dataPtr; // Pointer to the array data public uint elementCount; // Element count for first (only) dimension public int lowerBound; // Lower bound for first (only) dimension } 

I changed the signature of my method to:

 void ManagedMethod(ref ManagedSafeArray foo); 

Inside my method, I manually updated the dataPtr field by calling Marshal.AllocCoTaskMem(...) and then copying the lines that I would like to contain SAFEARRAY .

I have no idea why the CLR was not able to automatically marshal the parameters in and out of my own code, and I would still appreciate it if someone tries to explain this.

0
source

1) Your function returns a SAFEARRAY , so why do you allocate it before calling the function?
2) ManagedFunction must return SAFEARRAY , so it must get SAFEARRAY* to return it! therefore you must say:

 LPSAFEARRAY lpsa; binding.comObject->ManagedFunction(&lpsa); CComSafeArray<BSTR> cComSafeArray; cComSafeArray.Attach(lpsa); 
0
source

All Articles