分享

剪贴板查看器

 londonKu 2012-09-06

监视剪贴板内容变化的程序叫剪贴板查看器。在Windows中已经拥有了剪贴板查看器,当然也可以用API函数编写自己的剪贴板查看器程序。

8.3.1  剪贴板查看器链接列表

   Windows下可以同时运行很多剪贴板查看器,用于时刻监视剪贴板内容的变化情况。但Windows在剪贴板内容发生变化时,只对一个剪贴板查看器窗口发送消息,这就是所谓的“当前剪贴板查看器”。

   应用程序想要得到Windows发送给当前剪贴板查看器的消息,就必须加入“剪贴板查看器链接列表”。当一个程序将自己注册为一个剪贴板查看器时,其窗口句柄被Windows留作当前剪贴板查看器窗口句柄,它也就被Windows设置为当前剪贴板查看器。当此程序收到一个剪贴板查看器消息时,就把这个消息发送给剪贴板链表中下一个程序的窗口过程。

8.3.2  有关剪贴板查看器的函数和消息

1. 剪贴板查看器函数消息介绍

   程序通过调用函数SetClipboardViewer成为剪贴板查看器链表中的一员。如果程序是作为剪贴板查看器使用的,那么在主窗口创建之初就应该调用此函数。即在处理消息WM_CREATE期间,函数返回前一个当前剪贴板查看器的窗口句柄,将其放在静态变量中,如下所示:

static HWND hWndNextViewer;

case WM_CREATE :

   hWndNextViewer = SetClipboardViewer(hWnd);

   在以后介绍的实例中,大家将看到具体的应用。

   一旦成为当前剪贴板查看器,只要剪贴板有任何变化,Windows都会把WM_DRAWCLIPBOARD消息发送给其窗口过程。剪贴板查看器链表中的每一个程序,都应该用SendMessage把这个消息发送给下一个剪贴板查看器。链表中的最后一个程序,就是当前剪贴板查看器的窗口所保存的hWndNextViewerNULL。当消息传给它后,程序只是简单地返回,消息不再从这里发出。具体的处理方法是除了当前剪贴板查看器,一般都是简单地将消息发送给下一个剪贴板查看器的窗口过程,并使本窗口的客户区无效,如下所示:

case WM_DRAWCLIPBOARD :

if( hWndNextViewer )

   SendMessage ( hWndNextViewer, message, wParam, lParam);

InvalidateRect( hWnd, NULL, TRUE);

Break;

   在处理WM_PAINT期间,可以调用OpenClipboardGetClipboardDataCloseClipboard读取剪贴板的内容。当一个程序要从剪贴板查看器链表中删除自己时,应当调用ChangeClipboardChain函数。函数原型如下:

BOOL ChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext )

   其中,第一个参数hWndRemove是从剪贴板查看器链中删除的窗口句柄;第二个参数hWndNewNext是剪贴板查看器链中hWndRemove后面紧跟的窗口句柄。当程序调用ChangeClipboardChain时,Windows将消息   WM_CHANGECBCHAIN发送到当前剪贴板查看器。在此消息中,参数wParam是函数ChangeClipboardChain的第一个参数,参数lParam是函数ChangeClipboardChain的第二个参数。

   当程序收到消息WM_CHANGECBCHAIN,必须检查wParam与保留的hWndNextViewer静态变量是否相同。如果相同,则将hWndNextViewer设置为lParam。此项工作保证了将来WM_DRAWCLIPBOARD消息不会被发送到一个已经不存在的窗口。如果不同,并且hWndNextViewer不为NULL,表明非当前剪贴板查看器,则将消息发送给下一个剪贴板查看器,如下所示:

case WM_CHANGECBCHAIN :

  if( (HWND) wParam ==hWndClipboardViewer )

hWndClipboardViewer = (HWND) lParam;

 else if (hWndClipboardViewer)

SendMessage ( hWndClipboardViewer, message, wParam, lParam);

  return 0;

   当程序要结束时,如果它仍然在剪贴板查看器链中,则必须将其删除。为了保证这一点,可以在处理消息WM_DESTORY时通过调用函数ChangeClipboardChain来实现,如下所示:

case WM_DESTORY :

ChangeClipboardChain( hWnd, hWndNextViewer );

PostQuitMessage( 0);

break;

   Windows还提供获得第一个剪贴板查看器窗口句柄的函数:

HWND GetClipboardViewer(VOID)

   一般来说不会用到这个函数。如果没有当前剪贴板查看器,那么此函数的返回值为NULL

2. 剪贴板查看器的实例分析

   下面来看一个剪贴板查看器的具体实例,这个实例提供了显示CF_BITMAPCF_TEXT的剪贴板查看器。虽然它只提供了Windows剪贴板查看器的部分功能,但从中可以了解剪贴板查看器是如何工作的。

   首先,在创建窗口时就设置本窗口为剪贴板查看器链表中的一员,其中函数SetOwner是用在窗口标题表明客户区的内容来自何处。其中,用到了函数GetClipboardOwner,如下所示:

case WM_CREATE:   

       hNextViewer = SetClipboardViewer( hWnd );

       SetOwner( hWnd );

       break;

   其次,看消息是如何在剪贴板查看器链表中传递的,如下所示:

     case WM_DRAWCLIPBOARD:

         if (hNextViewer)

           SendMessage( hNextViewer, WM_DRAWCLIPBOARD, wParam, lParam );

           InvalidateRect( hWnd, NULL, TRUE );  

           SetOwner( hWnd );

           break;

   再看应用程序是如何将自己从剪贴板查看器链表中删除的,如下所示:

case WM_CHANGECBCHAIN:

          if ( (HWND)wParam == hNextViewer )

                 hNextViewer = (HWND)lParam;

          else if ( hNextViewer )

          SendMessage( hNextViewer, WM_CHANGECBCHAIN, wParam, lParam );

          break;

   最后是介绍在消息WM_PAINT中实现了什么。真正的具体实现是在这里完成的,在前面已经介绍了有关函数的具体操作,读者看起来应该轻松一些。

case WM_PAINT :

{

              static HANDLE hMem;         // 剪贴板文本的句柄         

              static HBITMAP hBitmap;      // 剪贴板位图的句柄

              RECT rect;         // 客户区            

              PAINTSTRUCT ps;           // 绘图的结构

              BeginPaint( hWnd, &ps );

              GetClientRect( hWnd, &rect );

              OpenClipboard( hWnd );

              if (hMem = GetClipboardData( CF_TEXT ))

                 // 如果剪贴板中的内容为文本格式,则执行

              {

                 LPSTR lpMem = GlobalLock( hMem );

                 DrawText( ps.hdc, lpMem, -1, &rect, DT_LEFT );

                 GlobalUnlock( hMem );

              }

              // 如果非文本格式,测试是否为位图格式

              else if (hBitmap = GetClipboardData( CF_BITMAP ))

              {

                 BITMAP bm;

                 HDC hMemDC = CreateCompatibleDC( ps.hdc );

                 SelectObject( hMemDC, hBitmap );

                 GetObject( hBitmap, sizeof (BITMAP), (LPSTR) &bm );

                 BitBlt( ps.hdc, 0, 0, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,

                            SRCCOPY );

                         DeleteDC( hMemDC );

                  }

                  CloseClipboard( );

                  EndPaint( hWnd, &ps );

              }

              break;

   通过本章的学习,了解了如何运用API提供的函数来编写剪贴板的程序。在实际的编程中会经常用到剪贴板的内容,希望通过本章的学习,读者在编写程序时能如虎添翼。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多