结构示例

更新:2007 年 11 月

该示例说明如何传递指向另一个结构的结构,如何传递具有嵌入结构的结构,以及如何传递具有嵌入数组的结构。

下面的代码示例的源代码由 .NET Framework 平台调用技术示例提供。

Structs 示例使用以下非托管函数(这里同时显示其原始函数声明):

  • 从 PinvokeLib.dll 导出的 TestStructInStruct

    int TestStructInStruct(MYPERSON2* pPerson2);
    
  • 从 PinvokeLib.dll 导出的 TestStructInStruct3

    void TestStructInStruct3(MYPERSON3 person3);
    
  • 从 PinvokeLib.dll 导出的 TestArrayInStruct

    void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
    

PinvokeLib.dll 是一个自定义非托管库,它包含前面列出的函数的实现和以下四种结构: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;

托管的 MyPerson、MyPerson2、MyPerson3 和 MyArrayStruct 结构具有以下特征:

  • MyPerson 只包含字符串成员。CharSet 字段在传递给非托管函数时将这些字符串设置为 ANSI 格式。

  • MyPerson2 包含一个指向 MyPerson 结构的 IntPtrIntPtr 类型将替换指向非托管结构的原始指针,原因是除非代码被标记为 unsafe,否则 .NET Framework 应用程序不使用指针。

  • MyPerson3 包含作为嵌入结构的 MyPerson。嵌入到另一个结构中的结构可以通过将嵌入结构的元素直接放置在主结构中而单一化;该结构也可保留为嵌入结构,此示例中即如此处理。

  • MyArrayStruct 包含一个整数数组。MarshalAsAttribute 属性将 UnmanagedType 枚举值设置为 ByValArray,后者用于指示数组中的元素数目。

对于此示例中的所有结构,都将应用 StructLayoutAttribute 属性,以确保成员在内存中按照它们的出现顺序依次排列。

LibWrap 类包含由 App 类调用的 TestStructInStruct、TestStructInStruct3 和 TestArrayInStruct 方法的托管原型。每个原型都声明单个参数,如下所示:

  • TestStructInStruct 将对 MyPerson2 类型的引用声明为其参数。

  • TestStructInStruct3 将 MyPerson3 类型声明为其参数并通过值传递该参数。

  • TestArrayInStruct 将对 MyArrayStruct 类型的引用声明为其参数。

作为方法参数的结构将通过值传递,除非该参数包含 ref(在 Visual Basic 中为 ByRef)关键字。例如,TestStructInStruct 方法将对 MyPerson2 类型的对象的引用(一个地址值)传递给非托管代码。为操作 MyPerson2 所指向的结构,该示例通过组合使用 Marshal.AllocCoTaskMemMarshal.SizeOf 方法创建一个指定大小的缓冲区并返回其地址。接着,该示例将该托管结构的内容复制到该非托管缓冲区。最后,该示例使用 Marshal.PtrToStructure 方法从该非托管缓冲区向托管对象封送数据,并使用 Marshal.FreeCoTaskMem 方法释放非托管内存块。

声明原型

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

请参见

概念

封送类、结构和联合

平台调用数据类型

在托管代码中创建原型