The case of the changing WinForm handle

Posted 08/01/2011

This weekend I was using the SetClipboardViewer (User32.dll) to create a Clipboard monitor in one of my applications. This API requires the current Handle of the calling window in order to send a message back to it. You then take that message and pass it down the chain to the next window that is registered. There are lots of good examples on the web of how to do this. Here are a few:

  1. http://www.radsoftware.com.au/articles/ClipboardMonitor_VB.txt
  2. http://www.radsoftware.com.au/articles/clipboardmonitor.aspx
  3. http://www.daniweb.com/software-development/vbnet/threads/355755

My problem was, I would receive an initial change event, but then I wouldn’t receive any other. The examples worked, but in my project it wouldn’t. And then I found out, the Handle on my form was changing (so the Handle that I registered was not the handle anymore thus wasn’t receiving the messages). My next question was… why did my Window Handle change? I thought it was supposed to be static for the instance of your Form or Object. Here’s what was happening in my case. I set the Form’s “ShowInTaskbar” property. When this is set, the form disappears and reappears and the handle is changed afterwards. I can only assume that a new instance is being created and the state being reset. The register event for me needed to occur after ShowInTaskbar was set.

Hope this helps someone.

For reference, if you want to see the code I used to debug/track this down, here it is. You’ll need a form (all default names) with a RichTextBox and a Timer on it.

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Me.Timer1.Interval = 1000
        Me.Timer1.Enabled = True
        Me.AddEvent("Load", Me.Handle.ToString)
    End Sub

   Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        Me.AddEvent("Shown", Me.Handle.ToString)
    End Sub

    Public Sub AddEvent(ByVal eventName As String, ByVal handle As String)
        RichTextBox1.Text += String.Format("{0}={1}{2}", eventName, handle, vbCrLf)
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Me.AddEvent("Before ShowInTaskBar", Me.Handle.ToString)
        Me.ShowInTaskbar = Not Me.ShowInTaskbar
        Me.AddEvent("After ShowInTaskBar", Me.Handle.ToString)
    End Sub

End Class