简体   繁体   中英

Marshaling an array of C# structure and use it in COM-What are the right Marshaling Attributes

I am facing the following problem for almost a week: I have an array of c# structure which needs to be sent to a COM application. But when I call the COM method I get the following

error: System.Runtime.InteropServices.MarshalDirectiveException' occurred

Additional information: Cannot marshal 'parameter #5': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).

The IDL file is extended/derived with a C# interface.

Here is the method defined as in the IDL:

[helpstring("Method MyCallbackMehtod")]
    HRESULT MyRequestFinished(
        [in] long    callId,
        [in] unsigned int nrElemArray1,
        [in, size_is(nrElemArray1)] MyStruct ElemArray1[],
        [in] unsigned int nrElemArray2,
        [in, size_is(nrElemArray2)] MyStruct ElemArray2[]
);

The c# interface:

 [ComImport, Guid("xxxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxx")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IMyInterface
    {

        void MyRequestFinished(
            [In] 
            long callId,

            [In] 
            uint nrElemArray1,

            [In,MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] 
            IntPtr ElemArray1,

            [In]
            uint nrElemArray2,

            [In, MarshalAs(UnmanagedType.LPArray,SizeParamIndex = 3)]  
            IntPtr ElemArray2);
}

The definition of MyStruct is:

[StructLayout(LayoutKind.Sequential,Pack=1)]
    public struct MyStruct
    {
        public double setValue;
        public double actualValue;
        [MarshalAs(UnmanagedType.I4)]
        public MyEnum myResult;
    }

    [ComVisible(true)]
    public enum MyEnum 
    {
        Val1,

        Val2,

        Val3
    }

The code snippet where the call to the COM method is called:

IntPtr pMyElemArray1  = IntPtr.Zero;
IntPtr pMyElemArray2 = IntPtr.Zero;

MyStruct[] MyElemArray1= GetArray1();
MyStruct[] MyElemArray2= GetArray2();

int lengthElemArray1= MyElemArray1.Length;
int lengthElemArray2= MyElemArray2.Length;

pMyElemArray1 = Marshal.AllocCoTaskMem(Marshal.SizeOf(MyElemArray1[0]) * lengthElemArray1);
pMyElem2 = Marshal.AllocCoTaskMem(Marshal.SizeOf(MyElemArray2[0]) * lengthElemArray2);

int rundef = (int)pMyElemArray1 ;
for (int i = 0; i < lengthElemArray1; i++)
{
     Marshal.StructureToPtr(MyElemArray1 [i], (IntPtr)rundef, false);
     rundef += Marshal.SizeOf(MyElemArray1[i]);
}

rundef = (int)pMyElemArray2;
for (int i = 0; i < lengthElemArray2; i++)
{
    Marshal.StructureToPtr(MyElemArray2[i], (IntPtr)rundef, false);
    rundef += Marshal.SizeOf(MyElemArray2[i]);
}

// Notify COM component
//here i get the error
  myComObject.MyRequestFinished(callId,
                       ((uint)lengthElemArray1),
                       pMyElemArray1,
                       ((uint)lengthElemArray2),
                       pMyElemArray2);
//....
}

LPArray is not applicable to parameters of type IntPtr . Try either changing the parameter type to an array or removing the MarshalAs attribute.

void MyRequestFinished(
    [In]
    long callId,

    [In]
    uint nrElemArray1,

    [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
    MyStruct[] ElemArray1,

    [In]
    uint nrElemArray2,

    [In]  
    IntPtr ElemArray2);
}

Personally, I prefer to pass in an array rather than an IntPtr as it results in much simpler logic at the call site.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM