2012-11-16 50 views
1

我有一個字節數組轉換爲類或結構的問題。 類是這樣的:類的大小錯誤

[Serializable()] 
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] 
public class General { 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = Defines.CENTR_NAME_LENGTH + 1)] byte[] centralName; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = Defines.PROJECT_NAME_LENGTH + 1)] byte[] projectName; 
    byte misc; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] byte[] accessCode2; 
    byte transmActive; 
    byte transmHour; 
    byte transmMin; 
    [MarshalAs(UnmanagedType.U1)] public int Cp; 
    [MarshalAs(UnmanagedType.U1)] public int Rp; 
    [MarshalAs(UnmanagedType.U1)] public int Lcd; 
    [MarshalAs(UnmanagedType.U1)] public int Relais; 
    [MarshalAs(UnmanagedType.U1)] public int Pr; 
    [MarshalAs(UnmanagedType.U1)] public int Sc; 
    byte rd; 
    byte reserve1; 
    [MarshalAs(UnmanagedType.U1)] public int LocalCentrId; 
    [MarshalAs(UnmanagedType.U1)] public int PrinterSel; 
    [MarshalAs(UnmanagedType.U1)] public int Slave1; 
    [MarshalAs(UnmanagedType.U1)] public int Slave2; 
    [MarshalAs(UnmanagedType.U1)] public int Slave3; 
    [MarshalAs(UnmanagedType.U1)] public int Master; 
    [MarshalAs(UnmanagedType.U1)] public int AlarmRepeat; 
    [MarshalAs(UnmanagedType.U1)] public int FaultRepeat; 
    [MarshalAs(UnmanagedType.U1)] public int ResetSil1; 
    [MarshalAs(UnmanagedType.U1)] public int ResetSil2; 
    [MarshalAs(UnmanagedType.U1)] public int EvacDelayed1; 
    [MarshalAs(UnmanagedType.U1)] public int EvacDelayed2; 
    [MarshalAs(UnmanagedType.U1)] public int Led1; 
    [MarshalAs(UnmanagedType.U1)] public int Led2; 
    [MarshalAs(UnmanagedType.U1)] public int GenControl; 
    [MarshalAs(UnmanagedType.U1)] public int ExtraGenControl; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = Defines.MAX_NMB_SIL_CONTROL)] byte[] silenceControls ; 
    byte autoResetFault; 
    byte autoResetSC; 
    [MarshalAs(UnmanagedType.U1)] public int InitEvacDelay; 
    [MarshalAs(UnmanagedType.U1)] public int SilenceEvacOff; 
    byte summerTime; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] byte[] accessCode1; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] byte[] btPinCode; 

    public string CentralName { get { return Encoding.ASCII.GetString(centralName); } set { centralName = Encoding.ASCII.GetBytes(value); } } 
    public string ProjectName { get { return Encoding.ASCII.GetString(projectName); } set { projectName = Encoding.ASCII.GetBytes(value); } } 
    public bool BackBeep { 
     get { 
      return (misc & 0x01) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x01; 
      } else { 
       misc ^= 0x01; 
      } 
     } 
    } 
    public bool StartStopEvac { 
     get { 
      return (misc & 0x02) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x02; 
      } else { 
       misc ^= 0x02; 
      } 
     } 
    } 
    public bool GenBehEvacKey { 
     get { 
      return (misc & 0x04) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x04; 
      } else { 
       misc ^= 0x04; 
      } 
     } 
    } 
    public bool GenBehEvacDet { 
     get { 
      return (misc & 0x08) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x08; 
      } else { 
       misc ^= 0x08; 
      } 
     } 
    } 
    public bool EvacDelayed { 
     get { 
      return (misc & 0x10) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x10; 
      } else { 
       misc ^= 0x10; 
      } 
     } 
    } 
    public bool SirService { 
     get { 
      return (misc & 0x20) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x20; 
      } else { 
       misc ^= 0x20; 
      } 
     } 
    } 
    public bool ResetSilService { 
     get { 
      return (misc & 0x40) != 0x00; 
     } 
     set { 
      if (value) { 
       misc |= 0x40; 
      } else { 
       misc ^= 0x40; 
      } 
     } 
    } 
    public string AccessCode1 { get { return Encoding.ASCII.GetString(accessCode1); } set { accessCode1 = Encoding.ASCII.GetBytes(value); } } 
    public string AccessCode2 { get { return Encoding.ASCII.GetString(accessCode2); } set { accessCode2 = Encoding.ASCII.GetBytes(value); } } 
    public bool EvacDirect { get { return transmActive == 0x01; } set { transmActive = (Byte)(value ? 0x01 : 0x00); } } 
    public TimeSpan EvacDirectTime { get { return new TimeSpan(transmHour, transmMin, 0); } set { transmHour = (Byte)value.Hours; transmMin = (Byte)value.Minutes; } } 
    public bool Rd { get { return rd == 0x01; } set { rd = (value ? (Byte)0x01 : (Byte)0x00); } } 
    public List<int> SilenceControl { 
     get { 
      List<int> retVal = new List<int>(); 
      if (silenceControls != null) { 
       foreach (byte b in silenceControls) { 
        retVal.Add(b); 
       } 
      } 
      return retVal; 
     } 
     set { 
      silenceControls = new byte[Defines.MAX_NMB_SIL_CONTROL]; 
      for (int t = 0; t < Defines.MAX_NMB_SIL_CONTROL && t < value.Count; ++t) { 
       silenceControls[t] = (Byte)value[t]; 
      } 
     } 
    } 
    public bool AutoResetFault { get { return autoResetFault == 0x01; } set { autoResetFault = (Byte)(value ? 0x01 : 0x00); } } 
    public bool AutoResetPower { get { return autoResetSC == 0x01; } set { autoResetSC = (Byte)(value ? 0x01 : 0x00); } } 
    public bool SummerTime { get { return summerTime == 0x01; } set { summerTime = (Byte)(value ? 0x01 : 0x00); } } 
    public string BtPinCode { get { return Encoding.ASCII.GetString(btPinCode); } set { btPinCode = Encoding.ASCII.GetBytes(value); } } 

    public General() { 
     Console.WriteLine("Create General"); 
     SetDefault(); 
    } 

    public void SetDefault() { 
     CentralName = "MD2400"; 
     ProjectName = "Limotec"; 
     Cp = 1; 
     Rp = 0; 
     Lcd = 0; 
     Relais = 1; 
     Pr = 0; 
     Sc = 1; 
     Rd = true; 
     BackBeep = false; 
     AccessCode1 = "654321"; 
     AccessCode2 = "123456"; 
     EvacDirect = false; 
     EvacDirectTime = new TimeSpan(0, 0, 0); 
     BtPinCode = "1111111111111111"; 
     SummerTime = true; 
     GenControl = 1; 
     ExtraGenControl = 0; 
     SilenceControl.Add(3); 
     InitEvacDelay = 2; 
     EvacDelayed = false; 
     StartStopEvac = false; 
     SirService = false; 
     ResetSilService = false; 
     GenBehEvacKey = true; 
     GenBehEvacDet = true; 
     Master = 32; 
     Slave1 = 0; 
     Slave2 = 0; 
     Slave3 = 0; 
     AlarmRepeat = 0; 
     FaultRepeat = 0; 
     ResetSil1 = 0; 
     ResetSil2 = 0; 
     Led1 = 0; 
     Led2 = 0; 
     EvacDelayed1 = 0; 
     EvacDelayed2 = 0; 
     LocalCentrId = 0; 
     AutoResetFault = true; 
     AutoResetPower = true; 
    } 

    [OnDeserialized()] 
    internal void OnDeserialized(StreamingContext contect) { 
     Config.Singleton.Log.Info(string.Format("General loaded: {0} {1}", CentralName, ProjectName)); 
    } 
} 

