Note that there are some explanatory texts on larger screens.

plurals
  1. POMarshalling nested structs to C#
    primarykey
    data
    text
    <p>We have COM Server (as dll, we have only dll file), that implements two COM interfaces. One of interfaces allows us to get messages (as structure) from some device. Depending on message we need to process corresponding structure. Every structure is pointer to a structure <strong>VARIANT</strong>. This structure is of type byte array <strong>(VT_ARRAY | VT_UI1)</strong>. </p> <p>All structures contains structure <code>Header</code> and some other information. Structure <code>Header</code> contains field <code>MsgId</code>. Depending on <code>MsgId</code> we need to process other structures.</p> <p>In order to get structures from dll to c# we use reflection. </p> <p>Now, it's time for example:</p> <pre><code>// Header (sub-struct of main struct) - [StructLayout(LayoutKind.Sequential)] public struct Header { public int MsgId; } // main struct [StructLayout(LayoutKind.Sequential)] public struct Main { [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct)] public Header h; public int count; } </code></pre> <p>Every 100 ms we get data from device via reflection:</p> <pre><code> private bool ReadMessage(ref object msg) { object _msg = null; object[] args = new Object[] { _msg }; ParameterModifier byRefParamMod = new ParameterModifier(1); byRefParamMod[0] = true; ParameterModifier[] pmArray = { byRefParamMod }; var value = SomeWrapper.CallMethod(ClientInstance, "ReadMessage", args, pmArray); msg = args[0]; return ((int)value == S_OK) ? true : false; } </code></pre> <p>Then we cast our <code>msg</code> as <code>byte[]</code> and then we need to convert array of bytes into our struct. At this place we have some problem with marshaling.</p> <p>As i have wrote in order to define which structure we need to process (another words <strong>we need to marshaling</strong>) first of all we need to marshal <code>Header</code> structure that is contained in all structures (another words <strong>in all messages from device</strong>).</p> <p>In order to marshal <code>Header</code> struct we use the method proposed in <a href="https://stackoverflow.com/questions/8704161/c-sharp-array-within-a-struct">C# array within a struct</a> (with some editing):</p> <pre><code> public static T DeserializeMsg&lt;T&gt;(byte[] msg) where T : struct { // Pin the managed memory while, copy it out the data, then unpin it GCHandle handle = GCHandle.Alloc(msg, GCHandleType.Pinned); T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); handle.Free(); return theStructure; } </code></pre> <p>How we are using one:</p> <pre><code> private void ProcessMessage(byte[] message) { Header msgHeader = new Header(); msgHeader = DeserializeMsg&lt;Header&gt;(message); } </code></pre> <p>Everything is OK! Here we get <code>msgHeader.MsgId</code> and then we need to get another structure:</p> <pre><code>private void ProcessMessage(byte[] message) { Header msgHeader = new Header(); msgHeader = DeserializeMsg&lt;Header&gt;(message); switch (msgHeader.MsgId) { case START: Main msgMain = new Main(); // Here we get exception (see below) msgMain = DeserializeMsg&lt;Main&gt;(message); break; default: break; } } </code></pre> <p>Here we get exception: <strong>Cannot marshal field 'h' of type 'Main'. Invalid managed/unmanaged type combination (this value type must be paired with Struct)</strong></p> <p>We have tried to change <code>MarshalAsAttribute</code> declaration of inner struct <code>h</code> to </p> <p><code>[MarshalAsAttribute(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_SAFEARRAY)]</code> </p> <p>and</p> <p><code>[MarshalAsAttribute (UnmanagedType.SafeArray, SafeArrayUserDefinedSubType=typeof(Header))]</code></p> <p>but it does not work. How can we get data from <code>Main</code> strucure if it is possible?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload