There are multiple ways of doing this but this is my favorite and works for me. I've created a class library so that others may add the project and include the DLL then simply call on it and use it wherever they want within their applications.
This answer was made with the help of this one.
- Create Class Library project and name it ClipboardHelper.
- Replace the Class1 name with ClipboardMonitor.
- Add the below code into it.
- Add System.Windows.Forms reference.
More steps under code.
using System;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace ClipboardHelper
{
public static class ClipboardMonitor
{
public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
public static event OnClipboardChangeEventHandler OnClipboardChange;
public static void Start()
{
ClipboardWatcher.Start();
ClipboardWatcher.OnClipboardChange += (ClipboardFormat format, object data) =>
{
if (OnClipboardChange != null)
OnClipboardChange(format, data);
};
}
public static void Stop()
{
OnClipboardChange = null;
ClipboardWatcher.Stop();
}
class ClipboardWatcher : Form
{
// static instance of this form
private static ClipboardWatcher mInstance;
// needed to dispose this form
static IntPtr nextClipboardViewer;
public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
public static event OnClipboardChangeEventHandler OnClipboardChange;
// start listening
public static void Start()
{
// we can only have one instance if this class
if (mInstance != null)
return;
var t = new Thread(new ParameterizedThreadStart(x => Application.Run(new ClipboardWatcher())));
t.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
t.Start();
}
// stop listening (dispose form)
public static void Stop()
{
mInstance.Invoke(new MethodInvoker(() =>
{
ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);
}));
mInstance.Invoke(new MethodInvoker(mInstance.Close));
mInstance.Dispose();
mInstance = null;
}
// on load: (hide this window)
protected override void SetVisibleCore(bool value)
{
CreateHandle();
mInstance = this;
nextClipboardViewer = SetClipboardViewer(mInstance.Handle);
base.SetVisibleCore(false);
}
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
// defined in winuser.h
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
ClipChanged();
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;
}
}
static readonly string[] formats = Enum.GetNames(typeof(ClipboardFormat));
private void ClipChanged()
{
IDataObject iData = Clipboard.GetDataObject();
ClipboardFormat? format = null;
foreach (var f in formats)
{
if (iData.GetDataPresent(f))
{
format = (ClipboardFormat)Enum.Parse(typeof(ClipboardFormat), f);
break;
}
}
object data = iData.GetData(format.ToString());
if (data == null || format == null)
return;
if (OnClipboardChange != null)
OnClipboardChange((ClipboardFormat)format, data);
}
}
}
public enum ClipboardFormat : byte
{
/// Specifies the standard ANSI text format. This static field is read-only.
///
/// 1
Text,
/// Specifies the standard Windows Unicode text format. This static field
/// is read-only.
/// 1
UnicodeText,
/// Specifies the Windows device-independent bitmap (DIB) format. This static
/// field is read-only.
/// 1
Dib,
/// Specifies a Windows bitmap format. This static field is read-only.
/// 1
Bitmap,
/// Specifies the Windows enhanced metafile format. This static field is
/// read-only.
/// 1
EnhancedMetafile,
/// Specifies the Windows metafile format, which Windows Forms does not
/// directly use. This static field is read-only.
/// 1
MetafilePict,
/// Specifies the Windows symbolic link format, which Windows Forms does
/// not directly use. This static field is read-only.
/// 1
SymbolicLink,
/// Specifies the Windows Data Interchange Format (DIF), which Windows Forms
/// does not directly use. This static field is read-only.
/// 1
Dif,
/// Specifies the Tagged Image File Format (TIFF), which Windows Forms does
/// not directly use. This static field is read-only.
/// 1
Tiff,
/// Specifies the standard Windows original equipment manufacturer (OEM)
/// text format. This static field is read-only.
/// 1
OemText,
/// Specifies the Windows palette format. This static field is read-only.
///
/// 1
Palette,
/// Specifies the Windows pen data format, which consists of pen strokes
/// for handwriting software, Windows Forms does not use this format. This static
/// field is read-only.
/// 1
PenData,
/// Specifies the Resource Interchange File Format (RIFF) audio format,
/// which Windows Forms does not directly use. This static field is read-only.
/// 1
Riff,
/// Specifies the wave audio format, which Windows Forms does not directly
/// use. This static field is read-only.
/// 1
WaveAudio,
/// Specifies the Windows file drop format, which Windows Forms does not
/// directly use. This static field is read-only.
/// 1
FileDrop,
/// Specifies the Windows culture format, which Windows Forms does not directly
/// use. This static field is read-only.
/// 1
Locale,
/// Specifies text consisting of HTML data. This static field is read-only.
///
/// 1
Html,
/// Specifies text consisting of Rich Text Format (RTF) data. This static
/// field is read-only.
/// 1
Rtf,
/// Specifies a comma-separated value (CSV) format, which is a common interchange
/// format used by spreadsheets. This format is not used directly by Windows Forms.
/// This static field is read-only.
/// 1
CommaSeparatedValue,
/// Specifies the Windows Forms string class format, which Windows Forms
/// uses to store string objects. This static field is read-only.
/// 1
StringFormat,
/// Specifies a format that encapsulates any type of Windows Forms object.
/// This static field is read-only.
/// 1
Serializable,
}
}
- In your other projects right click on solution and Add -> Exiting Project -> ClipboardHelper.csproj
- On your project go to and right click References -> Add Reference -> Solution -> Select ClipboardHelper.
- In your class file of the project type using ClipboardHelper.
-
You may now type ClipboardMonitor.Start or .Stop or .OnClipboardChanged
using ClipboardHelper; namespace Something.Something.DarkSide { public class MainWindow { public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } void MainWindow_Loaded(object sender, RoutedEventArgs e) { ClipboardMonitor.OnClipboardChanged += ClipboardMonitor_OnClipboardChange; ClipboardMonitor.Start; } private void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data) { // Do Something... } }