Пример HandleRef
Обновлен: Ноябрь 2007
В этом примере показан способ предотвращения сборки мусора для управляемого объекта до завершения работы неуправляемой функции. Кроме того, показано использование перегрузки функции для передачи пустой ссылки (Nothing в Visual Basic) вместо ссылки на тип значения.
В примере HandleRef используется следующая неуправляемая функция, показанная со своим исходным объявлением.
Функция ReadFile, экспортированная из Kernel32.dll.
BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
Исходная структура, переданная функции, содержит следующие элементы:
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
В этом примере структура Overlapped и класс Overlapped2 содержит типы IntPtr вместо типов указателей и типа HANDLE. Атрибут StructLayoutAttribute задается, чтобы гарантировать последовательный порядок членов в памяти, соответствующий порядку их появления.
Класс LibWrap содержит управляемые прототипы для методов ReadFile и ReadFile2. Метод ReadFile в качестве одного из параметров передает структуру Overlapped. При необходимости вместо ссылки на структуру можно передать пустую ссылку (Nothing в Visual Basic), воспользовавшись перегрузкой метода ReadFile. Ни C#, ни Visual Basic 2005 не разрешают непосредственную передачу пустой ссылки (Nothing).
Метод ReadFile2 передает класс Overlapped2. Классы, являющиеся ссылочными типами, по умолчанию передаются в виде параметров In. Применение атрибутов InAttribute и OutAttribute к объявлению инициирует маршалинг Overlapped2 как параметра In/Out. В примере при необходимости вместо класса может быть непосредственно передана пустая ссылка (Nothing), так как классы являются ссылочными типами и вместо них можно передать пустую ссылку (Nothing). Класс App создает оболочку HandleRef для FileStream, чтобы предотвратить выполнение сбора мусора до завершения вызовов ReadFile или ReadFile2.
Исходный код для следующих примеров кода см. в разделе Пример технологии вызова неуправляемого кода для .NET Framework.
Объявление прототипов
' 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 );
}
Вызов функций
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 );
}
}