45

I want to have this feature in my C# program: When the user do Ctrl + C or Copy anywhere (i.e. when the clipboard content changes), my program will get notified, and check whether the content met certain criteria, if so, become the active program, and process the content, etc.

I can get the contents out from System.Windows.Forms.Clipboard, however, I don't know how to monitor the content changes from the clipboard.

If using Windows Vista or later, use AddClipboardFormatListener as in John Knoeller's answer, for Windows XP, I have to use the older, more fragile SetClipboardViewer API, as in the accepted answer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Weiming
  • 929
  • 1
  • 10
  • 13
  • 1
    How to do this in WPF is here: http://stackoverflow.com/a/33018459/2122718 – marbel82 Jul 05 '16 at 12:17
  • [SharpClipboard](https://github.com/Willy-Kimura/SharpClipboard) as a library could be of more benefit as it encapsulates the same features into one fine component library. You can then access its `ClipboardChanged` event and detect various data-formats when they're cut/copied. – Willy Kimura Feb 07 '19 at 10:38

4 Answers4

57

I've written up a small utility class that uses the AddClipboardFormatListener function function with a Message-only window to do just this.

/// <summary>
/// Provides notifications when the contents of the clipboard is updated.
/// </summary>
public sealed class ClipboardNotification
{
    /// <summary>
    /// Occurs when the contents of the clipboard is updated.
    /// </summary>
    public static event EventHandler ClipboardUpdate;

    private static NotificationForm _form = new NotificationForm();

    /// <summary>
    /// Raises the <see cref="ClipboardUpdate"/> event.
    /// </summary>
    /// <param name="e">Event arguments for the event.</param>
    private static void OnClipboardUpdate(EventArgs e)
    {
        var handler = ClipboardUpdate;
        if (handler != null)
        {
            handler(null, e);
        }
    }

    /// <summary>
    /// Hidden form to recieve the WM_CLIPBOARDUPDATE message.
    /// </summary>
    private class NotificationForm : Form
    {
        public NotificationForm()
        {
            NativeMethods.SetParent(Handle, NativeMethods.HWND_MESSAGE);
            NativeMethods.AddClipboardFormatListener(Handle);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == NativeMethods.WM_CLIPBOARDUPDATE)
            {
                OnClipboardUpdate(null);
            }
            base.WndProc(ref m);
        }
    }
}

internal static class NativeMethods
{
    // See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
    public const int WM_CLIPBOARDUPDATE = 0x031D;
    public static IntPtr HWND_MESSAGE = new IntPtr(-3);

    // See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool AddClipboardFormatListener(IntPtr hwnd);

    // See http://msdn.microsoft.com/en-us/library/ms633541%28v=vs.85%29.aspx
    // See http://msdn.microsoft.com/en-us/library/ms649033%28VS.85%29.aspx
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
}

This class assumes that the notifications are always needed for the duration of the applications lifetime, however it could be modified to provide the ability to unsubscribe via the RemoveClipboardFormatListener function if required.

Justin
  • 84,773
  • 49
  • 224
  • 367
16

You can do this with pinvoke to the Win32 API AddClipboardFormatListener

The listener is a window handle (Form.Handle), and the form will be notified of changes with a WM_CLIPBOARDUPDATE notification

It is a more robust replacement for the older SetClipboardViewer API.

John Knoeller
  • 33,512
  • 4
  • 61
  • 92
  • Thanks. but on the msdn page, the minimum OS requirement for this API is Vista. is that true? (I'm still under XP though. in fact, my users will be using XP, too.) – Weiming Feb 09 '10 at 22:58
  • 2
    Yes, minimum requirement is Vista. If you are on XP then you have no choice than to use SetClipboarViewer. Be aware that SetClipboardViewer is fragile, although you should have no problems if _your_ code is correct and you are the _only_ viewer. – John Knoeller Feb 09 '10 at 23:32
  • Ok, I will be very cautious. Your answer would otherwise be the best. Thanks! – Weiming Feb 10 '10 at 00:03
14

You could use SetClipboardViewer provided by Win32 API (through P/Invoke).

Here is a page which contains code to set one up in C#: http://www.codeguru.com/csharp/.net/net_general/tipstricks/article.php/c7315/

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 10
    SetClipboardViewer is an fragile, older API, you should not be using it in new code. use AddClipboardFormatListener instead. – John Knoeller Feb 09 '10 at 10:52
  • 1
    Likewise, you can also try [SharpClipboard](https://github.com/Willy-Kimura/SharpClipboard). It provides a `ClipboardChanged` event that allows you to filter various data-formats whenever they're cut/copied and get the clipboard content. – Willy Kimura Feb 07 '19 at 10:41
  • 2
    The second link is broken. – Peter Mortensen Jul 08 '19 at 20:25
3

The Win32 API contains a function SetClipboardViewer.

Here is a pretty good (from a quick glance) write up.

µBio
  • 10,668
  • 6
  • 38
  • 56