进程的通信 - 剪切板

剪切板是系统维护管理的一块内存区域,本机的所有进程都可以访问。当一个进程复制数据时,先将数据放在该内存区,当另一个进程粘贴时,则是从该内存区块取出数据

剪切板操作:

其实在剪切板中也就那几个API在使用,下面会介绍几个常用的API,然后会给出一个demo示例

剪切板打开—OpenClipboard

BOOL OpenClipboard(
  [in, optional] HWND hWndNewOwner
);

OpenClipboard函数用来打开剪切板(放数据前的笔要操作)。参数hWndNewOwner指向一个窗口句柄,即代表是这个窗口打开的剪切板,如果这个参数设置为NULL,则以当前任务来打开剪切板 。如果有另一个窗口打开了剪切板,则函数失败,返回零。

 清空剪切板—EmptyClipboard

BOOL EmptyClipboard();

这个函数将清空剪贴板,并释放剪贴板中数据的句柄,然后将剪贴板的所有权分配给当前打开剪贴板的窗口。

因为剪贴板是所有进程都可以访问的,所以应用程序在使用这个剪贴板时,有可能已经有其他的应用程序把数据放置到了剪贴板上,因此该进程打开剪贴板之后,就需要调用 EmptyClipboard 函数来清空剪贴板,释放剪贴板中存放的数据的句柄,并将剪贴板的所有权分配给当前的进程,这样做之后当前打开这个剪贴板的程序就拥有了剪贴板的所有权,因此这个程序就可以往剪贴板上放置数据了。

数据发送到剪切板—SetClipboardData

HANDLE SetClipboardData(
  [in]           UINT   uFormat,
  [in, optional] HANDLE hMem
);
  • 参数uFormat用来指定发送剪切板上的数据的格式

常见的有CF_BTMAP(bitmap类型),CF_TEXT(text类型),CT_DIB等

  • 参数hMen表示一个指定格式的数据句柄。 

如果hMen参数标识的是内存对象,则必须带有GME_MOVEABLE属性的函数分配对象。下面的GlobalAlloc函数可以创建这种标识的内存对象句柄。

应用程序在调用了 SetClipboardData 函数之后,系统就拥有了 hMem 参数所标识的数据对象,该应用程序可以读取这个数据对象,但是在应用程序调用 CloseClipboard 函数之前,它都是不能释放该对象的句柄的,或者锁定这个句柄,如果 hMem 标识一个内存对象,那么这个对象必须是利用 GMEM_MOVEABLE 标识调用 GlobalAlloc 函数为其分配内存的。

数据句柄—GlobalAlloc 

DECLSPEC_ALLOCATOR HGLOBAL GlobalAlloc(
  [in] UINT   uFlags,
  [in] SIZE_T dwBytes
);

GlobalAlloc函数上分配指定数目的字节

这里有读者可能会问:为什么我们在自己的应用程序中不使用 GlobalAlloc 函数来分配内存,而是要使用 malloc 或者 new  来实现?

其实,这个也只用稍微想想就知道了,使用 malloc 或者 new 分配的内存是在进程的私有地址空间上分配的,这块私有地址空间归这个进程所拥有,在之后对这块内存的读写会快很多,而全局内存不属于这个进程,你下次要去访问全局内存的时候,还得通过映射转换,这样肯定是运行效率低。

  • 第一个参数表示内存分配的属性,例如上面要求的GME_MOVEABLE表示分配可移动内存 。
  • 第二个参数表示分配的字节数。

函数执行成功,返回新分配内存对象的句柄,否则返回NULL。

锁定全局内存对象—GlobalLock

LPVOID GlobalLock(
  [in] HGLOBAL hMem
);

锁定全局内存对象并返回指向该对象内存块的第一个字节的指针。我们可以通过这个指针对这块内存数据存取,这也保证了其他进程不会对这块内存的数据修改。

  • 参数hMem表示全局内存对象的句柄。此句柄由 GlobalAlloc 或GlobalReAlloc函数返回。

每个内存对象的内部数据结构包括最初为零的锁计数。对于可移动内存对象(GME_MOVEABLE),全局锁定将计数递增 1,全局解锁函数将计数递减 1。锁定内存对象的内存块将保持锁定状态,直到其锁定计数减少到零,此时可以移动或丢弃它。

全局内存对象解锁—GlobalUnLock

BOOL GlobalUnlock(
  [in] HGLOBAL hMem
);

GlobalUnlock函数递减与分配了GMEM_MOVEABLE的内存对象关联的锁定计数

  • 参数hMem表示全局内存对象的句柄。此句柄由 GlobalAlloc 或GlobalReAlloc函数返回。 

若函数执行完后内存对象仍处于锁定状态,则函数返回非零值,如果减少计数后解锁内存对象,则函数返回零(GetLasrError返回NO_ERROR),如果函数失败,则返回零(GetLastError返回NO_ERROR以外的值)

剪切板中的数据格式判断—IsClipboardFormatAvaliable

BOOL IsClipboardFormatAvailable(
  [in] UINT format
);

该函数将确定剪贴板是否包含指定格式的数据。如果剪贴板格式可用,则返回值为非零值。否则返回零。

  • 参数format指明需要判断的格式

剪贴板中数据接收—GetClipboardData

HANDLE GetClipboardData(
  [in] UINT uFormat
);

GetClipboardData以指定格式从剪贴板检索数据。剪贴板之前必须已打开。函数成功,返回指定格式剪切板对象的句柄,失败返回NULL。

Demo示例

创建一个MFC项目

当接收按钮按下后,会打开剪切板,将上方编辑框里的内容放到剪切板内

当接收按钮按下后,则会将剪切板中的内容粘贴到上方编辑框中。

接收按钮程序:

void CClipDlg::OnBnClickedSendBtn()
{
	
	//打开剪切板
	if (OpenClipboard()) {
		//清空剪切板
		EmptyClipboard();

		char* szSendBuf;//要发送的数据

		//获取编辑框的内容
		CStringW strSendW;
		GetDlgItemText(IDC_SEND_EDIT, strSendW);

		CStringA  strSend = (CStringA)strSendW;
		//分配一个内存对象,内存对象的句柄就是hClip
		HANDLE hClip = GlobalAlloc(GMEM_MOVEABLE, strSend.GetLength() + 1);
			//句柄加锁
		szSendBuf = (char*)GlobalLock(hClip);

	
		//将指定字符串复制到目标字符串,若目标字符串大小小于指定字符串,则会溢出
		//第一个参数为目标字符串,第二个参数为指定字符串
		strcpy(szSendBuf, strSend);

		//TRACE("seSendBuf =%s", szSendBuf);
			//解锁
		GlobalUnlock(hClip);
		//将数据放在剪切板
		SetClipboardData(CF_TEXT, hClip);
		//关闭剪切板
		CloseClipboard();
	}
}

发送按钮程序:

void CClipDlg::OnBnClickedButton1()
{
	if (OpenClipboard()) {
		//先确认剪切板是否可用
		if (IsClipboardFormatAvailable(CF_TEXT)) {
			HANDLE hClip;
			char* pBuf;
			//向剪切板要数据
			hClip = GetClipboardData(CF_TEXT);
			pBuf = (char*)GlobalLock(hClip);

			

			USES_CONVERSION;
			LPCWSTR strBuf = A2W(pBuf);
			GlobalUnlock(hClip);
			//显示
			SetDlgItemText(IDC_RECV_EDIT, strBuf);
			
		}
		CloseClipboard();
	}
}

运行:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值