views:

3273

answers:

5
+16  Q: 

Clipboard event C#

Is there a clipboard changed or updated event that i can access through C#?

+14  A: 

I think you'll have to use some p/invoke:

[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

See this article on how to set up a clipboard monitor in c#

Basically you register you app as a clipboard viewer using

_ClipboardViewerNext = SetClipboardViewer(this.Handle);

and then you will recieve the WM_DRAWCLIPBOARD message, which you can handle by overriding WndProc:

protected override void WndProc(ref Message m)
{
    switch ((Win32.Msgs)m.Msg)
    {
        case Win32.Msgs.WM_DRAWCLIPBOARD:
        // Handle clipboard changed
        break;
        // ... 
   }
}

(There's more to be done; passing things along the clipboard chain and unregistering your view, but you can get that from the article)

Daniel LeCheminant
+2  A: 

Check out the SetClipboardViewer, ChangeClipboardChain and SendMessage API calls.

Here's a good article that explains how to trap Clipboard change notifications. And another.

Cerebrus
+13  A: 

For completeness, here's the control I'm using in production code. Just drag from the designer and double click to create the event handler.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace ClipboardAssist {

// Must inherit Control, not Component, in order to have Handle
[DefaultEvent("ClipboardChanged")]
public partial class ClipboardMonitor : Control 
{
    IntPtr nextClipboardViewer;

    public ClipboardMonitor()
    {
        this.BackColor = Color.Red;
        this.Visible = false;

        nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
    }

    /// <summary>
    /// Clipboard contents changed.
    /// </summary>
    public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;

    protected override void Dispose(bool disposing)
    {
        ChangeClipboardChain(this.Handle, nextClipboardViewer);
    }

    [DllImport("User32.dll")]
    protected static extern int SetClipboardViewer(int hWndNewViewer);

    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                OnClipboardChanged();
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            case WM_CHANGECBCHAIN:
                if (m.WParam == nextClipboardViewer)
                    nextClipboardViewer = m.LParam;
                else
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;

            default:
                base.WndProc(ref m);
                break;
        }
    }

    void OnClipboardChanged()
    {
        try
        {
            IDataObject iData = Clipboard.GetDataObject();
            if (ClipboardChanged != null)
            {
                ClipboardChanged(this, new ClipboardChangedEventArgs(iData));
            }

        }
        catch (Exception e)
        {
            // Swallow or pop-up, not sure
            // Trace.Write(e.ToString());
            MessageBox.Show(e.ToString());
        }
    }
}

public class ClipboardChangedEventArgs : EventArgs
{
    public readonly IDataObject DataObject;

    public ClipboardChangedEventArgs(IDataObject dataObject)
    {
        DataObject = dataObject;
    }
}
}
dbkk
Great Job! Your event calling code is not thread safe, though. You should either create a local copy, or init the event with an empty delegate. You also forgot the 'event' keyword in the definition of ClipboardChanged :)
ohadsc
@ohadsc Thank you for the corrections. As far as I know, WndProc is called on the UI thread. Since the class derives from Control, clients should call it on UI thread as well.
dbkk
A: 

Hi .. i know this is a little bit old, but iam working on a small project to catch the Clipboard changes ...

the code works great BUT: if you add a notifyicon and minimize the form to tray and turn the showintaskbar to false, the program wont catch any clipboard changes anymore ... even if you maximize the form back, it wont work again ...you have to restart the program ..

any idea on how to solve this issue !? how can i catch clipboard changes, even if the form is minimized into the tray !?

lebhero
You should create your own question in a new thread.
Anna Lear
I think this deserves its own question
Sevki
A: 

hi ... i tested the code above, working great.. but on some applications like firefox, the event will fire twice, that means when you copy something from firefox, the clipboardtext (or object) will be set twice in the clipboard ??and the event will be fired 2 times .... i am not sure what`s happening..

any help on this ?

thanks

testerCB
You should really post this as a new question (maybe with a link to this one).
Oliver