Monitor clipboard in C#
The best way of monitoring the data in the clipboard through your application is by adding your application’s window to the chain of clipboard viewers so it can receive the WM_DRAWCLIPBOARD
message when the clipboard data is modified.
In order to do that we need to make use of the Windows SetClipboardViewer
and ChangeClipboardChain
APIs in order to monitor when the WM_DRAWCLIPBOARD
message triggers.
First we will need to pinvoke SetClipboardViewer
and ChangeClipboardChain
and WM_DRAWCLIPBOARD
and also set the variables that will hold the value for the next window in the chain that is required when we will want to stop our window from monitoring the clipboard. Place the following in your class.
1 2 3 4 5 6 7 8 | [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer); [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext); private const int WM_DRAWCLIPBOARD = 0x0308; // WM_DRAWCLIPBOARD message private IntPtr _clipboardViewerNext; // Our variable that will hold the value to identify the next window in the clipboard viewer chain |
Add your window to the chain of clipboard viewers so we can monitor the clipboard. Place the following either in your form’s constructor or in any of the on load events
.
1 | _clipboardViewerNext = SetClipboardViewer(this.Handle); // Adds our form to the chain of clipboard viewers. |
Next will be our WndProc method override that will monitor the window messages. Note that there are a few more DataFormats
that can be used, so feel free to experiment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | protected override void WndProc(ref Message m) { base.WndProc(ref m); // Process the message if (m.Msg == WM_DRAWCLIPBOARD) { IDataObject iData = Clipboard.GetDataObject(); // Clipboard's data if (iData.GetDataPresent(DataFormats.Text)) { string text = (string)iData.GetData(DataFormats.Text); // Clipboard text // do something with it } else if (iData.GetDataPresent(DataFormats.Bitmap)) { Bitmap image = (Bitmap)iData.GetData(DataFormats.Bitmap); // Clipboard image // do something with it } } } |
And finally it’s cleaning up time. Make sure to remove your window from the clipboard viewers chain before closing the form.
1 2 3 4 | private void Form1_FormClosing(object sender, FormClosingEventArgs e) { ChangeClipboardChain(this.Handle, _clipboardViewerNext); // Removes our from the chain of clipboard viewers when the form closes. } |
Note: There is a new Windows function now that is the recommended one if you want to target machines that are running Windows Vista and up. For more information take a look at Monitor for clipboard changes using AddClipboardFormatListener.
Thank you
Works great!!!!!!
thanks
Works perfectly!!!
So if i want to use this in a console application “this.handle” isn’t available, and base.WndPrc isnt either. Do you know of a solution ?
In order to get the handle of process in a console application you will have to use something similar to Process.GetCurrentProcess().MainWindowHandle.
As for handling the messages, you will need to create a window handle in your application in order to be able to receive (therefore process) the messages.
Take a look at the two solutions mentioned in http://stackoverflow.com/questions/2061167/how-to-receive-the-windows-messages-without-a-windows-form
This is really a great solution and has helped me a lot with a program that has to capture data from the clipboard by sending ctrl+c to other applications.
Thank you very much!
Glad to hear that the above solution helped you Riffer.
Thanks for taking the time to post your results :)