正在将非托管结构转换为C#

本文关键字:结构 转换 | 更新日期: 2023-09-27 18:25:58

首先,我是C#的新手(在中的1-2周内)。我正在尝试将WinDivert方法封装在C#中使用,我的成功和失败喜忧参半。虽然我不确定,但我相信我已经将问题缩小到了非托管代码中某些结构的定义方式与C#中它们的定义方式之间的错位(字面上),这是由于(据我所知)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错误,所以,只是一大堆我没有写的类出现了更多问题。

正在将非托管结构转换为C#

由于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