WndProc を Hook する
前述のように,Clipboard が更新されたことを知るためには,対象となるフォームのウィンドウプロシージャを override する必要があります.でも,何となく Clipboard のために override した WndProc を,Form のコードに書きたくないなぁ,とか思ったので,ウィンドウプロシージャを Hook することにしました.調べてみると,NativeWindow クラス (System.Windows.Forms) という,便利なクラスがあります.
これを使ってみることにしました.
public class ClipboardHelper { #region イベント定義 /// <summary> /// クリップボードの内容が更新されたときに発生するイベント /// </summary> public event EventHandler DrawClipboard = null; protected void OnDrawClipboard() { if (this.DrawClipboard != null) { this.DrawClipboard(this, new EventArgs()); } } #endregion /// <summary> /// ウィンドウプロシージャをHookするクラス /// </summary> private class Hook : NativeWindow { private ClipboardHelper _helper = null; private IntPtr nextHandle = IntPtr.Zero; private const int WM_DRAWCLIPBOARD = 0x0308; private const int WM_CHANGECBCHAIN = 0x030D; [DllImport("user32.dll")] private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer); [DllImport("user32.dll")] private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext); [DllImport("user32.dll", CharSet = CharSet.Auto)] private extern static int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); public Hook(Form target, ClipboardHelper helper) { target.Load += new EventHandler(target_Load); target.FormClosed += new FormClosedEventHandler(target_FormClosed); target.HandleCreated += new EventHandler(target_HandleCreated); target.HandleDestroyed += new EventHandler(target_HandleDestroyed); this._helper = helper; } void target_Load(object sender, EventArgs e) { this.nextHandle = SetClipboardViewer(((Form)sender).Handle); } void target_FormClosed(object sender, FormClosedEventArgs e) { ChangeClipboardChain(((Form)sender).Handle, this.nextHandle); } void target_HandleCreated(object sender, EventArgs e) { AssignHandle(((Form)sender).Handle); } void target_HandleDestroyed(object sender, EventArgs e) { ReleaseHandle(); } protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_DRAWCLIPBOARD: this._helper.OnDrawClipboard(); if (this.nextHandle != IntPtr.Zero) { SendMessage(this.nextHandle, m.Msg, m.WParam, m.LParam); } break; case WM_CHANGECBCHAIN: if ((IntPtr)m.WParam == this.nextHandle) { this.nextHandle = (IntPtr)m.LParam; } else if (this.nextHandle != IntPtr.Zero) { SendMessage(this.nextHandle, m.Msg, m.WParam, m.LParam); } break; } base.WndProc(ref m); } } private Hook hook = null; public ClipboardHelper(Form wnd) { this.hook = new Hook(wnd, this); } }