现在的位置: 首页 > 精选转贴 > 正文

详解 VBA 中 Windows 剪切板的操作(一)

2014年10月29日 精选转贴 ⁄ 共 3464字 ⁄ 字号 暂无评论 ⁄ 阅读 10,732 次
本文转自 http://www.officefans.net/, 原作者 小fisher
 
 
一、剪贴板概述


  首先,讨论一下剪贴板是什么
  Windows的帮助文件中对剪贴板的描述是这样的:剪贴板是从一个地方复制或移动并打算在其他地方使用的信息的临时存储区域。可以选择文本或图形,然后使用“剪切”或“复制”命令将所选内容移动到剪贴板,在使用“粘贴”命令将该内容插入到其他地方之前,它会一直存储在剪贴板中。例如,您可能要复制网站上的一部分文本,然后将其粘贴到电子邮件中。大多数 Windows 程序中都可以使用剪贴板。
  对于经常使用Ctrl+C/X、Ctrl+V的Windows用户来说,这个解释是非常易懂并且符合人们感观上的认识的。
  既然我们今天讨论的话题是如何VBA程序中通过API调用剪贴板,那就先看看微软MSDN中对于剪贴板的定义吧:剪贴板是一组用于在多个应用程序之间交换数据函数和消息(原文:The clipboard is a set of functions and messages that enable applications to transfer data)。
  呵呵,是不是有些晕?没关系,因为这句话是针对C/C++程序员给出的说明,我们仍然可以按习惯上的理解把它当做一个对象(使用过VB6的同志们可能更容易理解,因为VB6中确实有一个名字叫ClipBoard的对象,它其实是VB对windows的剪贴板API函数封装后产生的真正的对象)。
  然后,再来看看这个对象有什么特点,又是如何工作的呢?概括来说,剪贴板有以下的特性(这是我个人总结的,不一定正确或精确,也不一定全面):

  • 公开性
    剪贴板中的数据存放在全局内存中,因此大部分的windows应用程序都可以访问其中的数据,在遵守相关API函数约定的前提下,应用程序可以自由地打开剪贴板(OpenClipboard),读取剪贴板内的数据(GetClipboardData)、或者清空剪贴板(EmptyClipboard)、然后设置剪贴板内的数据(SetClipboardData),最后关闭剪贴板(CloseClipboard);
  • 独占性
    既然剪贴板是公开的,那么多个程序同时访问必然会导致冲突,比如数据互相覆盖。因此,Windows规定应用程序对剪贴板的访问是独占性的,当一个应用程序使用OpenClipboard打开剪贴板之后,其他程序 就不可以再访问剪贴板,直至前一程序使用CloseClipboard关闭剪贴板 。通常我们使用剪贴板的时候不会感觉受其他程序的影响,这是因为剪贴板内的数据操作都是在内存中进行的,速度非常快,对于特大块的数据,应用程序还可以选择延时处理(Delayed Rendering)机制以保证速度。但是,我们在对剪贴板编程的时候要注意以下两点:1)每次使用完剪贴板之后一定要记得使用CloseClipBoard关闭 它;2)在OpenClipboard和CloseClipboard之间不要放置耗时很长的代码,以免影响其他程序正常工作。
    设置剪贴板内数据的应用程序窗口被称为剪贴板数据拥有者(ClipboardOwner),可以通过GetClipboardOwner函数获得它的句柄。反过来说,如果一个应用程序想向剪贴板中放入数据,需要先成为ClipboardOwner。程序要成为ClipboardOwner需要先将自己的句柄传给OpenClipboard函数,如果剪贴板中已经有数据存在,还需要先调用EmptyClipboard;
  • 多元性
    剪贴板中可以同时存放多种格式的数据,各自放在全局内存的不同位置 ;剪贴板中的数据有标准格式/预定义格式的,如文本、位图、Wav声音……;也有非标准格式/用户自定义格式,比如word中的域和公式、Excel中的图表
  • 可检索性
    对于每种在剪贴板中存放过的格式,Windows都会给它分配一个独特的长整型编号,通过这个编号可以知道对应的数据格式的名称(GetClipboardFormatName),或者 查询对应的数据在剪贴板中是否存在(IsClipBoardFormatAvailable),如果存在,还可以通过这个编号找到对应的数据在内存中存放的位置(GetClipboardData);
    对于标准格式,这个编号是固定的,可以通过VB6自带的APIViewer查询以CF_开头的常量得到,比如:
    Public Const CF_TEXT = 1
    Public Const CF_BITMAP = 2
    Public Const CF_METAFILEPICT = 3
    Public Const CF_SYLK = 4
    ……
    对于非标准格式,这个编号由提供此格式数据的应用程序给此格式定义一个名称,然后将此名称传递给RegisterClipboardFormat函数,如果此名称已经存在,函数将返回此名称对应的编号,如果此名称不存在,函数将返回一个之前未使用的编号,在系统关机重启之前,这个名称和编号可以一直使用下去。
  • 可监视性
    有一组特别的窗口可以持续监视剪贴板内的数据变化,这组窗口被称作剪贴板观察程序(ClipboardViewer),由它们构成的这个小圈子叫作剪贴板观察程序链ClipBoardViewerChain,每当剪贴板内数据发生变化时,windows将向消息链中的第一个窗口发送一个WM_DRAWCLIPBOARD消息,再由它转发给第二个……直至消息到达消息链中的最后一个窗口,同样,当消息链中的成员发生变化时,每个窗口都会收到一个WM_CHANGECBCHAIN消息;
    通过SetClipboardViewer函数,应用程序可以将自己的窗口句柄告诉windows,从而注册成为剪贴板观察程序链中的一员;通过ChangeClipboardChain函数,应用程序可以退出剪贴板观察程序链而不影响它后面的窗口继续接收相关消息。
    希望以上文字能对大家重新认识剪贴板能够有所帮助。休息一会儿,我们再讨论剪贴板在Office VBA中的用途。


