ImageVerifierCode 换一换
格式:DOCX , 页数:50 ,大小:34.29KB ,
资源ID:12379684      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/12379684.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Petzold《windows程序设计C语言版》第12章.docx)为本站会员(b****4)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Petzold《windows程序设计C语言版》第12章.docx

1、Petzoldwindows程序设计C语言版第12章剪贴簿涛儿软件工作室整理编译 Microsoft Windows剪贴簿允许把数据从一个程序传送到另一个程序中。它的原理相对而言比较简单,把数据存放到剪贴簿上的程序或从剪贴簿上取出数据的程序都无须太多的负担。Windows 98和Microsoft Windows NT都提供了剪贴簿浏览程序,该程序可以显示剪贴簿的目前内容。 许多处理文件或者其它数据的程序都包含一个Edit菜单,其中包括Cut、Copy和Paste选项。当使用者选择Cut或者Copy时,程序将数据传送给剪贴簿。这个数据使用某种格式,如文字、位图(一种按位排列的矩形数组,其中的位

2、与平面显示的图素相对应)或者metafile(用二进制元数值内容表示的绘图命令集)等。当使用者从菜单中选择Paste时,程序检查剪贴簿中包含的数据,看看使用的是否是程序可以接受的一种格式。如果是,那么数据将从剪贴簿传送到程序中。如果使用者不发出明确的指令,程序就不能把数据送入或移出剪贴簿。例如,在某个程序中执行剪下或复制(或者按Ctrl-X及Ctrl-C)操作的使用者,应该能够假定数据将储存在剪贴簿上,直到下次剪下或复制操作为止。回忆一下第十和第十一章所示的POPPAD程序的修订版中,我们加上了Edit菜单,但是在那边这菜单的作用只是发送消息给编辑控件而已。多数情况下,处理剪贴簿并不方便,您必

3、须自己呼叫剪贴簿传输函数。本章集中讨论将文字传入和移出剪贴簿。在后面的章节里,我将向您展示如何用剪贴簿处理位图(第十四、十五和十六章)和metafile(第十八章)。剪贴簿的简单使用我们由分析把数据传送到剪贴簿(剪下或复制)和存取剪贴簿数据(粘贴)的程序代码开始。标准剪贴簿数据格式Windows支持不同的预先定义剪贴簿格式,这些格式在WINUSER.H定义成以CF为前缀的标识符。首先介绍三种能够储存在剪贴簿上的文字数据型态,以及一个与剪贴簿格式相关的数据型态: CF_TEXT以NULL结尾的ANSI字符集字符串。它在每行末尾包含一个carriage return和linefeed字符,这是最简

4、单的剪贴簿数据格式。传送到剪贴簿的数据存放在整体内存块中,并且是利用内存块句柄进行传送的(我将简短地讨论此项概念)。这个内存块专供剪贴簿使用,建立它的程序不应该继续使用它。 CF_OEMTEXT含有文字数据(与CF_TEXT类似)的内存块。但是它使用的是OEM字符集。通常Windows程序不必关心这一点;它只有与在窗口中执行MS-DOS程序一起使用剪贴簿时才会使用。 CF_UNICODETEXT含有Unicode文字的内存块。与CF_TEXT类似,它在每一行的末尾包含一个carriage return和linefeed字符,以及一个NULL字符(两个0字节)以表示数据结束。CF_UNICODE

5、TEXT只支援Windows NT。 CF_LOCALE一个国家地区标识符的句柄。表示剪贴簿文字使用的国别地区设定。下面是两种附加的剪贴簿格式,它们在概念上与CF_TEXT格式相似(也就是说,它们都是文字数据),但是它们不需要以NULL结尾,因为格式已经定义了数据的结尾。现在已经很少使用这些格式了: CF_SYLK包含Microsoft 符号连结数据格式的整体内存块。这种格式用在Microsoft的Multiplan、Chart和Excel程序之间交换数据,它是一种ASCII码格式,每一行都用carriage return和linefeed结尾。 CF_DIF包含数据交换格式(DIF)之数据的

6、整体内存块。这种格式是由Software Arts公司提出的,用于把数据送到VisiCalc电子表格程序中。这也是一种ASCII码格式,每一行都使用carriage return和linefeed结尾。下面三种剪贴簿格式与位图有关。所谓位图就是数据位的矩形数组,其中的数据位与输出设备的图素相对应。 第十四和 第十五章将详细讨论位图以及这些位图剪贴簿的格式: CF_BITMAP与设备相关的位图格式。位图是通过位图句柄传送给剪贴簿的。同样,在把这个位图传送给剪贴簿之后,程序不应该再继续使用这个位图。 CF_DIB定义一个设备无关位图(在第十五章中描述)的内存块。这种内存块是以位图信息结构开始的,后

