思路
Windows操作系统是基于“消息”机制运行,任何行为都有与之对应的消息,剪切板的内容变化也不列外,当剪切板的内容发生变化时会发出 WM_CLIPBOARDUPDATE 消息,所以我们的思路就是监听这个消息,如果收到了WM_CLIPBOARDUPDATE就说明是剪切板发生变化了,此时再去读取剪切板的内容即可
实现步骤
首先通过User32.dll 中的AddClipboardFormatListener 函数,将我们自己程序的主窗口句柄添加到剪切板的侦听器列表中,这样每当剪贴板的内容发生更改时,该窗口将发布WM_CLIPBOARDUPDATE 消息
[DllImport("User32.dll")]
private static extern bool AddClipboardFormatListener(IntPtr hwnd);
如果添加成功再通过HwndSource类中的AddHook函数添加一个委托,当接收到消息时会执行该委托函数,在该函数中去判断消息是否为WM_CLIPBOARDUPDATE,WM_CLIPBOARDUPDATE的值是0x031D
封装帮助类
在我的工作中经常会用到剪切板的监控,因此封装为一个帮助类更方便
public class ClipboardMonitHelper : IDisposable
{
public Action<string>? ClipboardUpdate;
private HwndSource _hwndSource;
private const int WM_CLIPBOARDUPDATE = 0x031D;
public ClipboardMonitHelper(Window window)
{
WindowInteropHelper helper = new WindowInteropHelper(window);
_hwndSource = HwndSource.FromHwnd(helper.Handle);
AddHook();
}
/// <summary>
/// 将指定窗口的句柄添加到剪切板的侦听器列表中
/// 将窗口添加到剪贴板格式侦听器列表后,每当剪贴板的内容发生更改时,该窗口将发布 WM_CLIPBOARDUPDATE 消息。
/// </summary>
/// <param name="hwnd"></param>
/// <returns></returns>
[DllImport("User32.dll")]
private static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("User32.dll")]
private static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
private void AddHook()
{
bool r = AddClipboardFormatListener(_hwndSource.Handle);
if (r)
{
_hwndSource.AddHook(new HwndSourceHook(OnHooked));
}
}
private void RemoveHook()
{
bool r = RemoveClipboardFormatListener(_hwndSource.Handle);
if (r)
{
_hwndSource.RemoveHook(new HwndSourceHook(OnHooked));
}
}
private IntPtr OnHooked(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_CLIPBOARDUPDATE)
{
string txt = Clipboard.GetText();
ClipboardUpdate?.Invoke(txt);
}
return IntPtr.Zero;
}
public void Dispose()
{
RemoveHook();
}
}
使用帮助类
public partial class MainWindow : Window
{
private ClipboardMonitHelper clipboardMonit;
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
clipboardMonit = new ClipboardMonitHelper(this);
clipboardMonit.ClipboardUpdate += OnUpdate;
}
private void OnUpdate(string obj)
{
Debug.WriteLine(obj);
}
}
特别要说明的是:要在Loaded 事件中去实例化帮助类,帮助类的构造需要传入当前程序的主窗体,然而Loaded 完成时才能生成窗体,因此需要等主窗体加载完成后才能去实例化