針對 XP 及以前的監視剪貼板更改的方法就不講了, 因為 XP 已嚴重過時。 本篇老周介紹的方法面向 Vista 以上的系統。
在託管應用程式中監聽剪貼板更新行為必須用到 Win 32 API , 具體做法, 我先簡單說一下。
首先, 調用 AddClipboardFormatListener 函數來向視窗註冊監聽行為, 它需要一個視窗控制碼作為傳入參數, 該控制碼所指的視窗即是監聽剪貼板更新的窗口。
然後, 當剪貼板的內容被更新, 處理常式會收到一條 WM_CLIPBOARDUPDATE 消息。 我們在應用程式中, 只要收到這條消息, 就說明剪貼板的內容已被更新。
WM_CLIPBOARDUPDATE 消息的巨集定義如下:
#define WM_CLIPBOARDUPDATE 0x031D這個消息的 wParam和lParam參數都不曾使用,
AddClipboardFormatListener 函數的原型如下:
BOOL WINAPI AddClipboardFormatListener( _In_ HWND hwnd );在託管代碼中調用它, 要先進行導入。
[DllImport("User32.dll")] static extern bool AddClipboardFormatListener(IntPtr hwnd);好, 基本理論說完了, 下面我們來看看如何在WPF程式中監聽剪貼板更新。
由於此功能實為WPF與 Win32 的交交互操作, 因此, 要用到 HwndSource 類, 這個類公開了一個 AddHook 方法, 調用這個方法可以添加一個 HwndSourceHook 委託實例, 當視窗接收到消息時, 就會調用這個委託。
該委託的定義如下。
delegate IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool 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;還有一件事, 各位會發現,
在添加 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 += $" 資料格式:{string.Join("、", fs)}"; }只要監聽到剪貼板被更新, 那麼要獲取剪貼板上的資料就很容易了, 因為System.Windows下面已經有一個 Clipboard 類, 它有一堆靜態方法, 可以直接讀寫剪貼板上的內容。
運行程式後, 隨便複製點東東到剪貼板中,
好了, 本文就扯到這裡了。