Search code examples
c#c++commarshalling

Passing a c# array of object to COM interface method


I should pass a pointer of object array to a COM interface with the following IDL and C++ definitions: C++ code:

UpdateItem( LONG lID, LONG lNumOfFields, FieldIdEnum* pFields, VARIANT* pvValues )

IDL:

HRESULT UpdateItem( [in] LONG lID, [in] LONG lNumOfFields, [in, size_is(lNumOfFields)] FieldIdEnum* pFields, [in, size_is(lNumOfFields)] VARIANT* pvValues );

tlbimp generated C# code:

UpdateItem([In] int lID, [In] int lNumOfFields, [In] ref FieldIdEnum pFields, [In][MarshalAs(UnmanagedType.Struct)] ref object pvValues);

... and I try to call with:

FieldIdEnum[] fieldIDs = { FieldIdEnum.fi1ID, FieldIdEnum.fi2At };
object[] values = { 3, DateTime.UtcNow };
mi.UpdateItem(1, 2, ref fieldIDs[0], ref values[0]);

I get this interface from my system as result of login and authentication process... The UpdateItem method is a public member of that interface.

I want to pass two or more field and value pairs (in same time) by the two array. The field array always is passed correctly to C++ code. I have debugged C++ code and the "FieldIdEnum* pFields" represents the first element of an integer array and the 2nd element (pFields1) is correct too. The pField[] is a c-style array.

But the 2nd array is a variant array with various element type in this case an integer and a date time. This appears as a SafeArray at c++ side instead of c_style array. I have checked this 2nd array too, it is a simple variant array if the method calling starts from another C code, but C# tries to marshal it to safearray.

I have changed the C# definition to

UpdateItem([In] int lID, [In] int lNumOfFields, [In] ref FieldIdEnum pFields, [In] ref object pvValues);

It does not work I always get an exception like "Value does not fall within the expected range." "System.Exception {System.ArgumentException}"

I have tried to use/marshal various managed/unmanaged types and Intptr, did not work.

I have found an other topic with same/similar problem, I could not make it work.

How should I pass a pointer of object array to COM interface?


Solution

  • I have found the solution. I have redefined the interface method:

            void UpdateItem([In] int lID, [In] int lNumOfFields, [In] ref FieldIdEnum pFields, [In][MarshalAs(UnmanagedType.LPArray)] object[] pvValues);
    

    ... and call this as:

                FieldIdEnum[] updateFieldIDs = { FieldIdEnum.fi1ID, FieldIdEnum.fi2At };
                object[] values = { 3, DateTime.UtcNow };
                
                mi.UpdateItem(id, updateFieldIDs.Length, ref updateFieldIDs[0], values);
    

    Thank you for guidance.