Freigeben über


HandleRef-Beispiel

Aktualisiert: November 2007

Dieses Beispiel demonstriert, wie die Garbage Collection für ein verwaltetes Objekt verhindert wird, bevor die nicht verwaltete Funktion abgeschlossen ist. Darüber hinaus wird gezeigt, wie das Überladen von Funktionen verwendet werden kann, um anstelle eines Verweises auf einen Werttyp einen NULL-Verweis (Nothing in Visual Basic) zu übergeben.

Das HandleRef-Beispiel verwendet die folgende nicht verwaltete Funktion, die zusammen mit ihrer ursprünglichen Funktionsdeklaration aufgeführt wird:

  • ReadFile aus Kernel32.dll exportiert.

    BOOL ReadFile(
       HANDLE hFile, 
       LPVOID lpBuffer, 
       DWORD nNumberOfBytesToRead, 
       LPDWORD lpNumberOfBytesRead, 
       LPOVERLAPPED lpOverlapped);
    

Die ursprüngliche, an die Funktion übergebene Struktur enthält die folgenden Elemente:

typedef struct _OVERLAPPED { 
    ULONG_PTR  Internal; 
    ULONG_PTR  InternalHigh; 
    DWORD  Offset; 
    DWORD  OffsetHigh; 
    HANDLE hEvent; 
} OVERLAPPED; 

In diesem Beispiel enthalten die Overlapped-Struktur und die Overlapped2-Klasse IntPtr -Typen anstelle von Zeigertypen und dem HANDLE-Typ. Das StructLayoutAttribute-Attribut ist so eingerichtet, dass sichergestellt wird, dass die Member im Speicher sequenziell in der Reihenfolge ihres Erscheinens angeordnet sind.

Die LibWrap-Klasse enthält verwaltete Prototypen für die Methoden ReadFile und ReadFile2. ReadFile übergibt die Overlapped-Struktur als einen der Parameter. Durch das Überladen der ReadFile-Methode kann in diesem Beispiel, wenn erforderlich, anstelle eines Verweises auf die Struktur ein NULL-Verweis (Nothing in Visual Basic) übergeben werden. Die direkte Übergabe eines NULL-Verweises (Nothing) ist weder in C# noch in Visual Basic 2005 zulässig.

ReadFile2 übergibt die Overlapped2-Klasse. Klassen, bei denen es sich um Referenztypen handelt, werden standardmäßig als In-Parameter weitergegeben. Wenn das InAttribute-Attribut und das OutAttribute-Attribut an die Deklaration weitergegeben werden, wird Overlapped2 als In/Out-Parameter gemarshallt. In diesem Beispiel kann, wenn erforderlich, anstelle einer Klasse direkt ein NULL-Verweis (Nothing) übergeben werden, da Klassen Referenztypen darstellen und somit an ihrer Stelle ein NULL-Verweis (Nothing) übergeben werden kann. Die App-Klasse erstellt einen HandleRef-Wrapper für den FileStream, mit dem verhindert wird, dass die Garbage Collection vor dem Beenden der Aufrufe von ReadFile oder ReadFile2 durchgeführt wird.

Der Quellcode für die folgenden Codebeispiele wird im Technologiebeispiel für Plattformaufrufe in .NET Framework bereitgestellt.

Deklarieren von Prototypen

' Declares a managed structure for the unmanaged structure.
< StructLayout( LayoutKind.Sequential )> _
Public Structure Overlapped
   …
End Structure 'Overlapped

' Declares a managed class for the unmanaged structure.
< StructLayout( LayoutKind.Sequential )> _
Public Class  Overlapped2
   …
End Class 'Overlapped2

