Win32剪贴簿

【引用windows程序设计】

标准剪贴簿数据格式
Windows支持不同的预先定义剪贴簿格式,这些格式在WINUSER.H定义成以CF为前缀的标识符。
首先介绍三种能够储存在剪贴簿上的文字数据型态,以及一个与剪贴簿格式相关的数据型态:CF_TEXT以NULL结尾的ANSI字符集字符串。它在每行末尾包含一个carriage return和linefeed字符,这是最简单的剪贴簿数据格式。传送到剪贴簿的数据存放在整体内存块中,并且是利用内存块句柄进行传送的(我将简短地讨论此项概念)。这个内存块专供剪贴簿使用,建立它的程序不应该继续使用它。 
CF_OEMTEXT含有文字数据(与CF_TEXT类似)的内存块。但是它使用的是OEM字符集。通常Windows程序不必关心这一点;它只有与在窗口中执行MS-DOS程序一起使用剪贴簿时才会使用。 
CF_UNICODETEXT含有Unicode文字的内存块。与CF_TEXT类似,它在每一行的末尾包含一个carriage return和linefeed字符,以及一个NULL字符(两个0字节)以表示数据结束。CF_UNICODETEXT只支援Windows NT。
CF_LOCALE一个国家地区标识符的句柄。表示剪贴簿文字使用的国别地区设定。 
下面是两种附加的剪贴簿格式,它们在概念上与CF_TEXT格式相似(也就是说,它们都是文字数据),但是它们不需要以NULL结尾,因为格式已经定义了数据的结尾。现在已经很少使用这些格式了:
CF_SYLK包含Microsoft 「符号连结」数据格式的整体内存块。这种格式用在Microsoft的Multiplan、Chart和Excel程序之间交换数据,它是一种ASCII码格式,每一行都用carriage return和linefeed结尾。 
CF_DIF包含数据交换格式(DIF)之数据的整体内存块。这种格式是由Software Arts公司提出的,用于把数据送到VisiCalc电子表格程序中。这也是一种ASCII码格式,每一行都使用carriage return和linefeed结尾。
下面三种剪贴簿格式与位图有关。所谓位图就是数据位的矩形数组,其中的数据位与输出设备的图素相对应。  第十四和 第十五章将详细讨论位图以及这些位图剪贴簿的格式:
CF_BITMAP与设备相关的位图格式。位图是通过位图句柄传送给剪贴簿的。同样,在把这个位图传送给剪贴簿之后,程序不应该再继续使用这个位图。 
CF_DIB定义一个设备无关位图(在第十五章中描述)的内存块。这种内存块是以位图信息结构开始的,后面跟着可用的颜色表和位图数据位。 
CF_PALETTE调色盘句柄。它通常与CF_DIB配合使用,以定义与设备相关的位图所使用的颜色调色盘。 
在剪贴簿中,还有可能以工业标准的TIFF格式储存的位图数据:
CF_TIFF含有标号图像文件格式(TIFF)数据的整体内存块。这种格式由Microsoft、Aldus公司和Hewlett-Packard公司以及一些硬件厂商推荐使用。这一格式可从Hewlett-Packard的网站上获得。 
下面是两个metafile格式,我将在第十八章详细讨论。一个metafile就是一个以二进制格式储存的画图命令集:
CF_METAFILEPICT以旧的metafile格式存放的「图片」。 
CF_ENHMETAFILE增强型metafile(32位Windows支持的)句柄。 
最后介绍几个混合型的剪贴簿格式:
CF_PENDATA与Windows的笔式输入扩充功能联合使用。 
CF_WAVE声音(波形)文件。 
CF_RIFF使用资源交换文件格式(Resource Interchange File Format)的多媒体数据。 
CF_HDROP与拖放服务相关的文件列表。 

【以文本方式访问剪贴簿】

从剪贴簿中取文本数据以及把文本送入剪贴簿(兼容ANSI和UNICODE)

#ifdef UNICODE
	#define CF_TCHAR CF_UNICODETEXT
#else
	#define CF_TCHAR CF_TEXT
#endif

