将嵌套结构编组到C#

时间:2013-11-27 15:28:29

标签: c# structure marshalling

我们有COM服务器(作为dll,我们只有dll文件),它实现了两个COM接口。其中一个接口允许我们从某个设备获取消息(作为结构)。根据消息,我们需要处理相应的结构。每个结构都指向结构 VARIANT 。此结构的类型为字节数组(VT_ARRAY | VT_UI1)

所有结构都包含结构Header和其他一些信息。结构Header包含字段MsgId。根据{{​​1}},我们需要处理其他结构。

为了从dll到c#获取结构,我们使用反射。

现在,是时候了:

MsgId

我们每100毫秒通过反射从设备获取数据:

// 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;
}

然后我们将 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结构,我们使用C# array within a struct中提出的方法(进行一些编辑):

Header

我们如何使用一个:

 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

这里我们得到例外:无法编组“Main”类型的字段“h”。托管/非托管类型组合无效(此值类型必须与Struct配对)

我们尝试将内部结构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; } } 的{​​{1}}声明更改为

MarshalAsAttribute

h

但它不起作用。如果可能,我们如何从[MarshalAsAttribute(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_SAFEARRAY)]结构中获取数据?

1 个答案:

答案 0 :(得分:-2)

字节通过BinaryReading读取是我现在的解决方案。一切都很好。谢谢大家!