HandleRef 샘플
이 샘플에서는 관리되지 않는 함수가 완료되기 전에 관리되는 개체가 가비지 수집되는 것을 방지하는 방법을 보여 줍니다. 함수 오버로드를 사용하여 값 형식에 대한 참조 대신 null 참조(Visual Basic에서는 Nothing)를 전달하는 방법도 보여 줍니다.
HandleRef 샘플에서는 다음의 관리되지 않는 함수를 사용합니다. 이 함수는 원래의 함수 선언과 함께 표시되어 있습니다.
Kernel32.dll에서 내보낸 ReadFile
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 클래스에는 포인터 형식 및 HANDLE 형식 대신 IntPtr 형식이 포함되어 있습니다. 멤버가 나타나는 순서에 따라 메모리에 순차적으로 정렬되도록 StructLayoutAttribute 특성이 설정됩니다.
LibWrap 클래스에는 ReadFile 및 ReadFile2 메서드의 관리되는 프로토타입이 포함되어 있습니다. ReadFile은 Overlapped 구조체를 매개 변수 중 하나로 전달합니다. 이 샘플에서는 필요한 경우 ReadFile 메서드를 오버로드하여 구조체에 대한 참조 대신 null 참조(Visual Basic에서는 Nothing)를 전달할 수 있습니다. C# 또는 Visual Basic 2005에서는 null 참조(Nothing)를 직접 전달할 수 없습니다.
ReadFile2는 Overlapped2 클래스를 전달합니다. 참조 형식인 클래스는 기본적으로 In 매개 변수를 통해 전달됩니다. 선언에 InAttribute 및 OutAttribute 특성을 적용하면 Overlapped2가 In/Out 매개 변수로 마샬링됩니다. 클래스가 참조 형식이고 해당 위치에 null 참조(Nothing)를 전달할 수 있기 때문에 이 샘플에서는 필요한 경우 클래스가 아니라 null 참조(Nothing)를 직접 전달할 수 있습니다. App 클래스에서는 FileStream에 대한 HandleRef 래퍼를 만들어 ReadFile 또는 ReadFile2에 대한 호출이 완료되기 전에 가비지 수집이 발생하는 것을 방지합니다.
프로토타입 선언
' 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);
};
함수 호출
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);
}
};