【.net 深呼吸】監聽剪貼板更新(針對Vista之後系統)
針對 XP 及以前的監視剪貼板更改的方法就不講了,因為 XP 已嚴重過時。本篇老周介紹的方法面向 Vista 以上的系統。
在托管應用程序中監聽剪貼板更新行為必須用到 Win 32 API ,具體做法,我先簡單說一下。
首先,調用 AddClipboardFormatListener 函數來向窗口註冊監聽行為,它需要一個窗口句柄作為傳入參數,該句柄所指的窗口即是監聽剪貼板更新的窗口。
然後,當剪貼板的內容被更新,處理程序會收到一條 WM_CLIPBOARDUPDATE 消息。我們在應用程序中,只要收到這條消息,就說明剪貼板的內容已被更新。
WM_CLIPBOARDUPDATE 消息的宏定義如下:
#define WM_CLIPBOARDUPDATE 0x031D
這個消息的 wParam 和 lParam 參數都不曾使用,所以我們不必理會這兩個參數值。如果用戶已處理該消息,應當返回 0。
AddClipboardFormatListener 函數的原型如下:
BOOL WINAPI AddClipboardFormatListener(
_In_ HWND hwnd
);
在托管代碼中調用它,要先進行導入。
[DllImport("User32.dll")] static externbool AddClipboardFormatListener(IntPtr hwnd);
好,基本理論說完了,下面我們來看看如何在WPF程序中監聽剪貼板更新。
由於此功能實為WPF與 Win32 的交互操作,因此,要用到 HwndSource 類,這個類公開了一個 AddHook 方法,調用這個方法可以添加一個 HwndSourceHook 委托實例,當窗口接收到消息時,就會調用這個委托。
該委托的定義如下。
delegate IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, refbool handled);
你一定會猛然發現,這個委托很像 WinProc 函數指針。msg 參數就是被攔截到的消息。在與該委托綁定的方法中,我們可以對收到的消息進行篩選,因為我們這裏只關心 WM_CLIPBOARDUPDATE 消息,其他的咱們不管。
private IntPtr OnHooked(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WM_CLIPBOARDUPDATE) { ClipboardUpdated?.Invoke(this, EventArgs.Empty); return IntPtr.Zero; } return IntPtr.Zero; }
ClipboardUpdated 事件是我封裝時定義的,這是為了方便引發。
public event EventHandler ClipboardUpdated;
還有一件事,各位會發現,HwndSource 實例創建時需要與一個窗口的句柄綁定,那麽,如何獲取到 Window 實例的句柄呢,這就要用到一個幫助類—— WindowInteropHelper。有了它,想得到窗口的句柄就很簡單了。
WindowInteropHelper helper = new WindowInteropHelper(window); _hwndSource = HwndSource.FromHwnd(helper.Handle);
在添加 hook 處理之前,一定要記得調用 AddClipboardFormatListener 函數為窗口註冊監聽行為。
bool r = AddClipboardFormatListener(_hwndSource.Handle);
要是監聽行為註冊成功,就可以添加 hook 了。
if (r) { _hwndSource.AddHook(new HwndSourceHook(OnHooked)); }
那麽,咱們封裝的這些代碼如何用到窗口代碼中呢。Window 有一個 SourceInitialized 事件,當句柄初始化完成就會發生。我們可以重寫 OnSourceInitialized 方法,然後在方法中使用我們上面封裝的代碼。
ClipboardHooker m_clipboardHooker; protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); m_clipboardHooker = new ClipboardHooker(this); m_clipboardHooker.ClipboardUpdated += OnClipboardUpdated; } private void OnClipboardUpdated(object sender, EventArgs e) { tb.Text = "老板,有人修改了剪貼板。"; IDataObject data = Clipboard.GetDataObject(); string[] fs = data.GetFormats(); tb.Text += $"\n數據格式:{string.Join("、", fs)}"; }
只要監聽到剪貼板被更新,那麽要獲取剪貼板上的數據就很容易了,因為System.Windows下面已經有一個 Clipboard 類,它有一堆靜態方法,可以直接讀寫剪貼板上的內容。
運行程序後,隨便復制點東東到剪貼板中,就會看到程序有反應了。如下面高清無碼截圖所示。
好了,本文就扯到這裏了。
本文示例源代碼下載
【.net 深呼吸】監聽剪貼板更新(針對Vista之後系統)