C#|クリップボードの変更を監視するのWPF版。
クリップボードに変更があるとDrawClipBoardイベントを発生するクラス。
使用後は必ずDisposeする必要がある。
using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
/// <summary>
/// クリップボードを監視するクラス。
/// 使用後は必ずDispose()メソッドを呼び出して下さい。
/// </summary>
public class ClipboardWatcher: IDisposable {
[DllImport("user32.dll")]
private static extern IntPtr SetClipboardViewer(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool ChangeClipboardChain(IntPtr hwnd, IntPtr hWndNext);
const int WM_DRAWCLIPBOARD = 0x0308;
const int WM_CHANGECBCHAIN = 0x030D;
IntPtr nextHandle;
IntPtr handle;
HwndSource hwndSource = null;
/// <summary>
/// クリップボードに内容に変更があると発生します。
/// </summary>
public event EventHandler DrawClipboard;
/// <summary>
/// ClipBoardWatcherクラスを初期化して
/// クリップボードビューアチェインに登録します。
/// 使用後は必ずDispose()メソッドを呼び出して下さい。
/// </summary>
public ClipboardWatcher(IntPtr handle) {
this.hwndSource = HwndSource.FromHwnd(handle);
this.hwndSource.AddHook(this.WndProc);
this.handle = handle;
this.nextHandle = SetClipboardViewer(this.handle);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_DRAWCLIPBOARD)
{
SendMessage(nextHandle, msg, wParam, lParam);
this.raiseDrawClipboard();
handled = true;
}
else if (msg == WM_CHANGECBCHAIN)
{
if (wParam == nextHandle)
{
nextHandle = lParam;
}
else
{
SendMessage(nextHandle, msg, wParam, lParam);
}
handled = true;
}
return IntPtr.Zero;
}
private void raiseDrawClipboard() {
if(DrawClipboard != null) {
DrawClipboard(this, EventArgs.Empty);
}
}
/// <summary>
/// ClipBoardWatcherクラスを
/// クリップボードビューアチェインから削除します。
/// </summary>
public void Dispose() {
ChangeClipboardChain(this.handle, nextHandle);
this.hwndSource.Dispose();
}
}
以下の様に使用する。
using System.Windows;
/// <summary>
/// Window1.xaml の相互作用ロジック
/// </summary>
public partial class Window1 : Window
{
ClipboardWatcher clipboardWatcher = null;
public Window1()
{
InitializeComponent();
this.clipboardWatcher = new ClipboardWatcher(new System.Windows.Interop.WindowInteropHelper(this).Handle);
this.clipboardWatcher.DrawClipboard += clipboardWatcher_DrawClipboard;
}
void clipboardWatcher_DrawClipboard(object sender, System.EventArgs e)
{
if (Clipboard.ContainsText())
{
this.listBox1.Items.Add(Clipboard.GetText());
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.clipboardWatcher.Dispose();
}
}
独力でやろうとしていたのですがなかなかうまくいかず悩んでいたところでした。
ありがとうございます。
Window1の方のコードで、
this.clipboardWatcher = new ClipboardWatcher(new System.Windows.Interop.WindowInteropHelper(this).Handle);
のところですが、ウィンドウの表示を待ってあげないとハンドルが取得できないことがあるので、
Loadedの中で記述してあげると良いのかなと思ってます。
確かにハンドルの取り損ねはありそうですね。ご指摘ありがとうございます。