Answered by:
Marshal an allocated struct from COM C++ to C#

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.
- Edited by John Silverdear Tuesday, October 29, 2013 11:16 AM
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
- Marked as answer by John Silverdear Tuesday, October 29, 2013 1:32 PM
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
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; }
- Edited by John Silverdear Tuesday, October 29, 2013 1:08 PM
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
- Marked as answer by John Silverdear Tuesday, October 29, 2013 1:32 PM
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