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 garantizar que los miembros se organizan secuencialmente en la memoria, 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 se completen las llamadas a ReadFile o ReadFile2.
Declaración de prototipos
' Declares a managed structure for the unmanaged structure.
<StructLayout(LayoutKind.Sequential)> _
Public Structure Overlapped
' ...
End Structure
' Declares a managed class for the unmanaged structure.
<StructLayout(LayoutKind.Sequential)> _
Public Class Overlapped2
' ...
End Class
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
' Declares an int instead of a structure reference for 'flag'
Overloads Declare Ansi Function ReadFile Lib "Kernel32.dll" ( _
ByVal hndRef As HandleRef, _
ByVal buffer As StringBuilder, _
ByVal numberOfBytesToRead As Integer, _
ByRef numberOfBytesRead As Integer, _
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
// 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);
}
// Declares a managed structure for the unmanaged structure.
[StructLayout(LayoutKind::Sequential)]
public value struct Overlapped
{
// ...
};
// Declares a managed class for the unmanaged structure.
[StructLayout(LayoutKind::Sequential)]
public ref class Overlapped2
{
// ...
};
public ref class LibWrap
{
public:
// 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")]
static bool ReadFile(
HandleRef hndRef,
StringBuilder^ buffer,
int numberOfBytesToRead,
int numberOfBytesRead,
Overlapped% flag );
[DllImport("Kernel32.dll")]
static bool ReadFile(
HandleRef hndRef,
StringBuilder^ buffer,
int numberOfBytesToRead,
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")]
static bool ReadFile2(
HandleRef hndRef,
StringBuilder^ buffer,
int numberOfBytesToRead,
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.SafeFileHandle.DangerousGetHandle())
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, IntPtr.Zero)
Console.WriteLine("Read {0} bytes with struct parameter: {1}", read, buffer)
LibWrap.ReadFile2(hr, buffer, 5, read, Nothing)
Console.WriteLine("Read {0} bytes with class parameter: {1}", read, buffer)
End Sub
End Class
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.SafeFileHandle.DangerousGetHandle());
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, IntPtr.Zero);
Console.WriteLine("Read {0} bytes with struct parameter: {1}", read, buffer);
LibWrap.ReadFile2(hr, buffer, 5, out read, null);
Console.WriteLine("Read {0} bytes with class parameter: {1}", read, buffer);
}
}
public ref class App
{
public:
static void Main()
{
FileStream^ fs = gcnew FileStream("HandleRef.txt", FileMode::Open);
// Wraps the FileStream handle in HandleRef to prevent it
// from being garbage collected before the call ends.
HandleRef hr = HandleRef(fs, fs->SafeFileHandle->DangerousGetHandle());
StringBuilder^ buffer = gcnew StringBuilder(5);
int read = 0;
// Platform invoke holds a reference to HandleRef until the call
// ends.
LibWrap::ReadFile(hr, buffer, 5, read, IntPtr::Zero);
Console::WriteLine("Read {0} bytes with struct parameter: {1}", read, buffer);
LibWrap::ReadFile2(hr, buffer, 5, read, nullptr);
Console::WriteLine("Read {0} bytes with class parameter: {1}", read, buffer);
}
};
Vea también
Conceptos
Diversos ejemplos de cálculo de referencias