Share via


OutArrayOfStructs 範例

這個範例示範如何將含有當做 Out 參數之整數和字串的結構陣列,傳遞給 Unmanaged 函式。此範例原始程式碼包含在平台叫用技術範例之中。

這個範例示範如何使用 Marshal 類別 (Class) 和 unsafe 程式碼來呼叫原生函式。

這個範例使用一個包裝函式 (Wrapper Function),以及在 PinvokeLib.dll 中定義的平台叫用,此平台叫用也有在原始程式檔 (Source File) 中提供。此範例使用 TestOutArrayOfStructs 函式和 MYSTRSTRUCT2 結構。該結構包含下列元素:

typedef struct _MYSTRSTRUCT2
{
   char* buffer;
   UINT size; 
} MYSTRSTRUCT2;

MyStruct 類別包含一個 ANSI 字元的字串物件。CharSet 欄位會指定 ANSI 格式。MyUnsafeStruct 是包含 IntPtr 型別 (而非字串) 的結構。

LibWrap 類別包含多載的 TestOutArrayOfStructs 原型方法。如果某個方法將指標宣告為參數,便應該以 unsafe 關鍵字來標記類別。因為 Visual Basic 2005 無法使用 Unsafe 程式碼,因此多載方法、不安全的修飾詞 (Modifier) 和 MyUnsafeStruct 結構都是不需要的。

App 類別會實作 UsingMarshal 方法,執行傳遞陣列時所需要的全部工作。以 out (在 Visual Basic 中為 ByRef) 關鍵字標記的陣列,表示資料從被呼叫端傳遞至呼叫端。此實作使用下列 Marshal 類別方法:

  • PtrToStructure 會將資料從 Unmanaged 緩衝區封送處理 (Marshal) 至 Managed 物件。

  • DestroyStructure 會釋放結構中保留給字串的記憶體。

  • FreeCoTaskMem 會釋放保留給陣列的記憶體。

如前所述,C# 允許使用 Unsafe 程式碼,而 Visual Basic 2005 則不允許使用 Unsafe 程式碼。在 C# 範例中,UsingUnsafe 是可以選擇的方法實作,會使用指標代替 Marshal 類別,並傳回含有 MyUnsafeStruct 結構的陣列。

宣告原型

' Declares a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Class MyStruct 
   Public buffer As String 
   Public someSize As Integer
End Class 'MyStruct

Public Class LibWrap
' Declares a managed prototype for the unmanaged function.
   Declare Sub TestOutArrayOfStructs Lib "..\\LIB\\PinvokeLib.dll" ( _
      ByRef arrSize As Integer, ByRef outArray As IntPtr )
End Class 'LibWrap
// Declares a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MyStruct 
{
   public String buffer;
   public int size;
}
// Declares a structure with a pointer.
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnsafeStruct 
{
   public IntPtr buffer;
   public int size;
}

public unsafe class LibWrap
{
   // Declares managed prototypes for the unmanaged function.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size, 
      out IntPtr outArray );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size, 
   MyUnsafeStruct** outArray );
}

呼叫函式

Public Class App
   Public Shared Sub Main()
      Console.WriteLine( ControlChars.CrLf & "Using marshal class" & _
ControlChars.CrLf )
      UsingMarshal()
      'Visual Basic 2005 cannot use unsafe code.
   End Sub 'Main
   
   Public Shared Sub UsingMarshal()   
      Dim arrSize As Integer
      Dim outArray As IntPtr
      LibWrap.TestOutArrayOfStructs( arrSize, outArray )
      Dim manArray(arrSize - 1) As MyStruct
      Dim current As IntPtr = outArray
      Dim i As Integer
      
      For i = 0 To arrSize - 1
      
         manArray(i) = New MyStruct()
         Marshal.PtrToStructure( current, manArray(i))
         
         Marshal.DestroyStructure( current, GetType( MyStruct )) 
         current = IntPtr.op_explicit( current.ToInt64() _
           + Marshal.SizeOf( manArray(i) ))
         
         Console.WriteLine( "Element {0}: {1} {2}", i, manArray(i)._
           buffer, manArray(i).someSize )
      Next i
      Marshal.FreeCoTaskMem( outArray )
   End Sub 'UsingMarshal
End Class 'App
public class App
{
   public static void Main()
   {
      Console.WriteLine( "\nUsing marshal class\n" );
      UsingMarshal();
      Console.WriteLine( "\nUsing unsafe code\n" );
      UsingUnsafe();
   }
   
   public static void UsingMarshal()   
   {
      int size;
      IntPtr outArray;
      LibWrap.TestOutArrayOfStructs( out size, out outArray );
      MyStruct[] manArray = new MyStruct[ size ];
      IntPtr current = outArray;
      for( int i = 0; i < size; i++ )
      {
         manArray[ i ] = new MyStruct();
         Marshal.PtrToStructure( current, manArray[ i ]);
         
         //Marshal.FreeCoTaskMem( (IntPtr)Marshal.ReadInt32( current ));
         Marshal.DestroyStructure( current, typeof(MyStruct) );
         current = (IntPtr)((long)current + 
            Marshal.SizeOf( manArray[ i ] ));
         
         Console.WriteLine( "Element {0}: {1} {2}", i, 
            manArray[ i ].buffer, manArray[ i ].size );
      }
      Marshal.FreeCoTaskMem( outArray );
   }
   
   public static unsafe void UsingUnsafe()
   {
      int size;
      MyUnsafeStruct* pResult;
      LibWrap.TestOutArrayOfStructs( out size, &pResult );
      MyUnsafeStruct* pCurrent = pResult;
      for( int i = 0; i < size; i++, pCurrent++ )
      {
         Console.WriteLine( "Element {0}: {1} {2}", i, 
            Marshal.PtrToStringAnsi( pCurrent->buffer ), pCurrent->size );
         Marshal.FreeCoTaskMem( pCurrent->buffer );
      }
      Marshal.FreeCoTaskMem( (IntPtr)pResult );
   }
}

請參閱

概念

封送處理類別、結構和等位
平台叫用資料型別
在 Managed 程式碼中建立原型