共用方式為


結構範例

更新: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 MyPerson、MyPerson2、MyPerson3 和 MyArrayStruct 結構有以下特性:

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

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

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

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

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

LibWrap 類別包含 App 類別所呼叫之 TestStructInStruct、TestStructInStruct3 和 TestArrayInStruct 方法的 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 區塊。

宣告原型

' 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
// 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 );
}

呼叫函式

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
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 ] );
   }
}

請參閱

概念

封送處理類別、結構和等位

平台叫用資料型別

在 Managed 程式碼中建立原型