Public Class LibWrap
   ' Declares a managed prototypes for unmanaged functions.
   ' Because Overlapped is a structure, you cannot pass Nothing as a 
   ' parameter. Instead, declares an overloaded method.
   Overloads Declare Ansi Function ReadFile Lib "Kernel32.dll" ( _
      ByVal hndRef As HandleRef, _
      ByVal buffer As StringBuilder, _
      ByVal numberOfBytesToRead As Integer, _
      ByRef numberOfBytesRead As Integer, _
      ByRef flag As Overlapped ) As Boolean
   Overloads Declare Ansi Function ReadFile Lib "Kernel32.dll" ( _
      ByVal hndRef As HandleRef, _
      ByVal buffer As StringBuilder, _
      ByVal numberOfBytesToRead As Integer, _
      ByRef numberOfBytesRead As Integer, _
      ' Declares an int instead of a structure reference.
      ByVal flag As IntPtr ) As Boolean 

   ' Because Overlapped2 is a class, you can pass Nothing as a parameter.
   ' No overloading is needed.
   Declare Ansi Function ReadFile2 Lib "Kernel32.dll" Alias "ReadFile" ( _
      ByVal hndRef As HandleRef, _
      ByVal buffer As StringBuilder, _
      ByVal numberOfBytesToRead As Integer, _
      ByRef numberOfBytesRead As Integer, _
      <[In], Out> ByVal flag As Overlapped2 ) As Boolean
End Class 'LibWrap
// Declares a managed structure for the unmanaged structure.
[ StructLayout( LayoutKind.Sequential )]
public struct Overlapped
{
   …
}
// Declares a managed class for the unmanaged structure.
[ StructLayout( LayoutKind.Sequential )]
public class Overlapped2
{
   …
}
public class LibWrap
{
   // Declares managed prototypes for unmanaged functions.
   // Because Overlapped is a structure, you cannot pass null as a 
   // parameter. Instead, declares an overloaded method.
   [ DllImport( "Kernel32.dll" )]
   public static extern bool ReadFile( 
      HandleRef hndRef, 
      StringBuilder buffer, 
      int numberOfBytesToRead, 
      out int numberOfBytesRead, 
      ref Overlapped flag );

   [ DllImport( "Kernel32.dll" )]
   public static extern bool ReadFile(
      HandleRef hndRef, 
      StringBuilder buffer, 
      int numberOfBytesToRead, 
      out int numberOfBytesRead, 
      IntPtr flag ); // Declares an int instead of a structure reference.

   // Because Overlapped2 is a class, you can pass null as parameter.
   // No overloading is needed.
   [ DllImport( "Kernel32.dll", EntryPoint="ReadFile" )]
   public static extern bool ReadFile2(
      HandleRef hndRef, 
      StringBuilder buffer, 
      int numberOfBytesToRead, 
      out int numberOfBytesRead,
      Overlapped2 flag );
}

Aufrufen von Funktionen

Public Class App
       Public Shared Sub Main()
      Dim fs As New FileStream( "HandleRef.txt", FileMode.Open )
      ' Wraps the FileStream handle in HandleRef to prevent it 
      ' from being garbage collected before the call ends.
      Dim hr As New HandleRef( fs, fs.Handle )
      Dim buffer As New StringBuilder( 5 )
      Dim read As Integer = 0
      ' Platform invoke holds the reference to HandleRef until the call 
      ' ends.
      LibWrap.ReadFile( hr, buffer, 5, read, 0 )
      Console.WriteLine( "Read with struct parameter: {0}", buffer )
      LibWrap.ReadFile2( hr, buffer, 5, read, Nothing )
      Console.WriteLine( "Read with class parameter: {0}", buffer )
   End Sub 'Main
End Class 'App
public class App
{
   public static void Main()
   {
      FileStream fs = new FileStream( "HandleRef.txt", FileMode.Open );
      // Wraps the FileStream handle in HandleRef to prevent it 
      // from being garbage collected before the call ends.
      HandleRef hr = new HandleRef( fs, fs.Handle );
      StringBuilder buffer = new StringBuilder( 5 );
      int read = 0;
      // Platform invoke holds a reference to HandleRef until the call 
      // ends.
      LibWrap.ReadFile( hr, buffer, 5, out read, 0 );
      Console.WriteLine( "Read with struct parameter: {0}", buffer );
      LibWrap.ReadFile2( hr, buffer, 5, out read, null );
      Console.WriteLine( "Read with class parameter: {0}", buffer );
   }
}

Siehe auch

Konzepte

Verschiedene Marshallingbeispiele

Datentypen für den Plattformaufruf

Erstellen von Prototypen in verwaltetem Code