用 C# 监视剪贴板的活动状态

原文地址:http://www.developer.com/net/csharp/article.php/3359891,翻译的不好的地方望指出。



概述

当剪贴板上的数据被修改时,Windows 保持一张要求被通知的窗口链表。每次剪贴板上的数据被修改,在链表中的第一个窗口接到 WM_DRAWCLIPBOARD 消息。这个窗口然后可以查询剪贴板关于它包含的数据类型(如 RTF,ASCII 文本等)与实际的数据。因为没有加入一个窗口到通知链表的托管(.NET)API,你必须使用 SetClipboardViewer Win32 函数。虽然这是一个简单的过程,当使用这个函数时你应该知道一些一般性指导原则 :

  • 当调用 SetClipboardViewer 函数时,你需要通过这个窗口的句柄接收 WM_DRAWCLIPBOARD 消息。
    SetClipboardViewer 函数返回在链表中的目前第一个窗口。你的应用程序应该存储这个值——典型的一个类的成员——因为每个窗口得到 WM_DRAWCLIPBOARD 消息必须发送相同的消息给在链表中的下个窗口(通过 SendMessage 函数)。
  • 处理 WM_DRAWCLIPBOARD 消息。可以提供一个 Form 类超载 WndProc 类成员函数做到。不久你会看到一个例子。
  • 处理 WM_CHANGECBCHAIN  消息。因为每个窗口处理 WM_DRAWCLIPBOARD 消息时负责发送这一消息给在链表中的下个窗口,还必须知道什么时候该链表变化。当一个窗口从链表中删除自己时剪贴板发送 WM_CHANGECBCHAIN 消息。
  • 从链表中删除窗口。这个任务通过 ChangeClipboardChain Win32 函数完成,剪贴板监视不再需要时它随时可以完成。
一步一步的教导
  1. 概述里提到的,在你的程序里你需要调用几个 Win32函数——SetClipboardViewer, ChangeClipboardChainSendMessage。为了在 .NET 程序里做到这点,你首先要用 DllImport 属性(驻留在 System.Runtime.InteropServices 名称空间里)导入这些函数。下面的例子导入这些函数在演示应用程序的 Form 类中:

    using  System.Runtime.InteropServices;
    ...
    public   class  Form1 : System.Windows.Forms.Form
    {
      [DllImport(
    " User32.dll " )]
      
    protected   static   extern   int
                SetClipboardViewer(
    int  hWndNewViewer);

      [DllImport(
    " User32.dll " , CharSet = CharSet.Auto)]
      
    public   static   extern   bool
             ChangeClipboardChain(IntPtr hWndRemove,
                                  IntPtr hWndNewNext);

      [DllImport(
    " user32.dll " , CharSet = CharSet.Auto)]
      
    public   static   extern   int  SendMessage(IntPtr hwnd,  int  wMsg,
                                           IntPtr wParam,
                                           IntPtr lParam);
      ...

  2. 在剪贴板通知链表中定义一个类成员去保持目前第一个窗口:

    public   class  Form1 : System.Windows.Forms.Form
    {
      ...
      IntPtr nextClipboardViewer;

  3. 调用 SetClipboardViewer 函数。在演示中,我在form 构造函数中调用这个函数:

    public  Form1()
    {
      InitializeComponent();
      nextClipboardViewer 
    =  (IntPtr)SetClipboardViewer(( int )
                             
    this .Handle);
      ..

  4. Form 类里,超载 WndProc 类成员函数。正如你可以看到这里,我只处理2个消息:
    WM_DRAWCLIPBOARD 和 WM_CHANGECBCHAIN。注意,我为了这些消息定义了2个常量
    (2个值可以在Platform SDK's winuser.h 文件里找到。)
    WM_DRAWCLIPBOARD 消息处理代码里,我查看从剪贴板链表中删除的窗口(通过
    Message.WParam 成员)是否是链表中的下个窗口。假如是的话,然后我设置 form 的下个
    窗口成员变量(nextClipboardViewer)成在链表中的下个窗口(通过 Message.LParam 成员):

    protected   override   void
              WndProc(
    ref  System.Windows.Forms.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 ;
      }
    }

  5. 最后,当在 .NET 运行环境中调用窗口类 Dispose 类成员函数时我从剪贴板链表中删除窗口:

    protected   override   void  Dispose(  bool  disposing )
    {
      ChangeClipboardChain(
    this .Handle, nextClipboardViewer);
      ...

A Chain Is Only As Strong...

经过这些步骤,剪贴板中文本的任何改变你的应用程序都将被告知。相似的在 Windows 下开发的很多任务,
一旦你知道调用正确的 APIs 就不是很困难了。关键的问题是用剪贴板工作是要确保你遵循一些简单的规则
使剪贴板链表中其他的应用程序继续正确地执行。

下载代码

下载陪同源代码,click here

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值