2

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?

3
  • 1
    Do you have control over the interface? SAFEARRAY will automatically work in managed code. Bit more of a bear from native, though. Otherwise, I expect you would have to pin an array of IntPtr manually filled with Marshal.GetIUnknownForObject and pass that address. I'm not sure what the marshalling for object[] is with [MarshalAs(UnmanagedType.LPArray)]. Commented Jan 10, 2022 at 15:32
  • Just pass an [In] VARIANT* parameter when you want to pass an array, and remove your size_is attribute in idl (more for C-style non-Automation interface). From .NET then use an object[] of anything as input. Commented Jan 10, 2022 at 15:57
  • Unfortunately I cannot change the COM/IDL code because it is used in other C/C++/Delphi application... Commented Jan 11, 2022 at 10:03

1 Answer 1

-1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.