當我做Marshall.SizeOf(typeof運算(一般))我得到一個ArgumentException。大小或偏移無法計算。

如果我在同一個類中使用私有變量和公共屬性,是否有問題?這些屬性僅用於將變量轉換爲更有用的變量。 (字節數組到字符串)

我該如何解決它,以便我可以使用Marshal.PtrToStructure將一個字節數組放入類中?

回答

2

對我來說,它只是工作:我得到43,它符合2 * 21 + 1.我檢查了.NET 2.0,3.5和4.5(和4.5我檢查了x86和x64) - 它似乎很好。

不,屬性不重要:編組代碼只查看字段。


編輯:什麼發生,不過,是該數據不匹配:

類型不能被封是因爲嵌入數組實例的長度不符合申報佈局中的長度。

你需要確保的陣列是正確的長度 - 以下是醜陋的,但作品,有點-:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)] 
byte[] centralName = new byte[21]; 
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)] 
byte[] projectName = new byte[21]; 
byte misc; 

public string CentralName { 
    get { 
     int i = Array.IndexOf(centralName, (byte)0); 
     if (i < 0) i = centralName.Length; 
     return Encoding.ASCII.GetString(centralName, 0, i); 
    } 
    set { 
     Array.Clear(centralName, 0, centralName.Length); 
     Encoding.ASCII.GetBytes(value, 0, value.Length, centralName, 0); 
    } } 
public string ProjectName { 
    get { 
     int i = Array.IndexOf(projectName, (byte)0); 
     if (i < 0) i = projectName.Length; 
     return Encoding.ASCII.GetString(projectName, 0, i); 
    } 
    set { 
     Array.Clear(projectName, 0, projectName.Length); 
     Encoding.ASCII.GetBytes(value, 0, value.Length, projectName, 0); 
    } } 

用(不設置超長字符串!)例如:

unsafe static void Main() 
{ 
    int i = Marshal.SizeOf(typeof(General)); 
    General obj = new General { CentralName = "abc", ProjectName = "def" }, 
      clone; 
    byte[] b = new byte[i]; 
    fixed(byte* a = b) 
    { 
     IntPtr ptr= new IntPtr(a); 
     Marshal.StructureToPtr(obj, ptr, false); 
     clone = (General) Marshal.PtrToStructure(ptr, typeof(General)); 
    } 
    Console.WriteLine(clone.CentralName); // abc 
    Console.WriteLine(clone.ProjectName); // def 
} 

或:

unsafe static void Main() 
{ 
    int i = Marshal.SizeOf(typeof(General)); 
    General obj = new General { CentralName = "abc", ProjectName = "def" }, 
      clone; 
    byte* a = stackalloc byte[i]; 

    IntPtr ptr= new IntPtr(a); 
    Marshal.StructureToPtr(obj, ptr, false); 
    clone = (General) Marshal.PtrToStructure(ptr, typeof(General)); 

    Console.WriteLine(clone.CentralName); // abc 
    Console.WriteLine(clone.ProjectName); // def 
} 
+0

它似乎與小班I p工作而不是全班。我編輯了我的文章,並把完整的課程放在裏面。你可以嘗試一下嗎? – Calypoter

+1

@Calypoter嘗試過;證實它不起作用;建議你把它剝下來,直到它工作,然後逐漸重新添加它們直到它破裂,所以你知道問題出在哪裏 –

+0

我發現它。看來[MarshalAs(UnmanagedType.U1)]是錯誤。我刪除了所有這些行,並將int更改爲字節。現在它正在工作。感謝Marc的幫助。 – Calypoter