剪贴板是由系统定义的,并不属于任何一个特定的进程。系统中所有进程都可以访问和设置剪贴板。剪贴板最大的特点就是数据传输没有明确的目标,数据是被动访问的;剪贴板的内容可以被多次访问,直到新的数据写入。剪贴板是一种可供选择的进程间通信方式,但由于系统中任何一个进程都可以都可以无限制地访问剪贴板,因此,它是一种不可靠的通信方式。

1)获取和设置剪贴板数据

涉及到的API有:OpenClipboard、EmptyClipboard、SetClipboardData、GetClipboardData、CloseClipboard等。

OpenClipboard用于打开剪贴板,获得剪贴板的句柄:

BOOL WINAPI OpenClipboard(

__in_opt  HWND hWndNewOwner //指定的窗口可以收到剪贴板操作所产生的消息

//如果为NULL,则采用当前任务的窗口

);

EmptyClipboard用于清空剪贴板中的内容:

BOOL WINAPI EmptyClipboard(void);

SetClipboardData用于设置剪贴板的内容:

HANDLE WINAPI SetClipboardData(

__in      UINT uFormat,       //指定数据格式,可以是标准系统格式,也可以是用户自定义格式

__in_opt  HANDLE hMem     //需要设置的数据的内存句柄;需使用全局内存管理的函数分配和

//设置,且在分配时需指定GMEM_MOVEABLE标志

);

GetClipboardData用于从剪贴板获取数据:

HANDLE WINAPI GetClipboardData(

__in  UINT uFormat //指定获取的数据的格式,获得的数据使用句柄返回

);

2)一般来说利用剪贴板进行数据通信是不具有实时性,所有操作都依赖于用户。除非使用剪贴板查看器Viewer,这样就可以立即知道剪贴板中内容的变化。

系统提供了WM_DRAWCLIPBOARD消息用于监视剪贴板的变化。如果调用SetClipboardViewer函数设置了窗口为剪贴板查看器,那么当剪贴板中内容变化时,所注册的查看器窗口就会收到WM_CHANGECBCHAIN消息和WM_DRAWCLIPBOARD消息。SetClipboardViewer函数原型如下:

HWND WINAPI SetClipboardViewer(

__in  HWND hWndNewViewer //指定监视窗口

);

剪贴板查看器的代码例子如下:

HINSTANCE hinst;

UINT uFormat = (UINT)(-1);

BOOL fAuto = TRUE;

LRESULT CALLBACK MainWndProc(HWND hwnd,

UINT uMsg,

WPARAM wParam,

LPARAM lParam)

{

static HWND hwndNextViewer;

HDC hdc;

HDC hdcMem;

PAINTSTRUCT ps;

LPPAINTSTRUCT lpps;

RECT rc;

LPRECT lprc;

HGLOBAL hglb;

LPSTR lpstr;

HBITMAP hbm;

HENHMETAFILE hemf;

HWND hwndOwner;

switch (uMsg)

{

case WM_PAINT: //收到WM_PAINT消息后显示剪贴板中的数据

hdc = BeginPaint(hwnd, &ps);

// Branch depending on the clipboard format.

//uFormat全局变量,在WM_DRAWCLIPBOARD和WM_COMMAND

//消息处理中,使用SetAutoView设置

//根据剪贴板中数据的不同格式,使用不同的显示方式

switch (uFormat)

{

case CF_OWNERDISPLAY: //剪贴板的所有者必须显示并刷新Viewer的窗口

hwndOwner = GetClipboardOwner();//获得剪贴板的所有者

//获取剪贴板的数据

hglb = GlobalAlloc(GMEM_MOVEABLE,

sizeof(PAINTSTRUCT));

lpps = (LPPAINTSTRUCT)GlobalLock(hglb);

memcpy(lpps, &ps, sizeof(PAINTSTRUCT));

GlobalUnlock(hglb);

//向剪贴板所有者发送WM_PAINTCLIPBOARD消息

SendMessage(hwndOwner, WM_PAINTCLIPBOARD,

(WPARAM) hwnd, (LPARAM) hglb);

GlobalFree(hglb);

break;

case CF_BITMAP: //位图

hdcMem = CreateCompatibleDC(hdc);

if (hdcMem != NULL)

{

if (OpenClipboard(hwnd)) //打开剪贴板

{

hbm = (HBITMAP)

GetClipboardData(uFormat); //获取剪贴板的数据

//将位图选择进DC,显示在窗口客户区

SelectObject(hdcMem, hbm);

GetClientRect(hwnd, &rc);

BitBlt(hdc, 0, 0, rc.right, rc.bottom,

hdcMem, 0, 0, SRCCOPY);

CloseClipboard();//关闭剪贴板

}

DeleteDC(hdcMem); //释放DC

}

break;

case CF_TEXT: //文本

if (OpenClipboard(hwnd)) //打开剪贴板

{

hglb = GetClipboardData(uFormat); //获得剪贴板数据

lpstr = GlobalLock(hglb);

//将文本绘制在窗口客户区

GetClientRect(hwnd, &rc);

DrawText(hdc, lpstr, -1, &rc, DT_LEFT);

GlobalUnlock(hglb);

CloseClipboard();//关闭剪贴板

}

break;

case CF_ENHMETAFILE: //增强格式图元文件

if (OpenClipboard(hwnd)) //打开剪贴板

{

hemf = GetClipboardData(uFormat); //获取剪贴板数据

//调用PlayEnhMetaFile在窗口客户区上显示

GetClientRect(hwnd, &rc);

PlayEnhMetaFile(hdc, hemf, &rc);

CloseClipboard();

}

break;

case 0: //剪贴板为空

GetClientRect(hwnd, &rc);

//在客户区中央显示

DrawText(hdc, "The clipboard is empty.", -1,

&rc, DT_CENTER | DT_SINGLELINE |

DT_VCENTER);

break;

default: //不支持的其他格式

GetClientRect(hwnd, &rc);

DrawText(hdc, "Unable to display format.", -1,

&rc, DT_CENTER | DT_SINGLELINE |

DT_VCENTER);

}

EndPaint(hwnd, &ps);

break;

case WM_SIZE: //如果窗口大小改变,通知剪贴板所有者窗口

if (uFormat == CF_OWNERDISPLAY)

{

hwndOwner = GetClipboardOwner();//获取剪贴板所有者

hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(RECT));

lprc = GlobalLock(hglb);

GetClientRect(hwnd, lprc);

GlobalUnlock(hglb);

SendMessage(hwndOwner, WM_SIZECLIPBOARD,

(WPARAM) hwnd, (LPARAM) hglb);

GlobalFree(hglb);

}

break;

case WM_CREATE: //当窗口创建时,在剪贴板Viewer链中增加一个

hwndNextViewer = SetClipboardViewer(hwnd);

break;

case WM_CHANGECBCHAIN:

// If the next window is closing, repair the chain.

if ((HWND) wParam == hwndNextViewer)

hwndNextViewer = (HWND) lParam;

// Otherwise, pass the message to the next link.

else if (hwndNextViewer != NULL)

SendMessage(hwndNextViewer, uMsg, wParam, lParam);

break;

case WM_DESTROY:

//窗口hwnd销毁时,从剪贴板查看器链中移除

ChangeClipboardChain(hwnd, hwndNextViewer);

PostQuitMessage(0);

break;

case WM_DRAWCLIPBOARD:  // clipboard contents changed.

// Update the window by using Auto clipboard format.

SetAutoView(hwnd);

// Pass the message to the next window in clipboard

// viewer chain.

SendMessage(hwndNextViewer, uMsg, wParam, lParam);

break;

case WM_INITMENUPOPUP: //当popup菜单弹出时收到此消息

if (!HIWORD(lParam)) //根据剪贴板中内容的格式设置菜单

InitMenu(hwnd, (HMENU) wParam);

break;

case WM_COMMAND: //处理用户菜单输入

switch (LOWORD(wParam))

{

case IDM_EXIT: //用户点击“退出”菜单项

DestroyWindow(hwnd);

break;

case IDM_AUTO: //用户点击“Auto”菜单项

SetAutoView(hwnd); //设置显示格式为自动

break;

default:

fAuto = FALSE;

uFormat = LOWORD(wParam);

InvalidateRect(hwnd, NULL, TRUE);

}

break;

default: //其他消息

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

return (LRESULT) NULL;

}

/**********************************************************

* void WINAPI SetAutoView(HWND hwnd)

* 获取剪贴板的主要格式,并设置显示方式

**********************************************************/

void WINAPI SetAutoView(HWND hwnd)

{

static UINT auPriorityList[] = {

CF_OWNERDISPLAY,

CF_TEXT,

CF_ENHMETAFILE,

CF_BITMAP

};

//设置剪贴板主要格式,设置显示格式

//uFormat在收到WM_PAINT消息时用到

uFormat = GetPriorityClipboardFormat(auPriorityList, 4);

fAuto = TRUE;

InvalidateRect(hwnd, NULL, TRUE);

UpdateWindow(hwnd);

}

/**************************************************************

* 功能:根据剪贴板中内容的格式,设置菜单项供用户选择显示方式

* 参数:hwnd--窗口句柄

*       hmenu--菜单句柄

**************************************************************/

void WINAPI InitMenu(HWND hwnd, HMENU hmenu)

{

UINT uFormat;

char szFormatName[80];

LPCSTR lpFormatName;

UINT fuFlags;

UINT idMenuItem;

// If a menu is not the display menu, no initialization is necessary.

if (GetMenuItemID(hmenu, 0) != IDM_AUTO)

return;

// Delete all menu items except the first.

while (GetMenuItemCount(hmenu) > 1)

DeleteMenu(hmenu, 1, MF_BYPOSITION);

// Check or uncheck the Auto menu item.

fuFlags = fAuto ? MF_BYCOMMAND | MF_CHECKED :

MF_BYCOMMAND | MF_UNCHECKED;

CheckMenuItem(hmenu, IDM_AUTO, fuFlags);

// If there are no clipboard formats, return.

if (CountClipboardFormats() == 0)

return;

// Open the clipboard.

if (!OpenClipboard(hwnd))

return;

// Add a separator and then a menu item for each format.

AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);

uFormat = EnumClipboardFormats(0);

while (uFormat)

{

// Call an application-defined function to get the name

// of the clipboard format.

lpFormatName = GetPredefinedClipboardFormatName(uFormat);

// For registered formats, get the registered name.

if (lpFormatName == NULL)

{

// Note that, if the format name is larger than the

// buffer, it is truncated.

if (GetClipboardFormatName(uFormat, szFormatName,

sizeof(szFormatName)))

lpFormatName = szFormatName;

else

lpFormatName = "(unknown)";

}

// Add a menu item for the format. For displayable

// formats, use the format ID for the menu ID.

if (IsDisplayableFormat(uFormat))

{

fuFlags = MF_STRING;

idMenuItem = uFormat;

}

else

{

fuFlags = MF_STRING | MF_GRAYED;

idMenuItem = 0;

}

AppendMenu(hmenu, fuFlags, idMenuItem, lpFormatName);

uFormat = EnumClipboardFormats(uFormat);

}

CloseClipboard();

}

BOOL WINAPI IsDisplayableFormat(UINT uFormat)

{

switch (uFormat)

{

case CF_OWNERDISPLAY:

case CF_TEXT:

case CF_ENHMETAFILE:

case CF_BITMAP:

return TRUE;

}

return FALSE;

}

3)剪贴板中存在各种数据格式,系统使用一个UINT类型的数据来表示剪贴板中数据类型。在这些格式信息中,有很多是各种应用程序之间通用的,比如文本、位图等。这些数据格式由系统预先定义,称为标准格式;当然应用程序也可自行定义剪贴板的数据格式,这样可以方便地在同一个应用程序的不同实例间进行数据传递而不用对数据格式进行过多的处理(典型的就包括word)。

