[Sample of Mar 7th] Monitor Windows Clipboard Changes in WPF
![]() |
![]() |
|
![]() |
![]() |
Sample download
C# version: https://code.msdn.microsoft.com/CSWPFClipboardViewer-f601b815
VB version: https://code.msdn.microsoft.com/VBWPFClipboardViewer-d3f3cbd3
Today’s code sample demonstrates how to monitor Windows clipboard changes in a WPF application. In order to be notified by the system when the clipboard content changes, an application must use the SetClipboardViewer function (user32.dll) to add its window into the chain of clipboard viewers. Clipboard viewer windows receive a WM_DRAWCLIPBOARD message whenever the content of the clipboard changes. And the WM_CHANGECBCHAIN message is sent to the first window in the clipboard viewer chain when a window is being removed from the chain. In a WPF application, we use HwndSource class to register a Win32 window message handler to process the messages. This sample also shows a workaround for a known issue in WPF Clipboard.GetImage() method.
The sample was written by our star sample writer: Jie Wang.
You can find more code samples that demonstrate the most typical programming scenarios by using Microsoft All-In-One Code Framework Sample Browser or Sample Browser Visual Studio extension. They give you the flexibility to search samples, download samples on demand, manage the downloaded samples in a centralized place, and automatically be notified about sample updates. If it is the first time that you hear about Microsoft All-In-One Code Framework, please watch the introduction video on Microsoft Showcase, or read the introduction on our homepage https://1code.codeplex.com/.
Introduction
This Sample demonstrates how to monitor Windows clipboard changes in a WPF application. In order to be notified by the system when the clipboard content changes, an application must use the SetClipboardViewer function (user32.dll) to add its window into the chain of clipboard viewers. Clipboard viewer windows receive a WM_DRAWCLIPBOARD message whenever the content of the clipboard changes. And the WM_CHANGECBCHAIN message is sent to the first window in the clipboard viewer chain when a window is being removed from the chain. In a WPF application, we use HwndSource class to register a Win32 window message handler to process the messages. This sample also shows a workaround for a known issue in WPF Clipboard.GetImage() method.
Running the Sample
Press F5 to run this application, you will see following result.
Using the Code
Gets the window handle for a Windows Presentation Foundation (WPF).
Adds an event handler to handle the clipboard message.
private void InitCBViewer()
{
WindowInteropHelper wih = new WindowInteropHelper(this);
hWndSource = HwndSource.FromHwnd(wih.Handle);
hWndSource.AddHook(this.WinProc); // start processing window messages
hWndNextViewer = Win32.SetClipboardViewer(hWndSource.Handle); // set this window as a viewer
isViewing = true;
}
private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
if (wParam == hWndNextViewer)
{
// clipboard viewer chain changed, need to fix it.
hWndNextViewer = lParam;
}
else if (hWndNextViewer != IntPtr.Zero)
{
// pass the message to the next viewer.
Win32.SendMessage(hWndNextViewer, msg, wParam, lParam);
}
break;
case Win32.WM_DRAWCLIPBOARD:
// clipboard content changed
this.DrawContent();
// pass the message to the next viewer.
Win32.SendMessage(hWndNextViewer, msg, wParam, lParam);
break;
}
return IntPtr.Zero;
}
Draw content in the window
private void DrawContent()
{
pnlContent.Children.Clear();
if (Clipboard.ContainsText())
{
// we have some text in the clipboard.
TextBox tb = new TextBox();
tb.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
tb.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
tb.Text = Clipboard.GetText();
tb.IsReadOnly = true;
tb.TextWrapping = TextWrapping.NoWrap;
pnlContent.Children.Add(tb);
}
else if (Clipboard.ContainsFileDropList())
{
// we have a file drop list in the clipboard
ListBox lb = new ListBox();
lb.ItemsSource = Clipboard.GetFileDropList();
pnlContent.Children.Add(lb);
}
else if (Clipboard.ContainsImage())
{
// Because of a known issue in WPF,
// we have to use a workaround to get correct
// image that can be displayed.
// The image have to be saved to a stream and then
// read out to workaround the issue.
MemoryStream ms = new MemoryStream();
BmpBitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(Clipboard.GetImage()));
enc.Save(ms);
ms.Seek(0, SeekOrigin.Begin);
BmpBitmapDecoder dec = new BmpBitmapDecoder(ms,
BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
Image img = new Image();
img.Stretch = Stretch.Uniform;
img.Source = dec.Frames[0];
pnlContent.Children.Add(img);
}
else
{
Label lb = new Label();
lb.Content = "The type of the data in the clipboard is not supported by this sample.";
pnlContent.Children.Add(lb);
}
}