基于观察链和窗口通知发送实现监控剪切板

引入相关命名空间

using System.Runtime.InteropServices;//引用Win32 DLL需此命名空间
using System.Windows.Forms;//Clipboard类命名空间

引入Win32 DLL

    /// <summary>
    /// 将CWnd加入一个窗口链,每当剪贴板的内容发生变化时,就会通知这些窗口
    /// </summary>
    /// <param name="hWndNewViewer">句柄</param>
    /// <returns>返回剪贴板观察器链中下一个窗口的句柄</returns>
    [DllImport("User32.dll")]
    protected static extern int SetClipboardViewer(int hWndNewViewer);
 
    /// <summary>
    /// 从剪贴板链中移出的窗口句柄
    /// </summary>
    /// <param name="hWndRemove">从剪贴板链中移出的窗口句柄</param>
    /// <param name="hWndNewNext">hWndRemove的下一个在剪贴板链中的窗口句柄</param>
    /// <returns>如果成功,非零;否则为0。</returns>
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
 
    /// <summary>
    /// 将指定的消息发送到一个或多个窗口
    /// </summary>
    /// <param name="hwnd">其窗口程序将接收消息的窗口的句柄</param>
    /// <param name="wMsg">指定被发送的消息</param>
    /// <param name="wParam">指定附加的消息特定信息</param>
    /// <param name="lParam">指定附加的消息特定信息</param>
    /// <returns>消息处理的结果</returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

重写窗口的WindowsSystem.Windows.Forms.Message方法以实现在RichTextBox中显示剪切板内容

IntPtr nextClipboardViewer;
    public Form()
    {
        InitializeComponent();
        nextClipboardViewer = (IntPtr)SetClipboardViewer((int)Handle);
    }
 
    /// <summary>
    /// 要处理的 WindowsSystem.Windows.Forms.Message。
    /// </summary>
    /// <param name="m"></param>
    protected override void WndProc(ref Message m)
    {
        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;
 
        switch (m.Msg)
        {
            case WM_DRAWCLIPBOARD:
                DisplayClipboardData();
                SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;
            case WM_CHANGECBCHAIN:
                if (m.WParam == nextClipboardViewer)
                    nextClipboardViewer = m.LParam;
                else
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }
    /// <summary>
    /// 显示剪贴板内容
    /// </summary>
    public void DisplayClipboardData()
    {
        try
        {
            IDataObject iData = new DataObject();
            iData = Clipboard.GetDataObject();
 
            if (iData.GetDataPresent(DataFormats.Rtf))
                richTextBox1.Rtf = (string)iData.GetData(DataFormats.Rtf);
            else if (iData.GetDataPresent(DataFormats.Text))
                richTextBox1.Text = (string)iData.GetData(DataFormats.Text);
            else
                richTextBox1.Text = "[Clipboard data is not RTF or ASCII Text]";
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());
        }
    }
 
    /// <summary>
    /// 关闭程序,从观察链移除
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form_FormClosed(object sender, FormClosedEventArgs e)
    {
        ChangeClipboardChain(Handle, nextClipboardViewer);
    }

总结

使用 SetClipboardViewer将窗口加入剪切板的观察链,当剪切板发生变化时使用 SendMessage将消息发送至当前窗口,再通过重写 WindowsSystem.Windows.Forms.Message来接受剪切板窗口传来的消息并判断是否为文本/富文本实现监控剪切板的效果。

Last modification:April 29th, 2021 at 12:21 am
如果喜欢可以赞赏哦~