C#非管理メモリの応用(二)―構造体コピー


構造体の変換は実は基礎タイプの配列の変換とあまり差がないが、構造体はMarshalを通過できない.Copy方式でメモリに直接変換します.構造体痛byte配列の相互回転は,ネットワーク通信に直接用いるのに非常に便利である.
1、構造体を定義する
/// <summary>
   ///  Copy
   /// </summary>
   public struct TestStruct
   {
       public string Number;
       public int[] IntMember;
       public byte ByteMember;
       public short ShortMember;
       public override  string ToString()
       {
           return string.Format("Number:" + Number + " ByteMember:" + ByteMember + " ShortMember:" + ShortMember + " IntMemberCount:" + IntMember.Length);
       }
   }

2、Copy構造体がbyte配列になる方法
/// <summary>
       ///  Copy byte 
       /// </summary>
       /// <param name="structObj"> </param>
       /// <param name="targetData"> byte , Marshal.SizeOf(structObj)</param>
       public static void CopyMemFromStruct(object structObj, byte[] targetData)
       {
           IntPtr tmptr = IntPtr.Zero;
           try
           {
               int size = Marshal.SizeOf(structObj); //  
               tmptr = Marshal.AllocHGlobal(size); //  
               Marshal.StructureToPtr(structObj, tmptr, false); //Copy 
               Marshal.Copy(tmptr, targetData, 0, size);
               Marshal.FreeHGlobal(tmptr);
           }
           catch(Exception ex)
           {
               if (tmptr != IntPtr.Zero)
                   Marshal.FreeHGlobal(tmptr);
               throw new Exception(" :" + ex.ToString());
           }
       }

3、byte配列Copyの構造体形成方法
/// <summary>
       ///  byte 
       /// </summary>
       /// <param name="sourceData"></param>
       /// <param name="startIndex"></param>
       /// <param name="length"></param>
       /// <param name="objectRef"></param>
       /// <param name="type"></param>
       public static void CopyMemFromBytes(byte [] sourceData, int startIndex, int length, ref object objectRef, Type type)
       {
           IntPtr tmptr = IntPtr.Zero;
           try
           {
               tmptr = Marshal.AllocHGlobal(length);
               Marshal.Copy(sourceData, startIndex, tmptr, length);
               objectRef = Marshal.PtrToStructure(tmptr, type);
               Marshal.FreeHGlobal(tmptr);
           }
           catch (Exception ex)
           {
               if (tmptr != IntPtr.Zero)
                   Marshal.FreeHGlobal(tmptr);
               throw new Exception(" :" + ex.ToString());
           }
       }

4、試験手順
TestStruct struct1 = new TestStruct();
           struct1.ByteMember = 123;
           struct1.IntMember = new int[] { 1, 3, 45, 4 };
           struct1.Number = "test";
           struct1.ShortMember = 23241;
           Console.WriteLine(struct1.ToString());
           int size = Marshal.SizeOf(struct1);
           byte[] testDest = new byte[size];
           MemoryCopy.CopyMemFromStruct(struct1, testDest);
           object struct2 = new TestStruct();
           MemoryCopy.CopyMemFromBytes(testDest, 0, size,ref struct2, typeof(TestStruct));
           Console.WriteLine(struct2.ToString());