У меня есть следующая структура, что я пытаюсь выстроить в C#:Marshalling String (но не Byte Array) Внутри Struct Причины AccessViolationException
- Длина (4 байта)
- версии (4 байта)
- MachineID (16 байт)
проблема у меня является получение MachineID
как string
в C#. В структуре я указываю [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 24)]
наверху и [MarshalAs(UnmanagedType.LPStr, SizeConst = 16)]
для MachineID
. Но когда я это делаю, я получаю System.AccessViolationException
.
Если я меняю MachineID
на byte[]
и указываю [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
, он отлично работает.
Ниже приведен код, который работает с byte[]
, но не string
. Форма MachineID
в форме ASCII составляет ABCDEFGHIJKLMNO
.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
public class Test
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 24)]
struct Valid
{
public uint Length;
public uint Version;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] MachineId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 24)]
struct Invalid
{
public uint Length;
public uint Version;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 16)]
public string MachineId;
}
public static void Main()
{
var bytes = new byte[]
{
0x58, 0, 0, 0,
0, 0, 0, 0,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0
};
var pinnedBuffer = GCHandle.Alloc(bytes, GCHandleType.Pinned);
var ptr = pinnedBuffer.AddrOfPinnedObject();
// Works!
Debug.Assert(bytes.Length == Marshal.SizeOf<Valid>());
var trackerData1 = Marshal.PtrToStructure<Valid>(ptr);
Console.WriteLine("Length: {0}", trackerData1.Length);
Console.WriteLine("Version: {0}", trackerData1.Version);
Console.WriteLine("MachineId: {0}", Encoding.ASCII.GetString(trackerData1.MachineId));
// Doesnt work!
Debug.Assert(bytes.Length == Marshal.SizeOf<Invalid>());
// Throws System.AccessViolationException
var trackerData2 = Marshal.PtrToStructure<Invalid>(ptr);
Console.WriteLine("Length: {0}", trackerData2.Length);
Console.WriteLine("Version: {0}", trackerData2.Version);
Console.WriteLine("MachineId: {0}", trackerData2.MachineId);
pinnedBuffer.Free();
Console.In.ReadLine();
}
}
Если вас run this code in IDEOne, вы увидите, что он бросает System.AccessViolationException
, когда он пытается выстроить в string
, и это не только мой компьютер.
Что мне любопытно, почему это работает для байтового массива, но не для строки?