19.1-传统剪贴板 剪贴板

剪贴板函数

将数据放入剪贴板需要四个步骤:

全局内存块是调用::GlobalAlloc分配的内存块,它返回一个HGLOBAL类型的句柄,在Win32应用中可以视为通用句柄。一个名为::GlobalLock的相关函数使用HGLOBAL,并返回指向该内存块的指针。Windows程序员不经常使用::GlobalAlloc,在Win32中被::HeapAlloc取代。但是,它还是非常有用的,因为剪贴板需要的是内存句柄,而不是指针。

下面的代码,先将字符串复制到全局内存块,再将内存块交给剪贴板:

全局内存块传一旦交给剪贴板,分配该内存块的应用既不应该使用它也不应该删除它。剪贴板拥有该内存块,下次调用::EmptyClipboard时,释放内存块。

传递给::OpenClipboard的唯一参数是打开剪贴板时,拥有剪贴板的窗口的句柄。在MFC应用中,CWnd的窗口句柄可以通过数据成员m_hWnd获得。如果其它应用已经打开了剪贴板,调用::OpenClipboard就会失败。Windows使用这种先打开再使用的方法,同步对共享资源的访问,并且可以保证使用过程中,内容不会被修改。

从剪贴板获取数据同样简单,步骤是:

下面的代码获取前一个例子放在剪贴板上的字符串:

19.1.1剪贴板格式

::SetClipboardData和::GetClipboardData都用一个整数值设置剪贴板格式,它是传递过程中数据类型的标识符。前一节例子中使用的是CF_TEXT,表示数据是ANSI文本。Unicode文本使用另一种格式ID。

经常使用的剪贴板格式

可以使用预定义的剪贴板格式像传递文本一样传递位图、调色板、增强型元文件等对象。例如,m_bitmap是CBitmap的一个数据成员,它保存一个位图,可以按照下面的方法复制这个位图,并将其放在剪贴板上:

从剪贴板获取位图时,调用::GetClipboardData,并传递一个CF_BITMAP参数:

注意这里使用的模式。将数据放入剪贴板时,要告诉Windows数据的类型。获取数据时,要询问该类型的数据是否存在。如果不存在,::GetClipboardData返回NULL。

CF_HDROP剪贴板格式

最有意思的一种格式是CF_HDROP。使用该格式从剪贴板获取数据时,得到的是HDROP,它实际上是一个全局内存块的句柄。内存块内部是一个文件名的列表。读取文件名时,不必解析内存块的内容,可以使用::DragQueryFile。下面的代码从剪贴板获取HDROP,并将文件名写入列表框:

从HDROP获取文件名很简单,而插入文件名则需要更多的工作。HDROP引用的内存块包含一个DROPFILES结构体,它后面跟随着一个文件名列表,以两个连续的NULL为结尾。DROPFILES在Shlobj.h中定义:

为了创建自己的HDROP,需要分配全局内存块、初始化DROPFILES结构体、附加一个文件名列表。DROPFILES中唯一需要初始化的是pFiles,它们保存文件名第一个字母相对于内存块起始位置的偏移量。fWide指示组成文件名的是ANSI字符还是Unicode字符。下面的代码创建一个包含两个文件名的HDROP,并将它放入剪贴板:

传递给::GlobalAlloc的参数GHND是GMEM_MOVEABLE和GMEM_ZEROINIT的组合。GMEM_ZEROINIT告诉::GlobalAlloc将内存块的所有字节初始化为0,这可以将没有被初始化的DROPFILES成员设置为0。在Win32环境中不再需要GMEM_MOVEABLE。
19.1-传统剪贴板 剪贴板


19.1.2 私用剪贴板格式

虽然预定义的剪贴板格式包含了很多种数据类型,但是它们不可能包括应用中所需的全部数据类型。Winodws允许注册私有的剪贴板格式,并使用它们代替标准的剪贴板格式。