常见标准格式:

CF_BITMAP    //位图句柄(HBITMAP)

CF_DIB             //内存位置包含BITMAPINFO结构和位图数据

CF_ENHMETAFILE         //增强的图元文件句柄(HENHMETAFILE)

CF_OEMTEXT        //OEM字符集的字符串(以CR-LF格式换行)

CF_OWNERDISPLAY    //由剪贴板查看器查看的格式

CF_PALETTE  //调色板数据

CF_RIFF  //标准的CF_WAVE波形数据

CF_TEXT          //ANSI字符串(以CR-LF格式换行)

CF_WAVE       //PCM波形

CF_TIFF  //Tagged图像文件格式

CF_UNICODETEXT       //Unicode字符串

自定义格式:

调用函数RegisterClipboardFormat可以自定义格式:

UINT WINAPI RegisterClipboardFormat(//返回值是系统分配的格式类型值(UINT)

__in  LPCTSTR lpszFormat //格式名,

);

多种格式:

很多情况下,数据的格式不止一种,比如格式化的文本有效的格式不止一种(例如从Word中复制的数据、从网页中复制的数据等),因此可能存在多重格式。

以下几个API函数是用于获取当前剪贴板中的格式信息的:

GetPriorityClipboardFormat的功能是检测剪贴板中是否有paFormatPriorityList参数指定的格式数组中的格式存在,如果有则返回格式数组中的第一个剪贴板当前具有的格式:

int WINAPI GetPriorityClipboardFormat(

__in  UINT *paFormatPriorityList, //格式数组,存储用于检测的格式信息

__in  int cFormats    //paFormatPriorityList数组的大小

);

CountClipboardFormats函数用于返回当前剪贴板中具有的不同格式的数量:

int WINAPI CountClipboardFormats(void);

EnumClipboardFormats函数用于列举当前剪贴板中的所有格式:

UINT WINAPI EnumClipboardFormats(

__in  UINT format   //指定一个已知的格式,通过函数返回值返回下一个格式

);

GetUpdatedClipboardFormats函数用于获取当前剪贴板的所有格式:

BOOL WINAPI GetUpdatedClipboardFormats(

__out  PUINT lpuiFormats, //指向用于保存返回的格式数组的缓冲区

__in   UINT cFormats, //lpuiFormats可以容纳的格式信息的数量

__out  PUINT pcFormatsOut //返回真是的数组大小

);

由于剪贴板数据会有多种格式,在调用GetClipboardData函数获取数据时,应该指定格式。一般情况下,指定不同格式,将获得不同的内容。

剪贴板数据的格式信息:

每一个剪贴板格式都有一个格式名,格式名是一个字符串,使用GetClipboardFormatName函数可以获得:

int WINAPI GetClipboardFormatName(

__in   UINT format, //要检索的格式ID

__out  LPTSTR lpszFormatName, //存储返回的格式名的缓冲区

__in   int cchMaxCount //拷贝到缓冲区的最大数据长度

);

