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(General))を実行すると、ArgumentExceptionが発生します。サイズやオフセットは計算できません。

同じクラスでプライベート変数とパブリックプロパティを使用する場合、問題はありますか?プロパティは、変数をより便利なものに変換するためだけのものです。(バイト配列から文字列へ)

Marshal.PtrToStructureを使用してバイト配列をクラスに配置できるようにするにはどうすればよいですか?

4

1 に答える 1

2

私にとってはうまくいきます.2 * 21 + 1に一致する43を取得します。

いいえ、プロパティは問題ではありません。マーシャル コードはフィールドのみを見ています。


編集:ただし、何起こるかは、データが一致しないことです:

埋め込み配列インスタンスの長さがレイアウトで宣言された長さと一致しないため、型をマーシャリングできませんでした。

配列が正しい長さであることを確認する必要があります - 以下は醜いですが、ある程度機能します (長すぎる文字列を設定しないでください!):

[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
}
于 2012-11-16T12:55:11.793 に答える