10 December 2008

SetClipboardViewer API VB.NET

This registers a form as a clipboard viewer. It then recieves notification when something happens to the clipboard. Some post on the msdn forum. It mentioned: http://www.radsoftware.com.au/articles/ClipboardMonitor_VB.txt, which I've tidied up to my liking (a stray long, a strange cast removed, you can't override Dispose (could you before?))
Option Strict On
Option Explicit On

Imports System.Runtime.InteropServices

Public Class Form1

   Private Const WM_DRAWCLIPBOARD As Integer = &H308
   Private Const WM_CHANGECBCHAIN As Integer = &H30D

   Private mNextClipBoardViewerHWnd As IntPtr
   Private Event OnClipboardChanged()

   <DllImport("user32")> _
   Private Shared Function SetClipboardViewer(ByVal hWnd As IntPtr) As IntPtr
   End Function

   <DllImport("user32")> _
   Private Shared Function ChangeClipboardChain(ByVal hWnd As IntPtr, ByVal hWndNext As IntPtr) As _
       <MarshalAs(UnmanagedType.Bool)> Boolean
   End Function

   <DllImport("user32")> _
   Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, _
       ByVal lParam As IntPtr) As IntPtr
   End Function

   Sub New()
       mNextClipBoardViewerHWnd = SetClipboardViewer(Me.Handle)
       AddHandler Me.OnClipboardChanged, AddressOf ClipBoardChanged
   End Sub

   Protected Overrides Sub WndProc(ByRef m As Message)
       Select Case m.Msg
           Case WM_DRAWCLIPBOARD
               RaiseEvent OnClipboardChanged()
               SendMessage(mNextClipBoardViewerHWnd, m.Msg, m.WParam, m.LParam)

           Case WM_CHANGECBCHAIN
               If m.WParam.Equals(mNextClipBoardViewerHWnd) Then
                   mNextClipBoardViewerHWnd = m.LParam
                   SendMessage(mNextClipBoardViewerHWnd, m.Msg, m.WParam, m.LParam)
               End If
       End Select
   End Sub

   Private Sub ClipBoardChanged()
       Dim data As IDataObject = Clipboard.GetDataObject()
       If data.GetDataPresent(GetType(Bitmap)) Then
           Me.BackgroundImage = DirectCast(data.GetData(GetType(Bitmap)), Bitmap)
       End If
   End Sub

   Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles Me.FormClosing
       ChangeClipboardChain(Me.Handle, mNextClipBoardViewerHWnd)
   End Sub

End Class

To use: start a few instances of the program. Copy an image into the clipboard - the backgrounds of the forms should change. Then close one of the forms and change the image in the clipboard - all the backgrounds should change.


  1. Many thanks!
    I'm just a beginner but it worked for my purpose
    In Private Sub ClipBoardChanged()
    i added the line:
    TextBox1.Text = Clipboard.GetText
    to check it's efficiency
    It allows me to get the clipboard displayed as soon as i hit ctl.c;
    in this way i keep a 46 lines clipboard, each line is assigned an autohotkey(R) shortcut a0, a1, etc.
    each "copy" or "cut" i do is automatically assigned at the top of the listbox, the bottom 46th item is discarded.

  2. Thanks dear. It's worked very well.

    We can detect either any clipboard change or only image changes.
    How can we detect if clipboard text change? as well as file drop list change?

    I am waiting your response :)