Compartir a través de


Ejemplo HandleRef

En este ejemplo se muestra cómo impedir la recolección de elementos no utilizados en un objeto administrado antes de que finalice la función no administrada. También se muestra cómo utilizar la sobrecarga de funciones para pasar una referencia null (Nothing en Visual Basic) en lugar de una referencia a un tipo de valor.

En el ejemplo HandleRef se utiliza la siguiente función no administrada, que se muestra con su declaración de función original:

  • ReadFile exportada desde Kernel32.dll.

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

La estructura original pasada a la función contiene los elementos siguientes:

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

En este ejemplo, la estructura Overlapped y la clase Overlapped2 contienen tipos IntPtr en lugar de tipos de puntero y el tipo HANDLE. El atributo StructLayoutAttribute se establece para asegurar que los miembros se organizan en la memoria de forma secuencial, en el orden en que aparecen.

La clase LibWrap contiene prototipos administrados para los métodos ReadFile y ReadFile2. ReadFile pasa la estructura Overlapped como uno de los parámetros. Mediante la sobrecarga del método ReadFile, en el ejemplo se puede pasar una referencia null (Nothing en Visual Basic) en lugar de una referencia a la estructura, cuando es necesario. Ni C# ni Visual Basic 2005 permiten pasar directamente una referencia null (Nothing).

El método ReadFile2 pasa la clase Overlapped2. Las clases, que son tipos de referencia, se pasan como parámetros In de forma predeterminada. Al aplicar los atributos InAttribute y OutAttribute en la declaración, se calcula la referencia de Overlapped2 como un parámetro In/Out. Cuando es necesario, en el ejemplo se puede pasar una referencia null (Nothing) directamente en lugar de una clase, porque las clases son tipos de referencia y está permitido pasar una referencia valor null (Nothing) en su lugar. La clase App crea un contenedor HandleRef para FileStream que impide que se lleve a cabo la recolección de elementos no utilizados antes de que finalicen las llamadas a ReadFile o ReadFile2.

El código fuente de los ejemplos de código siguientes lo proporciona el Ejemplo de tecnología de invocación de plataformas de .NET Framework.

Declaración de prototipos

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

Llamadas a funciones

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

Vea también

Conceptos

Diversos ejemplos de cálculo de referencias
Tipos de datos de invocación de plataforma
Crear prototipos en código administrado