熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

平台調用P-INVOKE完全掌握13

2022-06-13   來源: .NET編程 

  在使用結構體指針進行和的互相調用邊界對齊是一個大問題因為邊界對齊問題結構體的成員並不是順序在一個挨著一個的排序

  而且在C++中可以使用#pragma pack(n)改變邊界對齊的方案那C#的結構體怎麼對應C++的結構體那?(什麼是邊界對齊這裡不解釋

  不懂得可以去看看C++基本編程之類的書好好惡補一下

  第一最普通的情況下C++代碼沒有使用#pragma pack(n)改變邊界對齊這裡C#可以使用兩種方法處理LayoutKindExplicit 和

  LayoutKindSequential建議使用後者雖然前者是萬金油不過使用起來太累有愛出錯

  C++:

    struct Test
  {
    int test;
    char test;
    __int test;
    short test;
  };
  
  Test * __stdcall GetTest()
 {
   testtest = ;
   testtest = ;
   testtest = ;
   testtest = ;
   return &test;
 }

  C#(這裡有兩種方案使用LayoutKindExplicit 和LayoutKindSequential注意一下)

      [StructLayout(LayoutKindExplicit)]
    public struct Test
    {
      [FieldOffset()]
      public int test;
      [FieldOffset()]
      public char test;
      [FieldOffset()]
      public Int test;
     [FieldOffset()]
     public short test;
   }
 
   [StructLayout(LayoutKindSequential)]
   public struct Test
   {
     public int test;
     public char test;
     public Int test;
     public short test;
   }
 
     [DllImport(TestDll)]
     public static extern IntPtr GetTest();
 
       //#################################
        IntPtr p = GetTest();
       Test test = (Test)MarshalPtrToStructure(p typeof(Test));
       ConsoleWriteLine(testtest + testtest + testtest + testtest);
 
       IntPtr p = GetTest(); //Auto pack
        Test test = (Test)MarshalPtrToStructure(p typeof(Test));
       ConsoleWriteLine(testtest + testtest + testtest + testtest);

  

  第二特殊的情況下代碼使用#pragma pack(n)改變了邊界對齊這裡要使用要使用   [StructLayout(LayoutKindSequential Pack = N)] 對齊否則出錯

  C++:

    #pragma pack()
   struct Test
  {
    int test;
    char test;
    __int test;
    short test;
  };
   #pragma pack()
 
  #pragma pack()
  struct Test
 {
   int test;
   char test;
   __int test;
   short test;
 };
  #pragma pack()
 
 
  #pragma pack()
  struct Test
 {
   int test;
   char test;
   __int test;
   short test;
 };
  #pragma pack()

  C#:

      [StructLayout(LayoutKindSequential Pack = )]
    struct Test
    {
      public int test;
      public char test;
      public Int test;
      public short test;
    }
  
   [StructLayout(LayoutKindSequential Pack = )]
   struct Test
   {
     public int test;
     public char test;
     public Int test;
     public short test;
   }
 
   [StructLayout(LayoutKindSequential Pack = )]
   struct Test
   {
     public int test;
     public char test;
     public Int test;
     public short test;
   }
 
 
     [DllImport(TestDll)]
     public static extern IntPtr GetTest();
 
     [DllImport(TestDll)]
     public static extern IntPtr GetTest();
 
     [DllImport(TestDll)]
     public static extern IntPtr GetTest();
 
       //#################################
        IntPtr p = GetTest(); //pack 
        Test test = (Test)MarshalPtrToStructure(p typeof(Test));
 
       IntPtr p = GetTest(); //pack 
        Test test = (Test)MarshalPtrToStructure(p typeof(Test));
 
       IntPtr p = GetTest(); //pack
        Test test = (Test)MarshalPtrToStructure(p typeof(Test));
 
       ConsoleWriteLine(testtest + testtest + testtest + testtest);
       ConsoleWriteLine(testtest + testtest + testtest + testtest);
       ConsoleWriteLine(testtest + testtest + testtest + testtest);

  最後總結一下LayoutKind有個枚舉值LayoutKindAuto LayoutKindExplicit 和LayoutKindSequentialLayoutKindAuto或者為使用LayoutKind屬性的結構體

  進行PINVOKE調用會拋出異常改類型不允許進行PINVOKE調用LayoutKindSequential在中順序布局一般情況(上面兩種)推薦用這個LayoutKindExplicit

  只推薦特殊情況使用因為他會明確指定成員的內存offset很強大也很繁瑣


From:http://tw.wingwit.com/Article/program/net/201311/12581.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.