.NET Framework 開發人員手冊
結構範例

更新:2007 年 11 月

這個範例示範如何傳遞指向第二個結構的結構、傳遞具有內嵌結構的結構,以及傳遞具有內嵌陣列的結構。

下列程式碼範例的原始程式碼是由 .NET Framework 平台叫用技術範例所提供。

結構範例使用下列 Unmanaged 函式,顯示其原始函式宣告:

  • 從 PinvokeLib.dll 匯出 TestStructInStruct

    int TestStructInStruct(MYPERSON2* pPerson2);
  • 從 PinvokeLib.dll 匯出 TestStructInStruct3

    void TestStructInStruct3(MYPERSON3 person3);
  • 從 PinvokeLib.dll 匯出 TestArrayInStruct

    void TestArrayInStruct( MYARRAYSTRUCT* pStruct );

PinvokeLib.dll 是自訂的 Unmanaged 程式庫,包含先前列示函式和四個結構 (MYPERSONMYPERSON2MYPERSON3MYARRAYSTRUCT) 的實作。這些結構包含下列元素:

typedef struct _MYPERSON
{
   char* first; 
   char* last; 
} MYPERSON, *LP_MYPERSON;

typedef struct _MYPERSON2
{
   MYPERSON* person;
   int age; 
} MYPERSON2, *LP_MYPERSON2;

typedef struct _MYPERSON3
{
   MYPERSON person;
   int age; 
} MYPERSON3;

typedef struct _MYARRAYSTRUCT
{
   bool flag;
   int vals[ 3 ]; 
} MYARRAYSTRUCT;

Managed MyPersonMyPerson2MyPerson3MyArrayStruct 結構有以下特性:

  • MyPerson 只包含字串成員。當傳遞至 Unmanaged 函式時,CharSet 欄位會將字串設為 ANSI 格式。

  • MyPerson2 包含 MyPerson 結構的 IntPtr。除非程式碼被標示為 unsafe,否則 .NET Framework 應用程式不會使用指標,因此 IntPtr 型別會取代 Unmanaged 結構的原始指標。

  • MyPerson3 包含 MyPerson 做為內嵌結構。直接將內嵌結構的元素放置到主要結構,可以將內嵌其他結構的結構扁平化,或者可將這個結構保留為內嵌結構,如這個範例中所做的一樣。

  • MyArrayStruct 包含整數的陣列。MarshalAsAttribute 屬性會將 UnmanagedType 列舉型別值設為 ByValArray,用來指示陣列中的元素數。

針對這個範例中的所有結構,套用 StructLayoutAttribute 屬性可確保成員是以其出現的順序在記憶體中循序配置。

LibWrap 類別包含 App 類別所呼叫之 TestStructInStructTestStructInStruct3TestArrayInStruct 方法的 Managed 原型。每一個原型宣告單一參數,如下:

  • TestStructInStruct 宣告 MyPerson2 型別的參考做為其參數。

  • TestStructInStruct3 宣告 MyPerson3 型別做為它的參數,並且以傳值方式傳遞該參數。

  • TestArrayInStruct 宣告 MyArrayStruct 型別的參考做為它的參數。

除非參數包含 ref (在 Visual Basic 中為 ByRef) 關鍵字,否則做為方法引數的結構會以傳值 (By Value) 方式傳遞。例如,TestStructInStruct 方法會將 MyPerson2 型別的物件參考 (位址的值) 傳遞至 Unmanaged 程式碼。為了管理 MyPerson2 指向的結構,範例中結合了 Marshal..::.AllocCoTaskMemMarshal..::.SizeOf 方法,建立指定大小的緩衝區,並傳回其位址。接著,範例會將 Managed 結構的內容複製到 Unmanaged 緩衝區。最後,範例會使用 Marshal..::.PtrToStructure 方法,從 Unmanaged 緩衝區將資料封送處理至 Managed 物件,以及使用 Marshal..::.FreeCoTaskMem 方法來釋放記憶體的 Unmanaged 區塊。

宣告原型

Visual Basic
' Declares a managed structure for each unmanaged structure.
< StructLayout( LayoutKind.Sequential, CharSet := CharSet.Ansi )> _
Public Structure MyPerson
   Public first As String
   Public last As String
End Structure 'MyPerson

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPerson2
   Public person As IntPtr
   Public age As Integer
End Structure 'MyPerson2

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyPerson3
   Public person As MyPerson
   Public age As Integer
End Structure 'MyPerson3

< StructLayout( LayoutKind.Sequential )> _
Public Structure MyArrayStruct 
   Public flag As Boolean
   < MarshalAs( UnmanagedType.ByValArray, SizeConst:=3 )> _
   Public vals As Integer()
End Structure 'MyArrayStruct

Public Class LibWrap
   ' Declares managed prototypes for unmanaged functions.
   Declare Function TestStructInStruct Lib "..\LIB\PinvokeLib.dll" ( _
      ByRef person2 As MyPerson2 ) As Integer
   Declare Function TestStructInStruct3 Lib "..\LIB\PinvokeLib.dll" ( _
      ByVal person3 As MyPerson3 ) As Integer
   Declare Function TestArrayInStruct Lib "..\LIB\PinvokeLib.dll" ( _
      ByRef myStruct As MyArrayStruct ) As Integer   
