Tuesday, 10 September 2013

Marshalling arrays of VARIANT using P/Invoke

Marshalling arrays of VARIANT using P/Invoke

Situation: I have a managed (C#, .NET 2.0) application which uses an
unmanaged (C++) DLL using P/Invoke. Along with the "simple" methods (POD
arguments/return value) there's a requiement to pass a boost::variant
value arrays to the code. The reason for it is that these methods pass
report data (similar to Excel cells, which can be of any type).
The previous implementation called for use of SafeArray of COM VARIANT's.
However, due to poor coding/not testing it, the marshalling turned out to
be leaking memory. Now I have to find another option for marshalling the
data.
Previous implementation looked like this: C++:
extern "C" __declspec(dllexport) void GetReport(VARIANT& output) {
// ... here a SafeArray of VARIANT values was created
output.vt = VT_VARIANT | VT_ARRAY;
output.parray = safeArray;
}
C#
[DllImport("CppLibrary.dll")]
private static extern void GetReport(out object output);
//....
object data;
GetReport(data);
object rows = data as object[];
This specific implementation leaks memory by not freeing up the interop
structures.
I've tried to change the prototypes by including SafeArray marshalling
directives:
C#
private static extern void GetReport([Out,
MarshalAs(UnmanagedType.SafeArray, SafeArraySubType =
VarEnum.VT_VARIANT)]ref object[] output);
C++
extern "C" __declspec(dllexport) void GetReport(SAFEARRAY output) { //
Also tried SAFEARRAY*, SAFEARRAY&, VARIANT, VARIANT*
// Internal stuff
}
Problem: How to correctly marshal such data type (array of VARIANT-typed
structures) to C#? I can make the C++ DLL a COM one, but this will require
rewriting quite a handful of code. Is there any simpler way out of the
situation?

No comments:

Post a Comment