`
java-mans
  • 浏览: 11413756 次
文章分类
社区版块
存档分类
最新评论

《Windows核心编程》---剪贴板

 
阅读更多

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

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

涉及到的API有:OpenClipboardEmptyClipboardSetClipboardDataGetClipboardDataCloseClipboard等。

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_DRAWCLIPBOARDWM_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.API-函数、接口、编程实例.pdf

    2.3 Windows API核心DLL 21 2.3.1 Kernel32.dll 21 2.3.2 User32.dll 21 2.3.3 Gdi32.dll 22 2.3.4 标准C函数 22 2.3.5 其他Dll 22 2.4 Unicode和多字节 22 2.4.1 W版本和A版本的API 24 2.4.2 ...

    Windows应用程序捆绑核心编程光盘代码

    3.7 使用Windows剪贴板通信 67 3.7.1 使用剪贴板实现进程间通信的方法 68 3.7.2 使用剪贴板实现进程间通信的实例 68 3.8 使用动态数据交换(DDE)通信 70 3.8.1 使用DDE技术通信原理 70 3.8.2 如何使用DDEML...

    Windows 程序设计(第5版)(上、下册)--详细书签版

    在《Window程序设计》(第5版)中,这位杰出的“Windows先锋奖”(Windows Pioneer Award)获得者根据最新的Windows操作系统权威技术修订了他的经典著作——再一次演示了基本的Win32程序设计的API核心内容。...

    精通WindowsAPI 函数 接口 编程实例

    2.3 Windows API核心DLL 21 2.3.1 Kernel32.dll 21 2.3.2 User32.dll 21 2.3.3 Gdi32.dll 22 2.3.4 标准C函数 22 2.3.5 其他Dll 22 2.4 Unicode和多字节 22 2.4.1 W版本和A版本的API 24 2.4.2 ...

    DELPHI 5编程实例与技巧

    本书共分三部分、16章,主要介绍Delphi 5集成开发环境,对象Pascal语言、组件、通用编程技术、动态链接库、多线程、多媒体编程、数据库编程、网络编程和Windows API编程等。 目 录 前言 第一部分 Delphi编程基础 ...

    一款创新的桌面应用程序,在任何场景下快速利用 ChatGPT 的强大功能,包括专业术语查询、语言翻译、编程帮助,.exe直接运行

    快速生成内容:通过 GPT 模型,快速生成与剪贴板文本相关的内容。 多模式选择:学术GPT、翻译GPT 和代码GPT,多种模式应对不同需求。 系统托盘集成:简洁的系统托盘集成,便于访问和控制。 一键快捷操作:通过 Ctrl+...

    Tcl_TK编程权威指南pdf

    第35章 选择和剪贴板 选择模型 selection命令 clipboard命令 选择处理程序 第36章 焦点、焦点的捕获和对话框 标准对话框 定制对话框 使用update命令实现动画 第37章 tk组件的属性 配置属性 尺寸 边界与...

    vc++ 开发实例源码包

    《远程控制编程技术》源代码 内含(重启、图片操作、ip操作、键盘与鼠标、客户端以及服务端、文件传输等实例源码) 多个VC++加密解密算法库(CRYPT++) 详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法...

    Delphi 5编程实例与技巧

    第二部分 Delphi编程的核心技能 第3章 窗体和组件 53 3.1 窗体和组件 53 3.1.1 窗体 54 3.1.2 组件 56 3.1.3 在窗体中使用组件 57 3.2 文本组件 60 3.3 特殊输入组件 61 3.4 按钮及其分类组件 63 3.5 列表组件 64 ...

Global site tag (gtag.js) - Google Analytics