将嵌套结构编组到C# [英] Marshalling nested structs to C#

查看:93
本文介绍了将嵌套结构编组到C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 VARIANT. This structure is of type byte array (VT_ARRAY | VT_UI1).

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

All structures contains structure Header and some other information. Structure Header contains field MsgId. Depending on MsgId we need to process other structures.

为了将结构从dll转换为c#,我们使用反射.

In order to get structures from dll to c# we use reflection.

现在是时候了:

// 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毫秒,我们通过反射从设备获取数据:

Every 100 ms we get data from device via reflection:

   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[],然后需要将字节数组转换为结构.在这个地方,封送处理存在一些问题.

Then we cast our msg as byte[] and then we need to convert array of bytes into our struct. At this place we have some problem with marshaling.

正如我写的那样,为了定义我们需要处理的结构(换句话说,我们需要封送),首先,我们需要封送包含在所有结构中的Header结构( 来自设备的所有邮件中的另外一个字).

As i have wrote in order to define which structure we need to process (another words we need to marshaling) first of all we need to marshal Header structure that is contained in all structures (another words in all messages from device).

为了封送Header结构,我们使用一个结构(进行一些编辑):

In order to marshal Header struct we use the method proposed in C# array within a struct (with some editing):

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

一切都OK!在这里,我们得到msgHeader.MsgId,然后我们需要获得另一个结构:

Everything is OK! Here we get msgHeader.MsgId and then we need to get another structure:

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配对)

Here we get exception: Cannot marshal field 'h' of type 'Main'. Invalid managed/unmanaged type combination (this value type must be paired with Struct)

我们试图将内部结构hMarshalAsAttribute声明更改为

We have tried to change MarshalAsAttribute declaration of inner struct h to

[MarshalAsAttribute(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_SAFEARRAY)]

[MarshalAsAttribute (UnmanagedType.SafeArray, SafeArrayUserDefinedSubType=typeof(Header))]

,但是它不起作用.如果可能的话,我们如何从Main结构中获取数据?

but it does not work. How can we get data from Main strucure if it is possible?

推荐答案

逐字节是我的解决方案.一切正常.谢谢大家!

Byte by byte reading via BinaryReading is my solution now. Everything work fine. Thanks to everyone!

这篇关于将嵌套结构编组到C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