假设正在编写一个Widget应用。你想让用户可以剪切或复制饰件到剪贴板,然后粘贴到文档的其它位置。要实现这样的功能,就要调用Win32的API函数::RegisterClipboardForamt为饰件注册一个私有剪贴板格式:

nID是私有剪贴板格式的ID。要复制饰件到剪贴板,就要复制定义饰件所需的全部数据,然后用nID和内存句柄调用::SetClipboardData:

要从剪贴板获取饰件,可以向::GetClipboardData传递nID:

然后锁定内存块获取指针,用内存块的数据重建饰件。这里的关键点是,如果10个不同的应用(或同一应用的10个不同实例)用相同的格式名调用::RegisterClipboardFormat,它们会得到相同的剪贴板格式ID。这样,只要应用A和应用B调用::RegisterClipboardForamt时使用相同的格式名,应用B就可以获取应用A复制到剪贴板上的饰件。

19.1.3以多种格式提供数据

在剪贴板中放置多个项目是完全合法的,只要它们具有不同的格式。应用程序总是这么做。这也是向多个应用提供数据的有效方法,即使有些应用并不理解私有剪贴板格式。

微软的Excel就是一个例子。在Excel中选择一定范围的电子表格单元复制到剪贴板时,Excel最多可以在剪贴板上放置30个项目。其中之一是私有剪贴板格式,表示Excel自己的电子表格数据。另一个是表格单元格的CF_BITMAP译文。Windows的Paint应用并不理解Excel的私有剪贴板格式,但是却可以粘贴Excel电子表格单元到一个位图。至少看上去Paint可以粘贴表格单元。实际上,粘贴的只是这些单元的位图图像,不是真的表格单元。甚至可以粘贴Excel数据到记事本,因为格式中包含CF_TEXT。提供多种格式的表格数据,Excel提高了它的剪贴板数据的可移植性。

为每一种格式调用::SetClipboardData就可以在剪贴板上放置多个项目:

19.1.4查询有效数据格式

查询某种格式的剪贴板数据是否有效,可以调用::GetClipboardData,并查看返回值是否等于NULL。有时需要知道所有有效的格式,并从中选择一个最需要的。可以使用下面的函数:

::IsClipboardFormatAvailable是最简单的一个。要查看CF_TEXT格式是否有效,可以这样调用:

这个函数常用于实现Edit菜单Paste命令的更新处理函数。

即使剪贴板没有打开,::IsClipboardFormatAvailable也可以工作。但是不要忘了,这时剪贴板很容易被改变。不要这样编写代码:

这个代码是有问题的。在多任务环境中,::IsClipboardFormatAvailable执行后,调用::GetClipboardData之前,虽然机会很小,但是确实有机会改变剪贴板的数据。因此,要打开剪贴板之后再调用这个函数:

这段代码就不会出现什么问题,因为只有打开剪贴板的应用才能改变剪贴板的内容。

可以使用::EnumClipboardFormats循环访问有效剪贴板格式的列表。例如:

到达表尾时::EnumClipboardFormats返回0,因此获取最后一个有效模式后,循环结束。如果只是想知道有效模式的个数,调用::CountClipboardFormats。

::GetPriorityClipboardFormat简化了查询多个剪贴板格式的过程。假设你的应用可以以私有格式nID、CF_TEXT、CF_BITMAP格式粘贴数据。你希望使用nID,如果无效,用CF_TEXT代替,如果也无效,再用CF_BITMAP代替。不要这样编写代码:

需要这样编写代码:

::GetPriorityClipboardFormat的返回值是有效格式列表中第一个格式的ID。如果没有可用的格式,则返回-1;如果剪贴板为空,则返回0。

19.1.5延迟再现

传统剪贴板有一个局限性,剪贴板上的所有数据都要保存在内存上。对于文本字符串和其它简单数据类型,可以快速有效地传递。但是,假设复制了一个10MB的位图到剪贴板。清空剪贴板之前,位图都要占用10MB的内存。而如果没有人粘贴这个位图,给它分配的内存就毫无用处。

