views:

222

answers:

1

I would like to move fairly complex types from the managed to native world and visa versa.

Currently this is being done by creating multidimensional safearrays, which has the advantage that marshalling is done for you, but means we end up with rather complex jagged arrays to get our heads around.

I have tried to put some structs into SAFEARRAYs but came across issues very similar to this unanswered question. msdn seems to imply that it is possible, but I am having little success. If this is possible, what are valid VT_ types in the following situation?

edit: Thanks! So this has to be a VT_RECORD.

struct Change
{
    PSTR key;
    PSTR val;
};

struct NodeChages
{
    int nodeId;
    SAFEARRY* changes; //CComSafeArray<Change>
};


STDAPI func(/*CComSafeArray<NodeChanges>*/ SAFEARRAY * f);

On the managed side I have.

public struct Change
{
    [MarshalAsAttribute(UnmanagedType.LPStr)]
    public string key;
    [MarshalAsAttribute(UnmanagedType.LPStr)]
    public string value;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NodeChanges
{
    public int nodeId;
     [MarshalAsAttribute(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(CurveChange))]
    public Change[] changes;
}

[DllImportAttribute("My.dll", EntryPoint = "Func", PreserveSig = true, CallingConvention=CallingConvention.StdCall)]
   public static extern void Func(
   [MarshalAsAttribute(UnmanagedType.SafeArray, SafeArrayUserDefinedSubType = typeof(NodeChange))]
   NodeChange[] changes
   );

But this (as in the other post) gives me:

System.ArgumentException : The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
A: 

I also used VT_RECORD. But didn't got success in passing safearray of UDTs.

        [ComVisible(true)]
        [StructLayout(LayoutKind.Sequential)]
        public class MY_CLASS
        {
            [MarshalAs(UnmanagedType.U4)]
            public Int32 width;
            [MarshalAs(UnmanagedType.U4)]
            public Int32 height;
        };

    [DllImport("mydll.dll")]
    public static extern Int32 GetTypes(
        [In, Out][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD, SafeArrayUserDefinedSubType = typeof(MY_CLASS))]MY_CLASS[] myClass,
        [In, Out][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD, SafeArrayUserDefinedSubType = typeof(Guid))]Guid[] guids
        );

If i communicate with my unmanaged code without 1st parameter, Then there is no error in passing "guids" parameter to unmanaged code.

I also able to cast elements of obtained SAFEARRAY at unmanaged side to GUID type. But If i tried to pass my UDT class MY_CLASS to unmanaged code with SAFEARRAY then it fails on managed code. (as above code snippet)

It shows exception "An unhandled exception of type 'System.Runtime.InteropServices.SafeArrayTypeMismatchException' occurred in myapp.exe" "Additional information: Specified array was not of the expected type."

Plz help me in such a situation to pass SAFEARRAY of UDTs to unmaged code.

themilan