HandleRef 示例

更新:2007 年 11 月

该示例说明如何在非托管函数完成前防止对托管对象进行垃圾回收。它还说明如何使用函数重载来传递 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 类包含 IntPtr 类型而不是指针类型和 HANDLE 类型。StructLayoutAttribute 属性经过设置,可确保成员在内存中按它们的出现顺序依次排列。

LibWrap 类包含 ReadFile 和 ReadFile2 方法的托管原型。ReadFile 将 Overlapped 结构作为参数之一进行传递。通过重载 ReadFile 方法,该示例可以在必要时传递一个 null 引用(在 Visual Basic 中为 Nothing),而不是对该结构的引用。C# 和 Visual Basic 2005 都不允许直接传递 null 引用 (Nothing)。

ReadFile2 传递 Overlapped2 类。默认情况下,作为引用类型的类将作为 In 参数进行传递。将 InAttributeOutAttribute 属性应用于声明会使 Overlapped2 作为 In/Out 参数进行封送处理。该示例可以在必要时直接传递 null 引用 (Nothing),而不是类,因为类是引用类型并且您可以在它们的位置传递 null 引用 (Nothing)。App 类为 FileStream 创建一个 HandleRef 包装以防止在对 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 );
   }
}

请参见

概念

其他封送处理示例

平台调用数据类型

在托管代码中创建原型