End Class 'LibWrap
C#
// Declares a managed structure for each unmanaged structure.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct MyPerson 
{
   public String first; 
   public String last;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyPerson2 
{
   public IntPtr person;
   public int age;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyPerson3 
{
   public MyPerson person;
   public int age;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyArrayStruct 
{
   public bool flag;
   [ MarshalAs( UnmanagedType.ByValArray, SizeConst=3 )] 
   public int[] vals;
}

public class LibWrap
{
   // Declares a managed prototype for unmanaged function.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestStructInStruct( ref MyPerson2 person2 );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestStructInStruct3( MyPerson3 person3 );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern int TestArrayInStruct( ref MyArrayStruct 
   myStruct );
}
呼叫函式

Visual Basic
Public Class App
   Public Shared Sub Main()
      ' Structure with a pointer to another structure. 
      Dim personName As MyPerson
      personName.first = "Mark"
      personName.last = "Lee"
      
      Dim personAll As MyPerson2
      personAll.age = 30
      
      Dim buffer As IntPtr = Marshal.AllocCoTaskMem( Marshal.SizeOf( _
      personName ))
      Marshal.StructureToPtr( personName, buffer, False )
      
      personAll.person = buffer
      
      Console.WriteLine( ControlChars.CrLf & "Person before call:" )
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", _
      personName.first, personName.last, personAll.age )
      
      Dim res As Integer = LibWrap.TestStructInStruct( personAll )
      
      Dim personRes As MyPerson = _
         CType( Marshal.PtrToStructure( personAll.person, _
         GetType( MyPerson )), MyPerson )
      
      Marshal.FreeCoTaskMem( buffer )
      
      Console.WriteLine( "Person after call:" )
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", _
      personRes.first, _
         personRes.last, personAll.age )
      
      ' Structure with an embedded structure.
      Dim person3 As New MyPerson3()
      person3.person.first = "John"
      person3.person.last = "Evens"
      person3.age = 27
      LibWrap.TestStructInStruct3( person3 )
      
      ' Structure with an embedded array.
      Dim myStruct As New MyArrayStruct()
      
      myStruct.flag = False
      Dim array( 2 ) As Integer
      myStruct.vals = array
      myStruct.vals( 0 ) = 1
      myStruct.vals( 1 ) = 4
      myStruct.vals( 2 ) = 9
      
      Console.WriteLine( ControlChars.CrLf & "Structure with array _
      before call:" )
      Console.WriteLine( myStruct.flag )
      Console.WriteLine( "{0} {1} {2}", myStruct.vals( 0 ), _
         myStruct.vals( 1 ), myStruct.vals( 2 ) )
      
      LibWrap.TestArrayInStruct( myStruct )
      Console.WriteLine( ControlChars.CrLf & "Structure with array _
      after call:" )
      Console.WriteLine( myStruct.flag )
      Console.WriteLine( "{0} {1} {2}", myStruct.vals( 0 ), _
         myStruct.vals( 1 ), myStruct.vals( 2 ) )
   End Sub 'Main
End Class 'App
C#
public class App
{
   public static void Main()
   {
      // Structure with a pointer to another structure. 
      MyPerson personName;
      personName.first = "Mark";
      personName.last = "Lee";
      
      MyPerson2 personAll;
      personAll.age = 30;
      
      IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( 
      personName ));
      Marshal.StructureToPtr( personName, buffer, false );
      
      personAll.person = buffer;
      
      Console.WriteLine( "\nPerson before call:" );
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", 
         personName.first, personName.last, personAll.age ); 
      
      int res = LibWrap.TestStructInStruct( ref personAll );
      
      MyPerson personRes = 
         (MyPerson)Marshal.PtrToStructure( personAll.person, 
         typeof( MyPerson ));
      
      Marshal.FreeCoTaskMem( buffer );
      
      Console.WriteLine( "Person after call:" );
      Console.WriteLine( "first = {0}, last = {1}, age = {2}", 
         personRes.first, personRes.last, personAll.age );
      
      // Structure with an embedded structure.
      MyPerson3 person3 = new MyPerson3();
      person3.person.first = "John";
      person3.person.last = "Evens";
      person3.age = 27;
      LibWrap.TestStructInStruct3( person3 );
      
      // Structure with an embedded array.
      MyArrayStruct myStruct = new MyArrayStruct();
      
      myStruct.flag = false;
      myStruct.vals = new int[ 3 ];
      myStruct.vals[ 0 ] = 1;
      myStruct.vals[ 1 ] = 4;
      myStruct.vals[ 2 ] = 9;
      
      Console.WriteLine( "\nStructure with array before call:" );
      Console.WriteLine( myStruct.flag );
      Console.WriteLine( "{0} {1} {2}", myStruct.vals[ 0 ], 
         myStruct.vals[ 1 ], myStruct.vals[ 2 ] );
      
      LibWrap.TestArrayInStruct( ref myStruct );
      Console.WriteLine( "\nStructure with array after call:" );
      Console.WriteLine( myStruct.flag );
      Console.WriteLine( "{0} {1} {2}", myStruct.vals[ 0 ], 
         myStruct.vals[ 1 ], myStruct.vals[ 2 ] );
   }
}
請參閱

概念

標記 :


Page view tracker