GCHandle Sample

This sample demonstrates how to pass a managed object to an unmanaged function that expects an LPARAM type. An LPARAM type is a pointer to an unmanaged parameter.

The GCHandle sample uses the following unmanaged function, shown with its original function declaration:

  • EnumWindows exported from User32.dll.

    BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
    

In this sample, the LibWrap class contains a managed prototype of the EnumWindows method. As its parameters, the managed method substitutes the CallBack delegate for the WNDENUMPROC function pointer and an IntPtr pointer for the LPARAM type.

The App class creates a handle to the managed object using the GCHandle.Alloc method, which prevents the managed object from being collected. A call to the EnumWindows method passes the delegate and the managed object, casting the handle to an IntPtr. The unmanaged function passes the type back to the caller as a parameter of the callback function.

The source code for the following code examples is provided by the .NET Framework Platform Invoke Technology Sample.

Declaring Prototypes

Public Delegate Function CallBack( ByVal handle As Integer, ByVal param _As IntPtr ) As Boolean

Public Class LibWrap
   ' Passes a managed object instead of an LPARAM.
   ' Declares a managed prototype for the unmanaged function.
   Declare Function EnumWindows Lib "user32.dll" ( _
      ByVal cb As CallBack, ByVal param As IntPtr ) As Boolean
End Class 'LibWrap
public delegate bool CallBack( int handle, IntPtr param );

public class LibWrap
{
   // Passes a managed object as an LPARAM type.
   // Declares a managed prototype for the unmanaged function.
   [ DllImport( "user32.dll" )]
   public static extern bool EnumWindows( CallBack cb, IntPtr param );
}

Calling Functions

Public Class App
   Public Shared Sub Main()
      Dim tw As TextWriter = System.Console.Out
      Dim gch As GCHandle = GCHandle.Alloc( tw )
      
      ' Platform invoke prevents the delegate from being garbage collected
      ' before the call ends.
      Dim cewp As CallBack
      cewp = AddressOf App.CaptureEnumWindowsProc
      LibWrap.EnumWindows( cewp, GCHandle.op_Explicit( gch ))
      gch.Free()
   End Sub 'Main
   
   Public Shared Function CaptureEnumWindowsProc( ByVal handle _
         As Integer, ByVal param As IntPtr ) As Boolean
      Dim gch As GCHandle = GCHandle.op_Explicit( param )
      Dim tw As TextWriter = CType( gch.Target, TextWriter )
      tw.WriteLine( handle )
      return True
   End Function 'CaptureEnumWindowsProc
End Class 'App 
public class App
{
   public static void Main()
   {
      TextWriter tw = System.Console.Out;
      GCHandle gch = GCHandle.Alloc( tw );
      CallBack cewp = new CallBack( CaptureEnumWindowsProc );
      
      // Platform invoke prevents the delegate from being garbage 
      // collected before the call ends.
      LibWrap.EnumWindows( cewp, (IntPtr)gch );
      gch.Free();
   }
   
   private static bool CaptureEnumWindowsProc( int handle, IntPtr param )
   {
      GCHandle gch = (GCHandle)param;
      TextWriter tw = (TextWriter)gch.Target;
      tw.WriteLine( handle );
      return true;
   }   
}

See Also

Concepts

Miscellaneous Marshaling Samples

Platform Invoke Data Types

Creating Prototypes in Managed Code