время для другого от вопроса о стене. Я пишу загрузчик MD2 для своего маленького 3D проекта механизма. На моем старом языке (C) я мог определить структуру и затем читать () из открытого файла непосредственно в структуру. У меня есть структура для содержания информации заголовка из файла MD2, следующим образом:
[StructLayout(LayoutKind.Sequential)]
public struct MD2_Header
{
public int FourCC;
public int Version;
public int TextureWidth;
public int TextureHeight;
public int FrameSizeInBytes;
public int NbrTextures;
public int NbrVertices;
public int NbrTextureCoords;
public int NbrTriangles;
public int NbrOpenGLCmds;
public int NbrFrames;
public int TextureOffset;
public int TexCoordOffset;
public int TriangleOffset;
public int FrameOffset;
public int OpenGLCmdOffset;
public int EndOffset;
}
В моем коде читателя я хотел бы сделать что-то как:
// Suck the MD2 header into a structure, it is 68 bytes long.
Classic.Util.MD2_Header md2hdr = new Classic.Util.MD2_Header();
md2hdr = reader.ReadBytes(sizeof(Classic.Util.MD2_Header));
Я понимаю, что это не корректно, поскольку это повреждает безопасность типов несколько странно, но Вы получаете идею того, что я хочу выполнить. Я мог сделать это с отдельными вызовами читателю. ReadInt32 (), но мне любопытно, если там должен так или иначе заставить это прокладывать себе путь, я желаю использовать нормальные вызовы библиотеки.
Я немного изучил Маршала. Копия () метод, но это, кажется, для движения между управляемой и неуправляемой памятью, которая не является действительно, что я делаю здесь.
Какие-либо предложения?
Структура в C и структура в C# - это две совершенно разные вещи. Структура в C используется как для типов значений, так и для ссылочных типов, а структура в C# используется только для типов значений.
Тип значения должен представлять одно значение, но у вас много значений, поэтому вместо него следует использовать класс. Рекомендуемый максимальный размер структуры в .NET - 16 байт, а у вас в четыре раза больше данных.
Класс со свойствами и конструктором, принимающим байтовый массив, будет выглядеть так:
public class MD2_Header {
public int FourCC { get; set; }
public int Version { get; set; };
public int TextureWidth { get; set; };
public int TextureHeight { get; set; };
public int FrameSizeInBytes { get; set; };
public int NbrTextures { get; set; };
public int NbrVertices { get; set; };
public int NbrTextureCoords { get; set; };
public int NbrTriangles { get; set; };
public int NbrOpenGLCmds { get; set; };
public int NbrFrames { get; set; };
public int TextureOffset { get; set; };
public int TexCoordOffset { get; set; };
public int TriangleOffset { get; set; };
public int FrameOffset { get; set; };
public int OpenGLCmdOffset { get; set; };
public int EndOffset { get; set; };
public MD2_Header(byte[] values) {
FourCC = BitConverter.ToInt32(values, 0);
Version = BitConverter.ToInt32(values, 4);
TextureWidth = BitConverter.ToInt32(values, 8);
TextureHeight = BitConverter.ToInt32(values, 12);
FrameSizeInBytes = BitConverter.ToInt32(values, 16);
NbrTextures = BitConverter.ToInt32(values, 20);
NbrVertices = BitConverter.ToInt32(values, 24);
NbrTextureCoords = BitConverter.ToInt32(values, 28);
NbrTriangels = BitConverter.ToInt32(values, 32);
NbrOpenGLCmds = BitConverter.ToInt32(values, 36);
NbrFrames = BitConverter.ToInt32(values, 40);
TextureOffset = BitConverter.ToInt32(values, 44);
TexCoordOffset = BitConverter.ToInt32(values, 48);
TriangleOffset = BitConverter.ToInt32(values, 52);
FrameOffset = BitConverter.ToInt32(values, 56);
OpenGLCmdOffset = BitConverter.ToInt32(values, 60);
EndOffset = BitConverter.ToInt32(values, 64);
}
}
Я знаю, что у вас уже есть ответ, и это хороший ответ.
Я подумал, что вы можете получить некоторую ценность от сообщения в блоге, которое я сделал по некоторым опциям, доступным в .NET, чтобы достичь этого.
И соответствующий пост для обратного
Для обработки копирования можно использовать маршалинг. Нет необходимости писать код для его обработки.
//create object
Classic.Util.MD2_Header md2hdr = new Classic.Util.MD2_Header();
Classic.Util.MD2_Header another = new Classic.Util.MD2_Header();
byte[] mem = new byte[Marshal.SizeOf(typeof(MD2_Header))];
//allocate unmanaged memory
IntPtr hmem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Classic.Util.MD2_Header)));
//copy structure to unmanaged memory
Marshal.StructureToPtr(md2hdr, hmem, false);
//copy to managed memory
Marshal.Copy(hmem, mem, 0, mem.Length);
//copy unmanaged memory to structure
another = (Classic.Util.MD2_Header)Marshal.PtrToStructure(hmem, typeof(Classic.Util.MD2_Header));
//free unmanaged memory
Marshal.FreeHGlobal(hmem);
Это может быть немного сложным в C #, но вы можете настроить вещи, в которых вы можете скопировать байты из байтового массива в структуру.
Прочтите поток байтов в массив байтов, назовите его пакет
и попробуйте следующее:
GCHandle pinned = GCHandle.Alloc(packet, GCHandleType.Pinned);
MD2_Header h = (MD2_Header)Marshal.PtrToStructure(pinned.AddrOfPinnedObject(), typeof(MD2_Header));
pinned.Free();
Что вы можете сделать, так это прочитать байты в буфер подходящего размера, используйте fixed (int * = & md2hdr.FourCC)
, чтобы получить указатель на в начале вашей структуры, переведите указатель на вашу структуру на байт *
и скопируйте байты вручную.
Вы можете использовать Marshal.PtrToStructure для копирования из указателя прямо в вашу структуру одним выстрелом. Автор
byte[] data = reader.ReadBytes(...);
fixed (byte* bytes = data)
{
Classic.Util.MD2_Header md2hdr =
(Classic.Util.MD2_Header)Marshal.PtrToStructure(
Marshal.UnsafeAddrOfPinnedArrayElement(data, 0),
typeof(Classic.Util.MD2_Header)
);
}