二、剪贴板在Excel VBA中的用途 
  只要进行了正确的API声明,我们在VBA中也可以对剪贴板的进行操作,以它为媒介,我们可以访问到通过VBA难以接触到的数据,从而给我们的VBA或Office应用程序增加一些新奇和实用的功能。这里全是以Excel为例,在其他Office程序中原理一样。
  下面先看三个实例,它们分别演示了剪贴板数据的读取、写入和监视。
  

示例1ShapeToPicture.rar(点击下载)

 2014102901

说明:这个代码演示了如何在窗体中浏览工作簿中所有Shape对象,并且提供了按各种格式保存的功能。完成这个程序,并不能说明本人对各种图像格式有多深的认识,真正的幕后英雄是Excel,是它在我们选中工作表中的Shape对象并按下Ctrl+C后的1/1024柱香的时间内把这个Shape换成了bmp, jpg,gif, png,emf等各种格式并放在了剪贴板中,我们所做的只是把这些数据从剪贴板中取出并简单进行了加工,不过效果已经很理想了,下次再有人跟你说用把工作簿另存为网页的方法可以取出xls中所有的图形时,你就可以有得吹嘘了。说正题,把这个代码稍作修改,就可以做出一个用右键菜单导出当前选中图形的加载宏。我以前做过一个,不过代码不如现在这个严谨和通用。

示例2:  MSFlexGrid.rar (点击下载)


2014102902

说明:这个代码演示的是向放入数据,在userform窗体上的FlexGrid中选择一个单元格区域,然后通过右键或快捷键可以复制和剪切数据,回到Excel工作表后可直接粘贴。当然,跟华丽的Excel比起来,这个就有点槑了,不过这至少提供了一种在窗体上的表格和Excel工作表之间交换数据的思路,这种操作方式也更符合大多数用户的习惯。

示例3: clipboardviewer.rar (点击下载)

这是一个监控剪贴板数据变化的示例,很简单的一个功能:当剪贴板内数据发生变化时,在窗体左侧的列表中显示当前剪贴板内可用的数据格式,如果里面有文本,则将文本显示在TextBox中,像迅雷的监视剪贴板大致也是这个原理。
 2014102903
  看完之后,你可能对Windows剪贴板产生了一些兴趣。当然,剪贴板在VBA中的使用不止于此,套用一句广告词,哪啥来着?心有多大,舞台就有多大。接下来,剪贴板之旅正式开始,我们理论实践相结合,先逐个认识相关的API函数,最后让他们一起协作帮我们完成某个目的。

 

下接:详解 VBA 中 Windows 剪切板的操作(二)

给我留言

您必须 [ 登录 ] 才能发表留言!