7、面跟着可用的颜色表和位图数据位。 CF_PALETTE调色盘句柄。它通常与CF_DIB配合使用,以定义与设备相关的位图所使用的颜色调色盘。在剪贴簿中,还有可能以工业标准的TIFF格式储存的位图数据: CF_TIFF含有标号图像文件格式(TIFF)数据的整体内存块。这种格式由Microsoft、Aldus公司和Hewlett-Packard公司以及一些硬件厂商推荐使用。这一格式可从Hewlett-Packard的网站上获得。下面是两个metafile格式,我将在第十八章详细讨论。一个metafile就是一个以二进制格式储存的画图命令集: CF_METAFILEPICT以旧的metafile格式存

8、放的图片。 CF_ENHMETAFILE增强型metafile(32位Windows支持的)句柄。最后介绍几个混合型的剪贴簿格式: CF_PENDATA与Windows的笔式输入扩充功能联合使用。 CF_WAVE声音(波形)文件。 CF_RIFF使用资源交换文件格式(Resource Interchange File Format)的多媒体数据。 CF_HDROP与拖放服务相关的文件列表。内存配置程序向剪贴簿传输一些数据的时候,必须配置一个内存块,并且将这块内存交给剪贴簿处理。在本书早期的程序中需要配置内存时,我们只需使用标准C执行时期链接库所支持的malloc函数。但是,由于在Windows

9、中执行的应用程序之间必须要共享剪贴簿所储存的内存块,这时malloc函数就有些不适任这项任务了。实际上,我们必须把早期Windows所开发的内存配置函数再拿出来使用,那时的操作系统在16位的实际模式内存结构中执行。现在的Windows仍然支持这些函数,您还可以使用它们,但不是必须使用这些函数就是了。要用Windows API来配置一个内存块,可以呼叫:hGlobal = GlobalAlloc (uiFlags, dwSize) ; 此函数有两个参数:一系列可能的旗标和内存块的字节大小。函数传回一个HGLOBAL型态的句柄,称为整体内存块句柄或整体句柄。传回值为NULL表示不能配置足够的内存。

10、虽然GlobalAlloc的两个参数略有不同,但它们都是32位的无正负号整数。如果将第一个参数设定为0,那么您就可以更有效地使用旗标GMEM_FIXED。在这种情况下,GlobalAlloc传回的整体句柄实际是指向所配置内存块的指针。如果不喜欢将内存块中的每一位都初始化为0,那么您也能够使用旗标GMEM,_ZEROINIT。在Windows表头文件中,简洁的GPTR旗标定义为GMEM_FIXED和GMEM_ZEROINIT旗标的组合:#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) 下面是一个重新配置函数:hGlobal = GlobalReAlloc (hG

11、lobal, dwSize, uiFlags) ; 如果内存块扩大了,您可以用GMEM_ZEROINIT旗标将新的字节设为0。下面是获得内存块大小的函数:dwSize = GlobalSize (hGlobal) ; 释放内存块的函数:GlobalFree (hGlobal) ; 在早期16位的Windows中,因为Windows不能在物理内存中移动内存块,所以禁止使用GMEM_FIXED旗标。在32位的Windows中,GMEM_FIXED旗标很常见。这是因为它将传回一个虚拟地址,并且操作系统也能够通过改变内存页映像表在物理内存中移动内存块。因此为16位的Windows写程序时,Global

12、Alloc推荐使用GMEM_MOVEABLE旗标。在Windows的表头文件中还定义了一个简写标识符,用此标识符可以在可移动的内存之外填0:#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) GMEM_MOVEABLE旗标允许Windows在虚拟内存中移动一个内存块。这不是说将在物理内存中移动内存块,只是应用程序用于读写这块内存的地址可以被变动。尽管GMEM_MOVEABLE是16位Windows的通则,但是它的作用现在已经少得多了。如果您的应用程序频繁地配置、重新配置以及释放不同大小的内存块,应用程序的虚拟地址空间将会变得支离破碎。可以想象得到,最后虚拟

13、内存地址空间就会被用完。如果这是个可能会发生的问题,那么您将希望内存是可移动的。下面就介绍如何让内存块成为可搬移位置的。首先定义一个指标(例如,一个int型态的)和一个GLOBALHANDLE型态的变量:int * p ; GLOBALHANDLE hGlobal ; 然后配置内存。例如:hGlobal = GlobalAlloc (GHND, 1024) ; 与处理其它Windows句柄一样,您不必担心数字的实际意义,只要照著作就好了。需要存取内存块时,可以呼叫:p = (int *) GlobalLock (hGlobal) ; 此函数将句柄转换为指标。在内存块被锁定期间,Windows将

14、固定虚拟内存中的地址,不再移动那块内存。存取结束后呼叫:GlobalUnlock (hGlobal) ; 这将使Windows可以在虚拟内存中移动内存块。要真正确保此程序正常运作(体验早期Windows程序写作者的痛苦经历),您应该在单一个消息处理期间锁定和解锁内存块。在释放内存时,呼叫GlobalFree应使用句柄而不是指标。如果您现在不能存取句柄,可以使用下面的函数:hGlobal = GlobalHandle (p) ; 在解锁之前,您能够多次锁定一个内存块。Windows保留一个锁定次数,而且在内存块可被自由移动之前,每次锁定都需要相对应的解锁。当Windows在虚拟内存中移动一个内存

15、块时,不需要将字节从一个位置复制到另一个,只需巧妙地处理内存页映像表。通常,让32位Windows为您的程序配置可移动的内存块,其唯一确实的理由只是避免虚拟内存的空间碎裂出现。使用剪贴簿时,也应该使用可移动内存。为剪贴簿配置内存时,您应该以GMEM_MOVEABLE和GMEM_SHARE旗标呼叫GlobalAlloc函数。GMEM_SHARE旗标使得其它应用程序也可以使用那块内存。将文字传送到剪贴簿让我们想象把一个ANSI字符串传送到剪贴簿上,并且我们已经有了指向这个字符串的指针(pString)。现在希望传送这个字符串的iLength字符,这些字符可能以NULL结尾,也可能不以NULL结尾。

16、首先,通过使用GlobalAlloc来配置一个足以储存字符串的内存块,其中还包括一个终止字符NULL:hGlobal = GlobalAlloc (GHND | GMEM_SHARE, iLength + 1) ; 如果未能配置到内存块,hGlobal的值将为NULL 。如果配置成功,则锁定这块内存,并得到指向它的一个指标:pGlobal = GlobalLock (hGlobal) ; 将字符串复制到内存块中:for (i = 0 ; i wLength ; i+) *pGlobal+ = *pString+ ; 由于GlobalAlloc的GHND旗标已使整个内存块在配置期间被清除为零,所

17、以不需要增加结尾的NULL 。以下叙述为内存块解锁:GlobalUnlock (hGlobal) ; 现在就有了表示以NULL结尾的文字所在内存块的内存句柄。为了把它送到剪贴簿中,打开剪贴簿并把它清空:OpenClipboard (hwnd) ; EmptyClipboard () ; 利用CF_TEXT标识符把内存句柄交给剪贴簿,关闭剪贴簿:SetClipboardData (CF_TEXT, hGlobal) ; CloseClipboard () ; 工作告一段落。下面是关于此过程的一些规则: 在处理同一个消息的过程中呼叫OpenClipboard和CloseClipboard。不需要时

18、,不要打开剪贴簿。 不要把锁定的内存句柄交给剪贴簿。 当呼叫SetClipboardData后,请不要再继续使用该内存块。它不再属于使用者程序,必须把句柄看成是无效的。如果需要继续存取数据,可以制作数据的副本,或从剪贴簿中读取它(如下节所述)。您也可以在SetClipboardData呼叫和CloseClipboard呼叫之间继续使用内存块,但是不要使用传递给SetClipboardData函数的整体句柄。事实上,此函数也传回一个整体句柄,必需锁定这些代码以存取内存。在呼叫CloseClipboard之前,应先为此句柄解锁。从剪贴簿上取得文字从剪贴簿上取得文字只比把文字传送到剪贴簿上稍微复杂一

19、些。您必须首先确定剪贴簿是否含有CF_TEXT格式的数据,最简单的方法是呼叫bAvailable = IsClipboardFormatAvailable (CF_TEXT) ; 如果剪贴簿上含有CF_TEXT数据,这个函数将传回TRUE(非零)。我们在第十章的POPPAD2程序中已使用了这个函数,用它来确定Edit菜单中Paste项是被启用还是被停用的。IsClipboardFormatAvailable是少数几个不需先打开剪贴簿就可以使用的剪贴簿函数之一。但是,如果您之后想再打开剪贴簿以取得这个文字,就应该再做一次检查(使用同样的函数或其它方法),以便确定CF_TEXT数据是否仍然留在剪贴

20、簿中。为了传送出文字,首先打开剪贴簿:OpenClipboard (hwnd) ; 会得到代表文字的内存块代号:hGlobal = GetClipboardData (CF_TEXT) ; 如果剪贴簿不包含CF_TEXT格式的数据,此句柄就为NULL。这是确定剪贴簿是否含有文字的另一种方法。如果GetClipboardData传回NULL,则关闭剪贴簿,不做其它任何工作。从GetClipboardData得到的句柄并不属于使用者程序它属于剪贴簿。仅在GetClipboardData和CloseClipboard呼叫之间这个句柄才有效。您不能释放这个句柄或更改它所引用的数据。如果需要继续存取这些

21、数据,必须制作这个内存块的副本。这里有一种将数据复制到使用者程序中的方法。首先,配置一块与剪贴簿数据块大小相同的内存块,并配置一个指向该块的指标:pText = (char *) malloc (GlobalSize (hGlobal) ; 再次呼叫hGlobal ,而hGlobal是从GetClipboardData呼叫传回的整体句柄。现在锁定句柄,获得一个指向剪贴簿块的指标:pGlobal = GlobalLock (hGlobal) ; 现在就可以复制数据了:strcpy (pText, pGlobal) ; 或者,您可以使用一些简单的C程序代码:while (*pText+ = *pG

22、lobal+) ; 在关闭剪贴簿之前先解锁内存块:GlobalUnlock (hGlobal) ; CloseClipboard () ; 现在您有了一个叫做pText的指针,以后程序的使用者就可以用它来复制文字了。打开和关闭剪贴簿在任何时候,只有一个程序可以打开剪贴簿。呼叫OpenClipboard的作用是当一个程序使用剪贴簿时,防止剪贴簿的内容发生变化。OpenClipboard传回BOOL值,它说明是否已经成功地打开了剪贴簿。如果另一个应用程序没有关闭剪贴簿,那么它就不能被打开。如果每个程序在响应使用者的命令时都尽快地、遵守规范地打开然后关闭剪贴簿,那么您将永远不会遇到不能打开剪贴簿的问

23、题。但是,在不遵守规范程序和优先权式多任务环境中,总会发生一些问题。即使在您的程序将某些东西放入剪贴簿和使用者启动一个Paste选项期间,您的程序并没有失去输入焦点,但是您也不能假定您放入的东西仍然在那里,一个背景程序有可能已经在这段期间存取过剪贴簿了。而且,请留意一个与消息框有关的更微妙问题:如果不能配置足够的内存来将内容复制到剪贴簿,那么您可能希望显示一个消息框。但是,如果这个消息框不是系统模态的,那么使用者可以在显示消息框期间切换到另一个应用程序中。您应该使用系统模态的消息框,或者在您显示消息框之前关闭剪贴簿。如果您在显示一个对话框时将剪贴簿保持为打开状态,那么您还可能遇到其它问题,对话

24、框中的编辑字段会使用剪贴簿进行文字的剪贴。剪贴簿和Unicode迄今为止,我只讨论了用剪贴簿处理ANSI文字(每个字符对应一个字节)。我们用CF_TEXT标识符时就是这种格式。您可能对CF_OEMTEXT和CF_UNICODETEXT还不熟悉吧。我有一些好消息:在处理您所想要的文字格式时,您只需呼叫SetClipboardData和GetClipboardData,Windows将处理剪贴簿中所有的文字转换。例如,在Windows NT中,如果一个程序用SetClipboardData来处理CF_TEXT剪贴簿数据型态,程序也能用CF_OEMTEXT呼叫GetClipboardData。同样地

25、,剪贴簿也能将CF_OEMTEXT数据转换为CF_TEXT。在Windows NT中,转换发生在CF_UNICODETEXT、CF_TEXT和CF_OEMTEXT之间。程序应该使用对程序本身而言最方便的一种文字格式来呼叫SetClipboardData 。同样地,程序应该用程序需要的文字格式来呼叫GetClipboardData。我们已经知道,本书附上的程序在编写时可以带有或不带UNICODE标识符。如果您的程序也依此编写,那么在定义了UNICODE标识符之后,程序将执行带有CF_UNICODETEXT参数的SetClipboardData以及GetClipboardData呼叫,而不是CF_

26、TEXT。CLIPTEXT程序,如程序12-1所示,展示了一种可行的方法。程序12-1 CLIPTEXT CLIPTEXT.C /*- CLIPTEXT.C - The Clipboard and Text (c) Charles Petzold, 1998 -*/ #include #include resource.h LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; #ifdef UNICODE #define CF_TCHAR CF_UNICODETEXT TCHAR szDefaultText = TEXT (Defaul

27、t Text - Unicode Version) ; TCHAR szCaption = TEXT (Clipboard Text Transfers - Unicode Version) ; #else #define CF_TCHAR CF_TEXT TCHAR szDefaultText = TEXT (Default Text - ANSI Version) ; TCHAR szCaption = TEXT (Clipboard Text Transfers - ANSI Version) ; #endif int WINAPI WinMain (HINSTANCE hInstanc

28、e, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) static TCHAR szAppName = TEXT (ClipText) ; HACCEL hAccel ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hIns

29、tance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass) MessageBo

30、x ( NULL, TEXT (This program requires Windows NT!), szAppName, MB_ICONERROR) ; return 0 ; hwnd = CreateWindow (szAppName, szCaption, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; hAccel = LoadAccelerators (hInstance, szAppName) ; while (GetMessage (&msg, NULL, 0, 0) if (!TranslateAccelerator

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1