HandleRef, exemple

Mise à jour : novembre 2007

Cet exemple démontre comment éviter le garbage collection sur un objet managé avant que la fonction non managée ne se termine. Il montre également comment utiliser la surcharge de fonction pour passer une référence null (Nothing en Visual Basic) au lieu d'une référence à un type valeur.

L'exemple HandleRef utilise la fonction non managée suivante, illustrée avec sa déclaration de fonction d'origine :

  • ReadFile exportée à partir de Kernel32.dll.

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

La structure d'origine passée vers la fonction contient les éléments suivants :

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

Dans cet exemple, la structure Overlapped et la classe Overlapped2 contiennent des types IntPtr au lieu de types pointeur et du type HANDLE. L'attribut StructLayoutAttribute est défini afin de garantir que les membres sont disposés en mémoire de manière séquentielle, dans l'ordre de leur apparition.

La classe LibWrap contient les prototypes managés pour les méthodes ReadFile et ReadFile2. ReadFile passe la structure Overlapped comme l'un des paramètres. En surchargeant la méthode ReadFile, l'exemple peut passer une référence null (Nothing en Visual Basic) au lieu d'une référence à la structure lorsque cela est nécessaire. Ni C#, ni Visual Basic 2005 n'autorisent le passage direct d'une référence null (Nothing).

ReadFile2 passe la classe Overlapped2. Les classes, qui sont des types référence, sont passées sous la forme d'un paramètre en entrée par défaut. L'application des attributs InAttribute et OutAttribute à la déclaration entraîne le marshaling de Overlapped2 en tant que paramètre en entrée/sortie. L'exemple peut passer une référence null (Nothing) directement, si nécessaire, au lieu d'une classe car les classes sont des types référence et vous pouvez passer une référence null (Nothing) à leur place. La classe App crée un wrapper HandleRef pour FileStream afin d'éviter qu'un garbage collection ne se produise avant que les appels à ReadFile ou ReadFile2 ne soient terminés.

Le code source pour les exemples de code suivants est fourni par Appel de plate-forme, exemple de technologie du .NET Framework.

Déclaration de prototypes

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

Appel de fonctions

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

Voir aussi

Concepts

Exemples divers de marshaling

Types de données d'appel de plate-forme

Création de prototypes dans du code managé