Windows 剪切板API详解

 剪切、复制、粘贴都是我们在操作电脑的时候经常会用到的功能。但是你知道当我们剪切或者复制的 时候,数据会保存到什么地方吗?当我们粘贴的时候,又是从什么地方将数据输出出来呢?这都源自于系统中给我们提供了一个暂存数据的存储区域,我们称之为剪 切板,当新的内容送到剪切板后,新的内容将会覆盖掉旧的内容,即剪切板只能保存一份内容。因为剪切板是在内存当中,所以,电脑关闭或者是重启以后,存在剪 切板中的内容将会丢失掉。

除了我们人工的ctrl+C或ctrl+V进行对剪切板的操作以外,我们同时可以使用Windows给我们提供的API来让程序来进行剪切板的复制及粘贴。本篇文章以Visual Studio 2012为编程环境,使用C语言来演示程序操作剪切板的详细教程。


 

当我们想往剪切板中写入数据时,我们首先需要做的就是打开剪切板:

Bool OpenClipboard(HWND hWndNewOwner);

hWndNewOwner参数指定关联到打开剪切板的窗口句柄,传入NULL表示关联到当前任务。每次只允许一个进程打开并访问。当打开后,操作完剪切板以后,就必须要关闭剪切板,因为剪切板每次只能允许一个进程对其进行访问。如果打开剪切板后不关闭,除非程序结束,否则其他进程就无法使用剪切板。


 

当我们打开剪切板后,需要做的操作便是清空剪切板,在写入剪切板数据之前,我们必须得先清空剪切板,得到剪切板的操控权:

Bool EmptyClipboard(void)

当完成以上两个操作以后,我们开始为剪切板分配内存:

HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);

 第一个参数为分配内存属性,可以是以下内存属性:

 GMEM_FIXED分配一块固定的内存去续,不允许系统移动,这时返回值是一个指针。
GMEM_MOVEABLE分配一块可移动的内存区域,实际上内存块在物理内存中是不可移动的,这里的可移动指的是在应用程序 的默认逻辑堆内可以移动。返回值是内存对象的句柄。可以通过调用GlobalLock()函数讲一个句柄转化为 一个指针,这个标志不能和GMEM_FIXED同时使用。
GMEM_ZEROINT初始化内存对象为全0,如果不用这个标志,内存对象将为不确定的内
GHNDGMEM_MOVEABLE和GMEM_ZEROINT联合使用,即可移动同时初始化为0
GPTRGMEM_FIXED和GMEM_ZEROINT同时使用,即不可移动同时初始化为0

第二个参数为分配的大小。如果成功则指向该内存,如果失败则返回NULL。

如果我们分配内存的参数一的内存属性为GMEM_FIXED或GPTR,获得的便是一个指向内存区域的指针,不需要进行锁定内存及解锁内存的操作,直接使用memcpy函数将数据复制到分配的内存区域中即可,如果内存属性为GMEM_MOVEABLE或GHND,获得的便是一块内存区域,我们需要将内存区域转化为一个指针:

LPVOID GlobalLock(HGLOBAL hMem);

如果分配内存时分配的内存属性为GMEM_MOVEABLE或GHND,那么就需要锁定内存,锁定由GlobalAlloc分配的内存,并将内存对象的锁定计数器+1。如果该函数成功,则返回内存区域的起始地址指针,失败则返回NULL,GlobalLock会将计数器加1,而GlobalUnlock函数将使计数器减1。对于每次GlobalLock的每一次调用,都必须相应的调用一次GlobalUnlock函数。否则被锁定的内存空间不能够被移动或释放。直到计数器为0时被锁定的内存快才会被移动或者是释放。(更详细的解释请参考MSDN文档:GlobalLock function(Windows))

如果执行成功,返回的便是内存区域的起始地址指针,我们可以使用memcpy将数据复制到该片内存区域,当执行完毕复制以后,我们需要解除锁定的内存:

 BOOL GlobalUnlock(HGLOBAL hMem);

