我有以下结构,我试图在C#编组:
我遇到的问题是在C#中将MachineID
作为string
。在结构中,我在顶部指定[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
。 ASCII格式的MachineID
为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
。
我很好奇为什么它适用于字节数组而不是字符串?
答案 0 :(得分:0)
您需要将其整理为ByValTStr
才能实现此目的:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string MachineId;
此处the example
。