将非托管结构转换为C#

时间:2014-10-08 09:51:19

标签: c#

首先,我是C#的全新(如在1-2周内)。我正在尝试将WinDivert方法包装在C#中使用,并且我一直在混合成功和失败。虽然我不确定,但我相信我已经把这个问题缩小到一个错位(字面上),在非托管代码中如何定义某些结构以及如何在C#中定义它们,因为(据我所知)a C#的限制。

来自https://github.com/basil00/Divert/blob/master/include/windivert.h

的示例
typedef struct
{
    UINT8  HdrLength:4;
    UINT8  Version:4;
    UINT8  TOS;
    UINT16 Length;
    UINT16 Id;
    UINT16 FragOff0;
    UINT8  TTL;
    UINT8  Protocol;
    UINT16 Checksum;
    UINT32 SrcAddr;
    UINT32 DstAddr;
} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR;

这是我遇到问题翻译的结构之一。如您所见,HdrLength和Version被定义为每个占用4位结构。在C#版本中,我尝试简单地声明字节HdrLengthAndVersion,我尝试将布局更改为明确,并手动定义成员的位置,以便它们在这样的情况下重叠,以确保相同的内存长度和位置等。一些其他更大的结构变得特别复杂。

我很好奇是否有任何方法可以正确地将其转换为C#?我也很好奇这是否可能,或者它是否会成为不同架构的问题。我知道我们正在进入内存对齐,填充等,我承认这是一个主题,我不是专家,这就是为什么我在这里:)。

作为第二种选择,我正在考虑只做一些无效指针(因为托管的东西分配并使用这些对象)并且只是移动位置然后键入将指针转换回我实际需要访问的特定值。但同样,不确定这是否可能。

也只是为了提及,我尝试过SWIG。没有用,我在尝试使用它时遇到了998个ERROR_NOACCESS错误,所以,只是一大堆类,我没有写出更多的问题。

1 个答案:

答案 0 :(得分:3)

由于FieldOffsetAttribute接受以字节为单位的偏移量,您可以将HdrLengthVersion的偏移量设置为0,并添加将返回正确值的辅助属性每个字段使用位移。

例如:

[StructLayout(LayoutKind.Explicit)]
struct WINDIVERT_IPHDR
{
    [FieldOffset(0)]
    private byte hdrLength;

    [FieldOffset(0)]
    private byte version;

    [FieldOffset(1)]
    private byte tos;
    ...

    public byte HdrLength
    {
        get { return (byte)(hdrLength & 0xF); }
    }

    public byte Version
    {
        get { return (byte)(version >> 4); }
    }

    public byte TOS { get { return tos; } }
    ...
}

请注意,由于您使用的是LayoutKind.Explicit,因此您必须为所有结构字段定义FieldOffset