为了避免这种浪费,Windows支持延迟提交。即直到需要的时候才将数据复制到剪贴板。它是怎样工作的?首先,用有效的剪贴板格式和NULL数据句柄调用::SetClipboardData。然后,响应WM_RENDERFORMAT消息,调用::SetClipboardData将数据真正地放入剪贴板。应用调用::GetClipboardData请求获取指定格式的数据时,就会发送WM_RENDERFORMAT消息。如果没有人请求数据,就不会传递这条消息,就无需分配10MB的内存。要注意,该消息的处理函数不应该调用::OpenClipboard和::CloseClipboard,因为接收该消息的窗口,收到消息时就占有了剪贴板。

处理WM_RENDERFORMAT消息的应用还必须处理WM_RENDERALLFORMATS消息。当应用终止而剪贴板拥有应用放置的NULL数据句柄时,就会发送这条消息。该消息处理函数的任务是打开剪贴板、传递应用承诺提供的数据、关闭剪贴板。将数据放入剪贴板,保证使用延迟提交的应用终止后,其它应用可以使用这些数据。

第三个剪贴板消息是WM_DESTROYCLIPBOARD,也在延迟提交中使用。这条消息通知应用不需要再提供延迟提交数据。当其它应用调用::EmptyClipboard时,发送该消息。在WM_RENDERALLFORMATS消息之后也发送该消息。如果你拥有响应WM_RENDERFORMAT和WM_RENDERALLFORMATS所需的资源,可以在收到WM_DESTROYCLIPBOARD消息时安全释放它们。

下面给出一个MFC使用延迟提交复制位图到剪贴板的方法:

这个例子不完全实用,因为复制位图到剪贴板和从剪贴板获取位图之间,位图存在改变的可能性,OnEditCopy将被迫复制位图。但是,想一下,如果OnEditCopy复制了位图,延迟提交就失去了意义。延迟提交是节省内存的工具,但是,如果应用被迫复制每一项,为什么不直接复制?

不必如此,可以保存到硬盘上。下面是修改后的程序:

  

爱华网本文地址 » http://www.413yy.cn/a/25101017/328568.html

更多阅读

灭世OL火速飙级攻略! 神泣灭世1.4攻略

《灭世OL》中获圣元奶粉取经验的方式非常之多圣元奶粉,大致上来说,可以分圣元奶粉为传统任务升级、特殊圣元奶粉升级三大类。圣元级三大类。1.传统任务传统任务主要包括:主线任务、支线任务、境界任务和其它任务。下面我们就来详细

怎样在好友留言板里留图片 1 好友留言板留言大全

怎样在好友留言板里留图片现在告诉你在好友留言板中留下祝贺图片的方法:一、把你喜欢的图片上传到你的空间相册里(不管图片大小)。二、打开你自己的空间留言板,在最下面左角点“我要留言”。三、在自己的“插入QQ泡泡秀”界面输入你要祝

中小板ETF问答 中小板股票一览表

第一章 什么是中小板股票基金(ETF)1、 中小板股票基金(ETF)是什么样的产品?2、 什么是中小企业板?3、 中小企业板与主板相比有哪些投资优势?4、 中小企业板包括哪些股票?5、 为什么中小企业板具有较高成长性?6、 如何投资中小企业板分享上涨

CS5新手入门教程教程68ps联盟 pscs5抠图教程入门

师路才情博客 2013-02-25 18:05:59|分类: ps教程1-1.CS5概述及用途1-2.CS5界面介绍1-3.怎样新建文档1-4.图层详细介绍1-5.文档编排1-6.文档保存1-7.文档打开1-8.Bridge功能介绍1-9.剪贴板使用方法1-10.文档信息查看2-1.内容识别2-2.

声明:《19.1-传统剪贴板 剪贴板》为网友海与他的孤独症分享!如侵犯到您的合法权益请联系我们删除