概述
1、内存分配 |
---|
使用剪贴板时,程序必须申请一个内存块用于存储数据,并把内存块交给剪贴板。
申请内存块可以使用GlobalAlloc
函数,GlobalAlloc
的返回值是一个HGLOBAL
类型的句柄。如果GlobalAlloc
调用时指定了GMEM_FIXED
标志位,内存块地址是固定不变的,句柄值实际是一个内存块指针;如果指定了GMEM_MOVEABLE
标志位,那么windows会在需要情况下移动该内存块(虚拟内存),以防止内存碎片化。由于内存块可以移动,返回值自然不是固定的内存块指针,而就是一个句柄值。使用可移动的内存块前必须使用GlobalLock
锁定内存块,防止在访问期间windows移动内存块。GlobalLock
会根据内存块句柄返回对应的内存指针,访问完内存块后,使用GlobalUnlock
解锁内存块。
windows为内存块维护一个锁计数器。GlobalLock
时计数值加1,GlobalUnlock
时计数值减1。必须调用相同次数的GlobalUnlock
,使计数值为0,才能成功解锁内存块。
GlobalAlloc
用于分配全局内存,而LocalAlloc
用于分配局部内存。实际上,全局堆和局部堆是16位系统的概念,对于现在的32位或者64位系统的程序,都只有一个默认堆。所以GlobalAlloc
和LocalAlloc
的效果实际是一样的,MSDN
上说应该尽量使用HeapAlloc
系列的函数。
GlobalAlloc
相关的其他函数:
- GlobalHandle:根据内存指针获取内存块句柄
- GlobalFree:释放内存块
2、复制数据到剪贴板 |
---|
分配好内存并写入数据后,需要把数据传入剪贴板:
OpenClipboard
:打开剪贴板EmptyClipboard
:清空剪贴板SetClipboardData
:把内存句柄传给剪贴板CloseClipboard
:关闭剪贴板
调用SetClipBoardData
时需要指定数据的格式,windows预定义了很多标准的剪贴板数据格式,其标识符带有CF_
前缀。
在使用剪贴板过程中需要注意:
- 只有一个程序能够打开剪贴板,所以
OpenClipBoard
后必须尽快CloseClipBoard
。 - 不能把一个锁定的内存块句柄传给剪贴板
- 在
SetClipBoardData
后,内存块已经归系统所有,不能对内存块进行写入和释放操作。但在CloseClipBoard
之前,可以利用SetClipBoardData
返回的句柄,对内存块进行锁定和读取操作。在CloseClipBoard
之前必须解锁内存块。
3、从剪贴板粘贴数据 |
---|
IsClipboardFormatAvailable
:判断剪贴板数据内容格式,可以不打开剪贴板OpenClipboard
:打开剪贴板GetClipboardData
:获取数据的全局内存块句柄GlobalLock
:锁定内存块- 把数据拷贝到程序中
GlobalUnlock
:解锁内存块CloseClipboard
:关闭剪贴板
4、剪贴板和字符编码 |
---|
windows为剪贴板数据定义了多种文本格式,比如CF_TEXT
、CF_OEMTEXT
和CF_UNICODETEXT
。复制、粘贴时可以使用不同的字符编码,GetClipboardData
内部会完成文本转换。比如,程序A文本使用ANSI
编码,程序B文本使用UNICODE
编码。从程序A复制文本,调用SetClipboardData
自然使用CF_TEXT
格式。在程序B粘贴文本,调用GetClipboardData
使用CF_UNICODETEXT
标识符,获取到的文本就是UNICODE
格式。
5、同时使用多种数据格式 |
---|
在调用OpenClipboard
和CloseClipboard
之间,可以多次调用SetClipboardData
,把多个不同格式的数据写入剪贴板。但是,对一个格式不能多次写入数据。
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_TEXT, hGlobalText);
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();
粘贴数据时,调用GetClipboardData
,传入不同格式就可以获取到不同的数据:
hGlobalText = GetClipboardData(CF_TEXT);
hBitmap = GetClipboardData(hBitmap);
相关函数:
IsClipboardFormatAvailable
:判断剪贴板中是否包含某种格式数据EnumClipboardFormats
:枚举剪贴板中包含的数据格式
第一次调用时,把传参设为0,EnumClipboardFormats
会返回剪贴板中第一个数据的格式。后续的调用传入前一次调用的返回结果,EnumClipboardFormats
返回剪贴板中下一个数据的格式。当传参为剪贴板中最后一个数据的格式,EnumClipboardFormats
返回0,枚举结束。CountClipboardFormats
:获取剪贴板中数据格式的数量。
6、写时复制 |
---|
按照前面的方法,复制数据时就需要为数据分配好内存。但是,这些内存可能并没有被实际使用,也就是没有粘贴动作,或是过了很长时间才会被使用。这会造成内存浪费,数据量大时尤其严重。
为了解决这个问题,可以把内存分配动作延迟到粘贴动作发生时。
调用SetClipboardData
时,把第二传参句柄值设为NULL
。那么,当调用GetClipboardData
时,windows检查数据句柄,如果为NULL
,就向 剪贴板所有者 发送消息,请求一个数据句柄。
WM_RENDERFORMAT
GetClipboardData
被调用时,剪贴板所有者会收到WM_RENDERFORMAT
消息。消息处理中,不需要OpenClipboard
,即使调用也是失败,因为GetClipboardData
前已经OpenClipboard
;需要的是为数据分配内存,并调用SetClipboardData
把数据传给剪贴板,其wParam
参数指定了需要的数据格式。WM_RENDERALLFORMAT
剪贴板所有者即将关闭前会收到WM_RENDERALLFORMAT
消息。消息处理中,应该为所有需要的数据格式准备好数据,并传给剪贴板。在这之前需要OpenClipboard
。WM_DESTROYCLIPBOARD
EmptyClipboard
被调用时,剪贴板所有权发生转移,windows发送WM_DESTROYCLIPBOARD
消息通知原剪贴板所有者。
最后
以上就是孝顺菠萝为你收集整理的12、剪贴板的全部内容,希望文章能够帮你解决12、剪贴板所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复