Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
.NET Framework 3.5
HandleRef Structure
This page is specific to
Microsoft Visual Studio 2008/.NET Framework 3.5

Other versions are also available for the following:
.NET Framework Class Library
HandleRef Structure

Updated: November 2007

Wraps a managed object holding a handle to a resource that is passed to unmanaged code using platform invoke.

Namespace:  System.Runtime.InteropServices
Assembly:  mscorlib (in mscorlib.dll)

Visual Basic (Declaration)
<ComVisibleAttribute(True)> _
Public Structure HandleRef
Visual Basic (Usage)
Dim instance As HandleRef
C#
[ComVisibleAttribute(true)]
public struct HandleRef
Visual C++
[ComVisibleAttribute(true)]
public value class HandleRef
J#
/** @attribute ComVisibleAttribute(true) */
public final class HandleRef extends ValueType
JScript
JScript supports the use of structures, but not the declaration of new ones.

If you use platform invoke to call a managed object, and the object is not referenced elsewhere after the platform invoke call, it is possible for the garbage collector to finalize the managed object. This action releases the resource and invalidates the handle, causing the platform invoke call to fail. Wrapping a handle with HandleRef guarantees that the managed object is not garbage collected until the platform invoke call completes. For a description of platform invoke services, see Consuming Unmanaged DLL Functions.

The HandleRef value type, like GCHandle, is a special type recognized by the interop marshaler. A normal, nonpinned GCHandle also prevents untimely garbage collection, yet HandleRef provides better performance. Although using HandleRef to keep an object alive for the duration of a platform invoke call is preferred, you can also use the GC..::.KeepAlive method for the same purpose.

The HandleRef constructor takes two parameters: an Object representing the wrapper, and an IntPtr representing the unmanaged handle. The interop marshaler passes only the handle to unmanaged code, and guarantees that the wrapper (passed as the first parameter to the constructor of the HandleRef) remains alive for the duration of the call.

The following example shows how to use HandleRef to keep alive an object passed as the first parameter. The interop marshaler passes only the handle to unmanaged code.

Visual Basic
' HandleRef.vb

Imports System
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Security.Permissions

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

' declared as structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure Overlapped
    Private intrnal As IntPtr
    Private internalHigh As IntPtr
    Private offset As Integer
    Private offsetHigh As Integer
    Private hEvent As IntPtr
End Structure 'Overlapped

' declared as class
<StructLayout(LayoutKind.Sequential)> _
Public Class Overlapped2
    Private intrnal As IntPtr
    Private internalHigh As IntPtr
    Private offset As Integer
    Private offsetHigh As Integer
    Private hEvent As IntPtr
End Class 'Overlapped2


Public Class LibWrap

    ' to prevent FileStream to be GC-ed before call ends, 
    ' its handle should be wrapped in HandleRef

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

    Overloads Declare Unicode 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

    ' since Overlapped is struct, Nothing can't be passed instead, 
    ' we must declare overload method if we will use this

    Overloads Declare Unicode Function ReadFile Lib "Kernel32.dll" ( _
     ByVal hndRef As HandleRef, _
     ByVal buffer As StringBuilder, _
     ByVal numberOfBytesToRead As Integer, _
     ByRef numberOfBytesRead As Integer, _
     ByVal flag As Integer) _
    As Boolean  ' int instead of structure reference

    ' since Overlapped2 is class, we can pass Nothing as parameter  
    ' no overload is needed        

    Declare Unicode 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

Public Class App
    Public Shared Sub Main()
    
    Run()
    
    End Sub 'Main

    <SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Public Shared Sub Run()


        Dim fs As New FileStream("HandleRef.txt", FileMode.Open)
        Dim hr As New HandleRef(fs, fs.SafeFileHandle.DangerousGetHandle())
        Dim buffer As New StringBuilder(5)
        Dim read As Integer = 0

        ' platform invoke will hold reference to HandleRef until 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 'Run
End Class 'App

C#
// HandleRef.cs

using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Permissions;

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

// declared as structure
[StructLayout(LayoutKind.Sequential)]
public struct Overlapped
{
    IntPtr intrnal;
    IntPtr internalHigh;
    int offset;
    int offsetHigh;
    IntPtr hEvent;
}

// declared as class
[StructLayout(LayoutKind.Sequential)]
public class Overlapped2
{
    IntPtr intrnal;
    IntPtr internalHigh;
    int offset;
    int offsetHigh;
    IntPtr hEvent;
}