《Windows核心编程》---剪贴板相关推荐

  1. 内存映射文件——Windows核心编程学习手札之十七

    内存映射文件 --Windows核心编程学习手札之十七 与虚拟内存一样,内存映射文件保留地址空间,并将物理存储器提交给该区域,差别在于所提交的物理存储器是磁盘上有文件存在的空间,而非系统的页文件,一旦 ...

  2. 《windows核心编程系列》二谈谈ANSI和Unicode字符集

    第二章:字符和字符串处理 使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是 ...

  3. 《windows核心编程系列》十八谈谈windows钩子

    windows应用程序是基于消息驱动的.各种应用程序对各种消息作出响应从而实现各种功能. windows钩子是windows消息处理机制的一个监视点,通过安装钩子能够达到监视指定窗体某种类型的消息的功 ...

  4. 《Windows核心编程(第5版•英文版)》暨《深入理解.NET(第2版•英文版)》有奖书评/读书笔记征集活动

    <Windows核心编程(第5版•英文版)>暨<深入理解.NET(第2版•英文版)>有奖书评/读书笔记征集活动 图灵公司自成立以来,得到了CSDN的很多专家和朋友的帮助.为了感 ...

  5. chHANDLE_DLGMSG(windows核心编程)讲解

    看完<Windows程序设计>后开始看<windows核心编程>, 结果看第一个案例的时候就很惊人的发现,Jeffery大牛的代码很深奥.乍一看好像没有包含<window ...

  6. C#学习路线:C#入门经典 -> CLR VIA C# -> WINDOWS核心编程

    C#入门经典:入门阶段 CLR VIA C#:理论基础 WINDOWS核心编程:理论提升

  7. 窗口消息——Windows核心编程学习手札之二十六

    窗口消息 --Windows核心编程学习手札之二十六 Windows允许一个进程至多建立10000个不同类型的用户对象(user object):图符.光标.窗口类.菜单.加速键表等,当一个线程调用一 ...

  8. 未处理异常和C++异常——Windows核心编程学习手札之二十五

    未处理异常和C++异常 --Windows核心编程学习手札之二十五 当一个异常过滤器返回EXCEPTION_CONTINUE_SEARCH标识符时是告诉系统继续上溯调用树,寻找另外的异常过滤器,但当每 ...

  9. 异常处理程序和软件异常——Windows核心编程学习手札之二十四

    异常处理程序和软件异常 --Windows核心编程学习手札之二十四 CPU负责捕捉无效内存访问和用0除一个数值这种错误,并相应引发一个异常作为对错误的反应,CPU引发的异常称为硬件异常(hardwar ...

  10. 结束处理程序——Windows核心编程学习手札之二十三

    结束处理程序 --Windows核心编程学习手札之二十三 使用SEH可以只关注程序要完成任务,而运行中发生的错误,系统将会发现并通知.Windows引入SHE是为了便于操作系统的开发,使用SHE所造成 ...

最新文章

  1. JS 正则表达式 0.001 ~99.999
  2. 设置参数cocos2d-x 2.x 进度条CCProgressTimer
  3. 【javascript】四舍五入
  4. Linux 下关闭防火墙设置
  5. c语言中strcmp作用,C语言中strcmp的实现原型
  6. 编译源码 JAVA out of memory
  7. 如何把Access转成SQL Server的方法介绍
  8. Java多线程系列(六):深入详解Synchronized同步锁的底层实现
  9. 李宏毅机器学习 1.Machine Learning_introduction
  10. java工具类使用逗号切割字符串_【java】分割字符串工具类,霸气 jdk自带的
  11. 【渝粤教育】国家开放大学2018年秋季 2707T种植业基础 参考试题
  12. 向小伙伴讲讲搜索引擎?读完这个文章先
  13. 通话时自动中断音乐播放_您知道用户在何处以及为何中断通话吗?
  14. 算法:回溯解决电话拨号中的字母组合Letter Combinations of a Phone Number
  15. 百度大脑开放日·互联网内容安全线上专场报名中!
  16. 人类赋予人工智能伦理,生物进化方向的突破是关键【南科大发言】
  17. 云漫圈 | 什么是DNS?什么是DNS污染?什么又是DNS劫持?
  18. 支付宝转账到个人账户
  19. hive执行报错:Both left and right aliases encountered in JOIN
  20. html上中下布局关键字,HTML中关键字SEO优化布局位置

热门文章

  1. C#/WPF程序开机自动启动
  2. ajax跨域问题(php)
  3. 代码习惯---打印参数
  4. [HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)
  5. Finished yeah!
  6. echarts tooltip在图表范围内显示
  7. history.back(-1)和history.go(-1)的区别
  8. 【转】几张图看懂列式存储
  9. 【小记】-005--纯CSS实现的小玩意儿
  10. Spring 基于Java的Bean声明