Перевод неуправляемой структуры в C #

1

Во-первых, я совершенно новый (как через 1-2 недели) на С#. Я пытаюсь использовать методы WinDivert для использования внутри С#, и у меня был смешанный успех и неудача. Хотя я не уверен, я считаю, что я сузил проблему до несогласованности (буквально) между тем, как определенные структуры определены в неуправляемом коде и как они определены на С#, из-за (насколько мне известно) ограничение С#.

И пример из 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 бита каждой структуры. В версии С# я пробовал просто объявить байт HdrLengthAndVersion, я попытался изменить макет на простоту и вручную определить положение элементов, чтобы они перекрывались в таких случаях, чтобы обеспечить одинаковые длины и позицию памяти и т.д. Это становится чрезвычайно сложным с некоторыми другими, большими структурами.

Мне любопытно, есть ли способ правильно перевести это на С#? Мне также интересно, возможно ли это, или это будет проблемой для разных архитектур. Я знаю, что мы входим в выравнивание памяти, заполнение и т.д. Здесь, которые, я признаю, в настоящее время являются темой, в которой я меньше, чем эксперт, поэтому я здесь :).

В качестве второго варианта я рассматриваю возможность просто сделать некоторые указатели void (поскольку управляемый материал выделяет и работает с этими объектами) и просто сдвигая позицию, затем набирайте указатель обратно на определенные значения, которые мне действительно нужны для доступа. Но опять же, не уверен, что это возможно.

Также просто для того, чтобы упомянуть, я попробовал SWIG. Не работает, я получаю ошибки 998 ERROR_NOACCESS при попытке использовать его так, просто огромная куча классов, с которыми я не писал с большим количеством проблем.

  • 2
    Посмотрите на класс StructLayoutAttribute в C #
  • 0
    Да, попробуйте использовать StructLayoutAttribute с LayoutKind.Explicit и установите FieldOffsetAttribute для каждого поля структуры.
Показать ещё 4 комментария
Теги:

1 ответ

3
Лучший ответ

Поскольку FieldOffsetAttribute принимает смещение в байтах, вы можете установить HdrLength и Version на 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 для всех структурных полей.

  • 1
    Это кажется излишне сложным. Почему бы просто не иметь один private byte hdrLengthAndVersion; , используется в свойствах HdrLength и Version ? Это также позволило бы избежать необходимости явно указывать смещения полей.
  • 0
    @hvd, согласен. Я думаю, что эта версия чуть более читабельна. Но ваше предложение определенно здорово.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню