[英]Marshalling nested structs to C#
我們有COM服務器(作為dll,我們只有dll文件),它實現了兩個COM接口。 接口之一允許我們從某些設備獲取消息(作為結構)。 根據消息,我們需要處理相應的結構。 每個結構都指向結構VARIANT的指針。 此結構的類型為字節數組(VT_ARRAY | VT_UI1) 。
所有結構都包含結構Header
和其他一些信息。 結構Header
包含字段MsgId
。 根據MsgId
我們需要處理其他結構。
為了將結構從dll轉換為c#,我們使用反射。
現在是時候了:
// 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;
}
每隔100毫秒,我們就會通過反射從設備獲取數據:
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;
}
然后我們將msg
為byte[]
,然后需要將字節數組轉換為結構。 在這個地方,封送處理有些問題。
正如我寫的那樣,為了定義我們需要處理的結構(換句話說, 我們需要封送處理 ),首先,我們需要整理所有結構中包含的Header
結構(換句話說,來自device的所有消息中的字形 )。
為了編組Header
結構,我們使用結構中的C#數組中建議的方法(進行一些編輯):
public static T DeserializeMsg<T>(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;
}
我們如何使用一個:
private void ProcessMessage(byte[] message)
{
Header msgHeader = new Header();
msgHeader = DeserializeMsg<Header>(message);
}
一切都好! 在這里,我們得到msgHeader.MsgId
,然后我們需要得到另一個結構:
private void ProcessMessage(byte[] message)
{
Header msgHeader = new Header();
msgHeader = DeserializeMsg<Header>(message);
switch (msgHeader.MsgId)
{
case START:
Main msgMain = new Main();
// Here we get exception (see below)
msgMain = DeserializeMsg<Main>(message);
break;
default:
break;
}
}
在這里,我們得到了例外: 無法封送類型為“ Main”的字段“ h”。 無效的托管/非托管類型組合(此值類型必須與Struct配對)
我們試圖將內部結構h
MarshalAsAttribute
聲明更改為
[MarshalAsAttribute(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_SAFEARRAY)]
和
[MarshalAsAttribute (UnmanagedType.SafeArray, SafeArrayUserDefinedSubType=typeof(Header))]
但它不起作用。 如果可能的話,我們如何從Main
結構中獲取數據?
現在,通過BinaryReading
逐字節讀取是我的解決方案。 一切正常。 謝謝大家!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.