zoukankan      html  css  js  c++  java
  • 【.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 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 += $"
    数据格式:{string.Join("", fs)}";
            }

    只要监听到剪贴板被更新,那么要获取剪贴板上的数据就很容易了,因为System.Windows下面已经有一个 Clipboard 类,它有一堆静态方法,可以直接读写剪贴板上的内容。

    运行程序后,随便复制点东东到剪贴板中,就会看到程序有反应了。如下面高清无码截图所示。

    好了,本文就扯到这里了。

    本文示例源代码下载

  • 相关阅读:
    Struts2之页面取得当前actionName
    Javascript跳转页面和打开新窗口等方法
    数据集+树的一种最简单高效的算法
    TRzCheckTree的使用
    FASTSCRIPT脚本实现多国语言
    econtrol form designer添加三方控件
    内存管理六
    内存管理五
    程序启动时只显示登录窗体
    多标签主界面使用TRzPageControl
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/7182279.html
Copyright © 2011-2022 走看看