2017-01-08 76 views
0

我有我想要在C#編組結構如下:編組字符串(而不是字節數組)的內部結構導致AccessViolationException

  • 長度(4個字節)
  • 版本(4個字節)
  • 機號(16個字節)

我有越來越的MachineID如在C#string問題。在結構中,我在頂部指定[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Size = 24)],在MachineID指定[MarshalAs(UnmanagedType.LPStr, SizeConst = 16)]。但是當我這樣做時,我得到了System.AccessViolationException被拋出。

如果我將MachineID更改爲byte[]並指定[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]它工作正常。

下面是代碼與byte[],但不是string。 ASCII形式的MachineIDABCDEFGHIJKLMNO

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

你需要元帥它作爲ByValTStr此工作:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 
public string MachineId; 

這裏的the example