//把剪贴簿内容送入pTarget(粘贴)
VOID GetTextFromClip(HWND hwnd,TCHAR **pTarget)
{
	HGLOBAL hGlobal;
	VOID *pGlobal;
	OpenClipboard(hwnd);
	//判断剪贴簿是否为文本格式并返回剪贴簿句柄
	hGlobal=GetClipboardData(CF_TCHAR);
	//如果是文本格式
	if(hGlobal!=NULL)
	{
		//锁定剪贴簿返回指向剪贴簿的指针
		pGlobal=GlobalLock(hGlobal);
		//把存放目标清空
		if(*pTarget)
		{
			free(*pTarget);
			*pTarget=NULL;
		}
		//重新为目标分配内存,数据大小与剪贴簿中文本一致
		*pTarget=malloc(GlobalSize(hGlobal));
		//将剪贴簿中数据送入目标
		lstrcpy(*pTarget,pGlobal);
		InvalidateRect(hwnd,NULL,TRUE);
	}
	CloseClipboard();//关闭剪贴薄	
}
//将pSource内容送入剪贴簿(复制、剪切)
VOID SetTextToClip(HWND hwnd,const TCHAR *pSource)
{
	//建立一个剪贴簿句柄分配一块与源szTemp同样大小的内存
	HGLOBAL hGlobal=GlobalAlloc( GMEM_SHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
		sizeof(TCHAR)*( lstrlen(pSource)+1 ) );
	//锁定剪贴簿句柄
	VOID *pGlobal=GlobalLock(hGlobal);
	//把数据送入剪贴簿
	lstrcpy(pGlobal,pSource);
	//解锁剪贴簿句柄
	GlobalUnlock(hGlobal);	
	//打开并清空剪贴簿
	OpenClipboard(hwnd);
	EmptyClipboard();
	//设置并关闭剪贴簿
	SetClipboardData(CF_TCHAR,hGlobal);
	CloseClipboard();
}

 

【剪贴簿的延迟处理】

如果从A程序复制数据到B程序,在数据量小的情况下可以直接按常规方法复制粘贴。延迟处理在面对大型数据时是个不错的选择。

例如在A程序中可以先将NULL设置在剪贴簿上,当B程序粘贴时会向Windows发出一个请求,这时Windows会向A程序发送一条WM_RENDERFORMAT消息。只要我们处理这个消息就可以进行延迟复制了,不必在进入B程序粘贴前去申请内存。另外当设置剪贴簿为NULL,并退出程序时会收到一个WM_RENDERALLFORMATS消息。

A程序中的代码:

#ifdef UNICODE //如果是UNICODE
#define CF_TCHAR CF_UNICODETEXT
#else //如果是ASNI
#define CF_TCHAR CF_TEXT
#endif

//设置剪贴板数据为NULL
void SetCbData(HWND hwnd)
{
	OpenClipboard(hwnd);
	EmptyClipboard();
	SetClipboardData(CF_TCHAR,NULL);
	CloseClipboard();
}

/*在消息处理过程中,当设置了剪贴簿为NULL。并在其它程序进行粘贴时*/
case WM_RENDERFORMAT:
	{
		HGLOBAL hGlobal;
		PTSTR pGlobal;
		TCHAR myStr[]=_T("abcdefghijklmn");
		INT szLen=(lstrlen(myStr)+1)*sizeof(TCHAR);
		hGlobal=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_SHARE,szLen);
		pGlobal=GlobalLock(hGlobal);
		lstrcpy(pGlobal,myStr);
		GlobalUnlock(hGlobal);
		SetClipboardData(CF_TCHAR,hGlobal);
	}
	break;
/*在消息处理过程中,当设置了剪贴簿为NULL。并退出程序时*/
case WM_RENDERALLFORMATS:		
	if(MessageBox(hwnd,_T("想要清空剪贴板吗"),_T(""),MB_OKCANCEL))
	{
		OpenClipboard(hwnd);
		EmptyClipboard();
		CloseClipboard();
	}
	break;

 

【剪贴簿同时设置多种格式】

设置三种格式的数据到剪贴簿
OpenClipboard(hwnd);       
EmptyClipboard();       
SetClipboardData(CF_TEXT, hGlobalText);       
SetClipboardData(CF_BITMAP, hBitmap);       
SetClipboardData(CF_METAFILEPICT, hGlobalMFP);       
CloseClipboard();

当这三种格式的数据同时位于剪贴簿上时
IsClipboardFormatAvailable(CF_TEXT)返回TRUE
IsClipboardFormatAvailable(CF_BITMAP)返回TRUE
IsClipboardFormatAvailable(CF_METAFILEPICT)返回TRUE

从剪贴簿中取回数据
hGlobalText = GetClipboardData(CF_TEXT);
hBitmap = GetClipboardData (CF_BITMAP);
hGlobalMFP = GetClipboardData (CF_METAFILEPICT);

【自定义剪贴簿格式】

RegisterClipboardFormat(LPCTSTR formatName)函数可以注册一种格式,它返回一个0x0000~0xFFFF的UINT格式码。注册后就可以使用自定义的格式了。