参数1为使用分配内存返回的内存区域。


当内存分配完毕后,便可以将数据写入剪切板了。

HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);

参数1为剪切板的数据格式,可以是以下格式:

CF_TEXT以NULL结尾的ANSI字符集字符串。它在每行末尾包含一个carriage return和linefeed字符,这是最简单的剪切板数据格式
CF_OEMTEXT含有文字数据(与CF_TEXT类似)的内存块。但是它使用的是OEM字符集。
CF_UNICODETEXT含有Unicode文字的内存快。与CF_TEXT类似,它在每一行的末尾包含一个carriage return和linefeed字符,以及一个NULL字符(两个0字节)以表示数据结束。CF_UNICODETEXT针对UNICONDE格式
CF_SYLK包含Microsoft 「符号连结」数据格式的整体内存块。这种格式用在Microsoft的Multiplan、Chart和Excel程序之间交换数据,它是一种ASCII码格式。
CF_DIF包含数据交换格式(DIF)之数据的整体内存块。用于把数据送到VisiCalc电子表格程序中。这也是一种ASCII码格式
CF_BITMAP与设备相关的位图格式。位图是通过位图句柄传送给剪贴簿的。
CF_DIB定义一个设备无关位图的内存块。
CF_PALETTE调色盘句柄。
CF_METAFILEPICT以旧的metafile格式存放的「图片」。
CF_ENHMETAFILE增强型metafile(32位Windows支持的)句柄。
CF_PENDATA与Windows的笔式输入扩充功能联合使用
CF_WAVE声音(波形)文件。
CF_RIFF使用资源交换文件格式(Resource Interchange File Format)的多媒体数据。
CF_HDROP与拖放服务相关的文件列表。

该数据表使用谷歌自动翻译完成,如果英文较好,可查看MSDN文档:Standard Clipboard Formats(Windows)

参数2为分配的内存区域。如果执行成功,则返回数据句柄,否则返回NULL。


当完成对剪切板的操作以后,我们还需要关闭剪切板:

Bool CloseClipboard(void);

直接调用该函数便可关闭剪切板,只有执行此函数后,其他进程才能使用剪切板,关闭剪切板后,当前进程就不能写入数据。


 

如果我们想获取剪切板中数据,可以使用GetClipboardData函数:

HANDLE GetClipboardData(UINT uFormat);

参数1为剪切板的数据格式,参见:剪切板的数据格式

如果执行成功,则返回数据句柄,否则返回NULL。


下面是代码例程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

int main(int argc, char * argv[])
{
 HGLOBAL hMemory;
 LPTSTR lpMemory;
 char * content = "蓝雨麦郎版权所有";   // 待写入数据
 int contentSize = strlen(content) + 1;

 if(!OpenClipboard(NULL))    // 打开剪切板,打开后,其他进程无法访问
 {
  puts("剪切板打开失败");
  return 1;
 }

 if(!EmptyClipboard())       // 清空剪切板,写入之前,必须先清空剪切板
 {
  puts("清空剪切板失败");
  CloseClipboard();
  return 1;
 }

 if((hMemory = GlobalAlloc(GMEM_MOVEABLE, contentSize)) == NULL)    // 对剪切板分配内存
 {
  puts("内存赋值错误!!!");
  CloseClipboard();
  return 1;
 }

 if((lpMemory = (LPTSTR)GlobalLock(hMemory)) == NULL)             // 将内存区域锁定
 {
  puts("锁定内存错误!!!");
  CloseClipboard();
  return 1;
 }

 memcpy_s(lpMemory, contentSize, content, contentSize);   // 将数据复制进入内存区域

 GlobalUnlock(hMemory);                   // 解除内存锁定

 if(SetClipboardData(CF_TEXT, hMemory) == NULL)
 {
  puts("设置剪切板数据失败!!!");
  CloseClipboard();
  return 1;
 }

 system("pause");
 return 0;
}

转载于:https://www.cnblogs.com/cnlyml/archive/2013/03/02/2940434.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值