【.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 += $"\n数据格式:{string.Join("、", fs)}";
        }

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

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

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

本文示例源代码下载

时间: 2024-07-30 20:23:56

【.net 深呼吸】监听剪贴板更新(针对Vista之后系统)的相关文章

【laravel】Eloquent 模型事件和监听方式

所有支持的模型事件 在 Eloquent 模型类上进行查询.插入.更新.删除操作时,会触发相应的模型事件,不管你有没有监听它们.这些事件包括: retrieved 获取到模型实例后触发 creating 插入到数据库前触发 created 插入到数据库后触发 updating 更新到数据库前触发 updated 更新到数据库后触发 saving 保存到数据库前触发(插入/更新之前,无论插入还是更新都会触发) saved 保存到数据库后触发(插入/更新之后,无论插入还是更新都会触发) deleti

设置IIS服务器监听特定IP的特定端口(IIS与IHS或Apache共存的解决方案)

在灾难恢复的试验中,遇到了一个IIS无法启动的情况,会报如下的错误: "The network location cannot be reached, xxxxxx" 要知道,Windows报的这种弹窗错误,也只能通过Windows自带的事件管理器里查看了.直接运行:eventvwr,打开SYSTEM项,一个大大的错误映入眼帘: 所以错误就很明显了,没有把我们的新地址添加到监听列表里... 根据搜索,发现仅仅用IIS的图形界面工具,似乎无法让IIS去监听某一个IP地址的某个端口,必须要

Oracle Enterprise Linux 64-bit 下Oracle11g的监听配置改动及測试步骤

測试环境:Oracle Enterprise Linux 64-bit (5.8版本号) + Oracle 11g 64位 相关说明: Oracle11g64位软件的安装位置为/u01/app/oracle/product/11.2.0/dbhome_1 ,数据库名为默认的orcl,Linux虚拟机的IP设置为192.168.1.121 一.改动listener.ora文件内容 命令:[[email protected] ~]$ vi /u01/app/oracle/product/11.2.0

11g R2 rac linstener 监听配置

两个节点host,ipvip ,scan的信息 #eth0-Public IP 162.12.0.1    cqltjcpt1 162.12.0.3    cqltjcpt2 #eth1 PRIVATE IP 192.12.0.1   cqltjcpt1-prvi 192.12.0.3   cqltjcpt2-prvi #VIP 162.12.0.5   cqltjcpt1-vip 162.12.0.7   cqltjcpt2-vip #SCAN 162.12.0.9   cqltjcptsca

Oracle Enterprise Linux 64-bit 下Oracle11g的监听配置修改及测试步骤

测试环境:Oracle Enterprise Linux 64-bit (5.8版本) + Oracle 11g 64位 相关说明: Oracle11g64位软件的安装位置为/u01/app/oracle/product/11.2.0/dbhome_1 ,数据库名为默认的orcl,Linux虚拟机的IP设置为192.168.1.121 一.修改listener.ora文件内容 命令:[[email protected] ~]$ vi /u01/app/oracle/product/11.2.0/

ORA-12514:TNS 监听问题

解决问题:ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 测试环境:RedHat7.4 + Oracle 11g 64位 相关说明: 数据库服务器: Oracle11g 64位软件的安装位置为/u01/app/oracle/product/11.2.0/dbhome_1,数据库名为默认的orcl, RedHat7.4虚拟机的IP设置为:192.168.8.13 Windows10客户端: 1.PLSQL安装位置:E:\Program Files\PLSQL Develope

RN性能优化及事件监听

自从React Native出世,虽然官方一直尽可能的优化其性能,为了能让其媲美原生App的速度,但是现实感觉有点不尽人意.接下来介绍下实践中遇到的一些性能问题以及优化方案. 一.StackNavigator页面切换动画优化 场景:在navigation还没出来时,导航路由使用NavigatorIOS来实现,页面切换是很流畅的,但是用了StackNavigator navigation发现页面切换会使JS线程出现严重的掉帧(卡顿现象): 原因:NavigatorIOS的切换动画是跑在UI主线程上

Vue2.X监听data变化的核心API—Object.defineProperty详解

Vue2.X监听data变化的核心API—Object.defineProperty基本使用: Object.defineProperty实现响应式 1.监听对象(简单对象) 上面通过监听get,set方法了解到data变化,进而可以达到响应式. 2.复杂对象(深度监听),深度监听 触发更新视图 // 触发更新视图 function updateView() { console.log('视图更新') } 在上面例子data加: // 准备数据 const data = { name: '佩奇'

oracle 监听服务自动停止与无法启动问题

描述:监听服务莫名其妙终止,必须手动启动. 网上关于该问题的资料很多,总结下来,有以下几点 1.地址使用了主机名,修改Host文件和监听文件即可解决该问题. 2.防火墙作怪. 3.安全软件的优化功能作怪. 4.环境变量有问题 但是,我们这边的情况比较复杂,在尝试关闭防火墙,修改host文件等,还原优化选项,查看环境变量等操作之后,仍有主机出现该问题. 分析:1.不是所有主机都会产生该问题,大致先排除服务器问题,2.可能某些网络原因导致监听服务停止.3.系统方面导致的该问题.因为该问题具有随机性,