public class LibWrap
{
    // to prevent FileStream to be GC-ed before call ends, 
    // its handle should be wrapped in HandleRef

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

    [DllImport("Kernel32.dll", CharSet=CharSet.Unicode)]
    public static extern bool ReadFile(
        HandleRef hndRef,
        StringBuilder buffer,
        int numberOfBytesToRead,
        out int numberOfBytesRead,
        ref Overlapped flag);

    // since Overlapped is struct, null can't be passed instead, 
    // we must declare overload method if we will use this 

    [DllImport("Kernel32.dll", CharSet=CharSet.Unicode)]
    public static extern bool ReadFile(
        HandleRef hndRef,
        StringBuilder buffer,
        int numberOfBytesToRead,
        out int numberOfBytesRead,
        int flag);    // int instead of structure reference

    // since Overlapped2 is class, we can pass null as parameter,
    // no overload is needed    

    [DllImport("Kernel32.dll", CharSet=CharSet.Unicode, EntryPoint = "ReadFile")]
    public static extern bool ReadFile2(
        HandleRef hndRef,
        StringBuilder buffer,
        int numberOfBytesToRead,
        out int numberOfBytesRead,
        Overlapped2 flag);
}

public class App
{
    public static void Main()
    {
    Run();
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
    public static void Run()
    {
        FileStream fs = new FileStream("HandleRef.txt", FileMode.Open);
        HandleRef hr = new HandleRef(fs, fs.SafeFileHandle.DangerousGetHandle());
        StringBuilder buffer = new StringBuilder(5);
        int read = 0;

        // platform invoke will hold reference to HandleRef until 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);

    }
}

Visual C++
// HandleRef.cs
using namespace System::Runtime::InteropServices;
using namespace System;
using namespace System::IO;
using namespace System::Text;
using namespace System::Runtime::InteropServices;

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

// declared as structure
[StructLayout(LayoutKind::Sequential)]
public value struct Overlapped
{
private:
   IntPtr intrnal;
   IntPtr internalHigh;
   int offset;
   int offsetHigh;
   IntPtr hEvent;
};

// declared as class
[StructLayout(LayoutKind::Sequential)]
public ref class Overlapped2
{
private:
   IntPtr intrnal;
   IntPtr internalHigh;
   int offset;
   int offsetHigh;
   IntPtr hEvent;
};

public ref class LibWrap
{
public:
   // to prevent FileStream to be GC-ed before call ends, 
   // its handle should be wrapped in HandleRef
   //BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
   //    LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);    

   [DllImport("Kernel32.dll", CharSet=CharSet::Unicode)]
   static bool ReadFile( HandleRef hndRef, StringBuilder^ buffer, int numberOfBytesToRead, [Out]int * numberOfBytesRead, Overlapped ** flag );

   // since Overlapped is struct, null can't be passed instead, 
   // we must declare overload method if we will use this 

   [DllImport("Kernel32.dll", CharSet=CharSet::Unicode)]
   static bool ReadFile( HandleRef hndRef, StringBuilder^ buffer, int numberOfBytesToRead, [Out]int * numberOfBytesRead, int flag ); // int instead of structure reference

   // since Overlapped2 is class, we can pass null as parameter,
   // no overload is needed 
   [DllImport("Kernel32.dll", CharSet=CharSet::Unicode, EntryPoint="ReadFile")]
   static bool ReadFile2( HandleRef hndRef, StringBuilder^ buffer, int numberOfBytesToRead, [Out]int * numberOfBytesRead, Overlapped2^ flag );
};

int main()
{

   FileStream^ fs = gcnew FileStream( "HandleRef.txt", FileMode::Open );
   HandleRef hr = HandleRef(fs,fs->Handle);
   StringBuilder^ buffer = gcnew StringBuilder( 5 );
   int read = 0;

   // platform invoke will hold reference to HandleRef until call ends
   LibWrap::ReadFile( hr, buffer, 5,  &read, 0 );
   Console::WriteLine( "Read with struct parameter: {0}", buffer );


   LibWrap::ReadFile2( hr, buffer, 5,  &read, nullptr );
   Console::WriteLine( "Read with class parameter: {0}", buffer );
}

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

.NET Framework

Supported in: 3.5, 3.0, 2.0, 1.1, 1.0
Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
Processing
© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker