none
Marshal an allocated struct from COM C++ to C# RRS feed

  • Question

  • Hi,

    I have a native com component and I want to access it from C#.

    Here is a part of the idl :

    typedef struct { 

    BOOL bStuff; 

    BSTR sAString;

    } MyInfos;

    interface IMyInterf : IUnknow

    {

    HRESULT iGetMyInfos([out] MyInfos **ppInfos);

    }

    In the iGetMyInfos method, the struct is allocated with CoTaskMemAlloc, filled and returned in the ppInfos parameter.

    I want to use this in C#. tlbimp doesn't look strong with struct, so I tried to write the marshal by myself :

    namespace Mynamespace
    {
        using System;
        using System.Runtime.CompilerServices;
        using System.Runtime.InteropServices;
    
        [StructLayout(LayoutKind.Sequential)]
        public struct MyInfos {
            [MarshalAs(UnmanagedType.Bool)]
            public bool bStuff;
            [MarshalAs(UnmanagedType.BStr)]
            public string sAString;
        };
    
        [ComImport, InterfaceType((short)1), Guid("xxxx")]
        public interface IMyInterf 
        {
           [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
            void iGetMyInfos([Out, MarshalAs(UnmanagedType.Struct)] out MyInfos infos);
        }
    
        [ComImport, Guid("xxxx")]
        public class CoMyObj { }
    }

    I have other methods wich return strings as out parameters, and these work well.

    But I never succeeded to retrieve the content of My MyInfos struct. I try many MarshalAs types, without success.

    The string in the struct is empty and the Boolean is always true (?).

    Does anybody can tell me how to solve this ?

    I saw many samples with struct, but none with a struct allocated by the com component.

    Thanks a lot !

    J.


    Tuesday, October 29, 2013 11:14 AM

Answers

  • Try doing it in two steps like in the link I provided.  The error is occuring because you are getting a long pointer array back instead of a MarshalAs(UnmanagedType.Struct)] .

    Or try this

     void iGetMyInfos([Out, MarshalAs(UnmanagedType.LPArray)] out MyInfos[] infos);


    jdweng

    Tuesday, October 29, 2013 1:23 PM

All replies

  • Try change below.  the C code has it shown as **ppInfos which is a pointer to a pointer which indicates it is a pointer to an array.

    From :     void iGetMyInfos([Out, MarshalAs(UnmanagedType.Struct)] out MyInfos infos);
    To   :     void iGetMyInfos([Out, MarshalAs(UnmanagedType.Struct)] out MyInfos[] infos);

    See webpage below

    http://stackoverflow.com/questions/11131676/how-do-i-marshall-a-pointer-to-a-pointer-of-an-array-of-structures


    jdweng

    Tuesday, October 29, 2013 12:35 PM
  • Thanks.

    I got an exception :

    Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination (Arrays can only be marshaled as LPArray, ByValArray, or SafeArray)." [thrown by System.StubHelpers.StubHelpers.ThrowInteropParamException]

    ---

    For information, the native COM code looks like this :

    (no error management for clarity)

    STDMETHODIMP CMyObj::iGetMyInfos(MyInfos **ppInfos) { MyInfos *pInfos=NULL; pInfos=(MyInfos *)CoTaskMemAlloc(sizeof(*pInfos))); memset(pInfos, 0, sizeof(*pInfos)); pInfos->bStuff=FALSE; pInfos->sAString=SysAllocString(L"tototo"); *ppInfos=pInfos;
    return S_OK; }



    Tuesday, October 29, 2013 1:07 PM
  • Try doing it in two steps like in the link I provided.  The error is occuring because you are getting a long pointer array back instead of a MarshalAs(UnmanagedType.Struct)] .

    Or try this

     void iGetMyInfos([Out, MarshalAs(UnmanagedType.LPArray)] out MyInfos[] infos);


    jdweng

    Tuesday, October 29, 2013 1:23 PM
  • Thanks a lot.

    It works with LPArray.

    It also works if I use IntPtr and Marshal.PtrToStructure.

    Tuesday, October 29, 2013 1:32 PM