Во-первых, я совершенно новый (как через 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 при попытке использовать его так, просто огромная куча классов, с которыми я не писал с большим количеством проблем.
Поскольку 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
для всех структурных полей.
private byte hdrLengthAndVersion;
, используется в свойствах HdrLength
и Version
? Это также позволило бы избежать необходимости явно указывать смещения полей.
StructLayoutAttribute
сLayoutKind.Explicit
и установитеFieldOffsetAttribute
для каждого поля структуры.