分享

浅析Windows编程的剪贴板机制

 微米工 2013-12-12
摘要: 本文对Windows剪贴板机制作了深入、全面的阐述,具体内容包括:文本、位图、DSP、自定义格式剪贴板的使用和多数据项和延迟提交技术。

  关键词: VC++6.0; 剪贴板机制;数据格式;延迟提交

  Windows剪贴板

  Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存,用来暂存在各进程间进行交换的数据:提供数据的进程创建一个全局内存块,并将要传送的数据移到或复制到该内存块;接受数据的进程(也可以是提供数据的进程本身)获取此内存块的句柄,并完成对该内存块数据的读取。

  为使剪贴板的这种IPC机制更加完善和便于使用,需要解决好如下三个问题:提供数据的进程在结束时Windows系统将删除其创建的全局内存块,而接受数据的进程则希望在其退出后剪贴板中的数据仍然存在,可以继续为其他进程所获取;能方便地管理和传送剪贴板数据句柄;能方便设置和确定剪贴板数据格式。为完善上述功能,Windows提供了存在于USER32.dll中的一组API函数、消息和预定义数据格式等,并通过对这些函数、消息的使用来管理在进程间进行的剪贴板数据交换。

  Windows系统为剪贴板提供了一组API函数和多种消息,基本可以满足编程的需要。而且Windows还为剪贴板预定义了多种数据格式。通过这些预定义的格式,可以使接收方正确再现数据提供方放置于剪贴板中的数据内容。

  文本剪贴板和位图剪贴板的使用

  这两种剪贴板是比较常用的。其中,文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板,是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不带任何格式信息的ASCII字符。若要将文本传送到剪贴板,可以先分配一个可移动全局内存块,然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函数将数据放置到剪贴板:

DWORD dwLength = 100; // 要复制的字串长度
HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存
LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存
for (int i = 0; i < dwLength; i++) // 将"*"复制到全局内存块
 *lpGlobalMemory++ = '*';
 GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
 HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
 ::OpenClipboard(hWnd); // 打开剪贴板
 ::EmptyClipboard(); // 清空剪贴板
 ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
 ::CloseClipboard(); // 关闭剪贴板

  这里以OpenClipboard()打开剪贴板,并在调用了EmptyClipboard()后使hWnd指向的窗口成为剪贴板的拥有者,一直持续到CloseClipboard()函数的调用。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。

  从剪贴板获取文本的过程与之类似,首先打开剪贴板并获取剪贴板的数据句柄,如果数据存在就拷贝其数据到程序变量。由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它:

HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄
DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小
LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存
m_sMessage = CString(lpClipMemory); // 保存得到的文本数据
GlobalUnlock(hClipMemory); // 内存解锁
::CloseClipboard(); // 关闭剪贴板

  大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的,只是数据格式要指明为CF_BITMAP,而且在使用SetClipboardData()或GetClipboardData()函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例代码将把存在于剪贴板中的位图数据显示到程序的客户区:

HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄
HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄
HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境
SelectObject(hdcMem, hBitmap); // 选择对象
SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式
BITMAP bm; // 得到位图对象
GetObject(hBitmap, sizeof(BITMAP), &bm);
BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制
::ReleaseDC(hWnd, hDC); // 释放设备环境句柄
DeleteDC(hdcMem); // 删除内存环境
::CloseClipboard(); // 关闭剪贴板

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多