標籤:cte das nbsp 技術分享 封裝 rdl use void .com
針對 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);
在Managed 程式碼中調用它,要先進行匯入。
[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;
還有一件事,各位會發現,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之後系統)