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 Microsoft .NET Framework SDK includes the complete Visual Basic .NET and C# versions of this sample in Samples\Technologies\Interop\Platform-Invoke.

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.

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
[C#]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 
[C#]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

Miscellaneous Marshaling Samples | Platform Invoke Data Types | Creating Prototypes in Managed Code