例如:

UINT myFormat=RegisterClipboardFormat(_T("自定义格式"));
SetClipboardData(myFormat,hMem);//hMem可以是字符,位图,或者其它

这种自定义的格式只对你自己的程序有意义,所以可以配合几个函数使用

HWND hwndClipOwner = GetClipboardOwner () ;//得到剪贴簿提供者的窗口句柄

TCHAR clsName[64] ;

GetClassName( hwndClipOwner,clsName,sizeof(clsName) ); //把窗口句柄为hwndClipOWner的类名送入clsName中

通过判断窗口句柄或类名来决定是否处理自定义格式的数据。

 

剪贴簿浏览器

1、设置一个剪贴簿浏览器:

HWND nextClipHwnd=SetClipboardViewer(hwnd);

如果该程序第一次运行,则nextClipHwnd返回NULL。如果不关闭第一个程序,再次运行一个。则第二次运行的nextClipHwnd等于第一个程序的句柄,第一个的nextClipHwnd是NULL。有点像链表。

 WM_DRAWCLIPBOARD消息:如果设置了剪贴簿浏览器就会收到本消息。一般是判断nextClipHwnd是否为NULL,如果不为NULL就将此消息发送给nextClipHwnd处理SendMessage(nextClipHwnd,WM_DRAWCLIPBOARD,wParam,lParam)。如果为NULL就不作处理。

//当设置了剪贴簿浏览器时
	case WM_DRAWCLIPBOARD:
		//如果下一个存在,可以继续发给下一个处理
		if(nextClipHwnd)
			SendMessage(nextClipHwnd,message,wParam,lParam);


 

2、改变剪贴簿浏览器链表:

当在程序中用代码SetClipboardViewer(hwnd)设置了剪贴簿链表,接着运行4个该程序的实例,假设:

第一个的窗口句柄:hwnd1,则nextClipHwnd=NULL

第二个的窗口句柄:hwnd2,则nextClipHwnd=hwnd1

第三个的窗口句柄:hwnd3,则nextClipHwnd=hwnd2

第四个的窗口句柄:hwnd4,则nextClipHwnd=hwnd3

如果关闭第二个窗口,那剪贴簿浏览器就断了。这时可以在WM_DESTORY消息中调用ChangeClipboardChain(hwnd,nextClipHwnd);再PostQuitMessage(0);这时第二个窗口在退出前会向最顶层的hwnd4发送一个WM_CHANGECBCHAIN通知它要退出了,剪贴簿链表即将被修改。将wParam设置为hwnd表示自己,lParam设置为nextClipHwnd表示自己的下一个。

如果要继续维护剪贴簿链表,可以在WM_CHANGECBCHAIN中进行如下处理:

思路是当hwnd2关闭时向顶层hwnd4发送WM_CHANGECBCHAIN消息,那么顶层hwnd4在WM_CHANGECBCHAINj里判断wParam和lParam参数,如果hwnd4的nextClipHwnd等于wParam,则表示hwnd4的nextClipHwnd是hwnd2,实际hwnd4的nextClipHwnd是hwnd3。如果hwnd4的nextClipHwnd不等于wParam那么hwnd4就向hwnd3继续发送WM_CHANGECBCHAIN消息。当hwnd3收到时再次判断,这时wParam等于hwnd3的nextClipHwnd了,lParam保存着hwnd2的nextClipHwnd,既然hwnd2销毁了。那么hwnd3就把nextClipHwnd设置为hwnd1。这样就把要断掉的链表重新链起来了。

hwnd4, nextClipHwnd=hwnd3

hwnd3, nextClipHwnd=hwnd2

hwnd2, nextClipHwnd=hwnd1

hwnd1, nextClipHwnd=NULL

把hwnd2关掉后

hwnd4, nextClipHwnd=hwnd3

hwnd3, nextClipHwnd=hwnd1

hwnd1, nextClipHwnd=NULL

 

case WM_CHANGECBCHAIN:
		//如果下一个是wParam,则把自己的下一个设置为wParam的下一个
		//因为wParam关闭前调用了ChangeClipboardChain(hwnd,nextClipHwnd)发送了此消息
		if(nextClipHwnd==wParam)
			nextClipHwnd=lParam;
		//如果下一个不是wParam,继续发到下一个
		else if(nextClipHwnd)
			SendMessage(nextClipHwnd,message,wParam,lParam);
		//其它处理;
		break;


由于时间有限,还有些更复杂的剪贴簿知识当需要用到时再研究。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值