(1)设置多种数据项
OpenClipboard(hwnd); EmptyClipboard();
//下面设置多种数据项,但这3种数据项必须不同,且在Empty和CloseClipboard间设置。 //将文本字符串写到位图或图元文件中,这样字符串即可被文读文本的程序访问。也可 //被读位图的程序访问,但这些程序没办法轻易判断出位图中其实还含有字符串。
SetClipboardData(CF_TEXT,hGlobalText); //每次,每个数据项只能是一种格式。 SetClipboardData(CF_BITMAP,hBitmap); //如文本,不能同时设CF_TEXT SetClipboardData(CF_METAFILEPICT,hGlobalMFP);//和CF_UNICODETEXT等格式 CloseClipboard();
(2)取出这些数据项
hGlobalText= GetClipboardData(CF_TEXT); hBitmap = GetClipboardData(CF_BITMAP); hGlobalMFP = GetClipboardData(CF_METAFILEPICT);
(3)判断剪贴板里有几种存储的数据格式——EnumClipboardFormats(iFormat);
①函数枚举当前剪贴板中可用的数据格式
②iFormat指己知的数据格式,当设为0时,会自动获取第一个可用的数据格式。
③剪贴板的数据格式被存储在一个有序的链表里,每次调用该函数,会返回下一种格式。当返回值为0时,枚举结束。
iFormat =0; OpenClipboard(hwnd); While (iFormat =EnumClipboardFormats(iFormat)) { //针对每个iFormat数据格式的操作 } CloseClipboard();
(4)获取当前剪贴板不同格式的数目:iCount = CountClipboardFormats();
12.2.2 延迟提交技术
(1)复制数据端的程序——放完数据后,hwnd成为把数据放到剪贴板里的最后一个窗口,即剪贴板的最后Owner为hwnd。
OpenClipboard(hwnd); //Windows先把新的窗口句柄(hwnd)保存下来,但并不立即变 //更剪贴者拥有者,要调用EmptyClipboard后才变更。 EmptyClipboard(); //调用该函数时,Windows将剪贴板拥有者设为hwnd,并向旧拥有者发送一条WM_DESTROYCLIPBOARD消息 //以告知旧拥有者,剪贴板的内容己被我清空,而且我也正式接管理剪贴板的拥有权,而你失去拥有权了 //(呵呵,多有礼貌呀!) SetClipboardData(iFormat,NULL); //设为NULL,以延迟提交数据句柄。会一直等到有程序对剪贴板中的数据进行请求时,该程序 //(也就是剪贴板的拥有者)才会按指定数据格式将数据复制到剪贴板中,这就是“延迟提交 //技术”。 CloseClipboard()
(2)粘贴数据端的程序
①GetClipboardData时:先检查指定数据格式的句柄是否为NULL,如果是,则向剪贴板拥有者(hwnd)发送WM_RENDERFORMAT消息,请求得到实际的句柄。
复制数据端的程序开始处理请求:
case WM_RENDERFORMAT: //wParam:要请求传送的数据格式
[根据wParam的数据格式(iFormat),产生全局内存块];
SetClipboardData(iFormat,hGlobal);
★注意
A、处理该消息的过程无须打开、清空和关闭剪贴板,也不能那样做,因为剪贴板己被粘贴数据端的程序打开,这时复制端的程序无法进行打开、清空和关闭等操作。
B、此时剪贴板虽然被粘贴端的程序打开,但其拥有者仍是复制数据端程序。(∵粘贴端的程序还没有调用EmptyClipboard函数,一旦调用该函数后,会导致剪贴板拥有者发生变更,从而这里收不到该消息,所有剪贴板拥有者仍然为复制端程序。另外,此处Windows好象为SetClipboardData开了个后门,如果是数据句柄为NULL的数据项,可以在不打开剪贴板的前提下修改剪贴板的数据!这是我的猜测而己哦!)
②粘贴端调用EmptyClipboard后:Windows会向复制端程序发送WM_DESTROYCLIPBOARD消息,告知剪贴板数据信息被清空了,同时告知拥有者也变更了。一般不需要处理该消息。
③如果延迟提交剪贴板拥有者进程将要终止,并且此时剪贴板仍然拥有为NULL的数据句柄,则系统将会为其发送一条WM_RENDERALLFORMATS消息,通知将所有为NULL的数据项拷贝到剪贴板。(课本的处理是将所有数据项重新设置到剪贴板)
case WM_RENDERALLFORMATS: //这里只需重新设置所有数据句柄为NULL的数据项,这情况可以不打开剪贴板。而课本的是处理 //所有的数据项(含不为NULL的),因为要设置不为NULL的数据项,就必须打开剪贴板。 OpenClipboard(hwnd); EmptyClipboard(); //清空剪贴板,设置hwnd为剪贴板新的拥有者。 //调用后会发送WM_DESTROYCLIPBOARD消息 //设置所有的数据项(因为剪贴板己被Empty了) SetClipboard(CF_TEXT,hGlobalText); //之前不为NULL的数据项 [根据iFormat,产生全局内存块]; SetClipboardData(iFormat,hGlobal); //之前为句柄为NULL的数据项 CloseClipboard();
12.2.3 私有数据类型——3种方法
(1)使用伪标准格式(CF_DSPTEXT、CF_DSPBITMAP等)——为使用DSP数据格式,必须确保进程本身与剪贴板拥有者进程同属一个程序。指定为这种格式时,剪贴板的这部分数据就被设成是私有的,只能通过CF_DSPXXX格式并且剪贴板的拥有者是同一程序(或不同实例间)才能被访问。
①设置数据:SetClipboardData(CF_DSPXXX,hGlobal);
②取出数据:
A、获取剪贴板拥有者:hwndClipOwner = GetClipboardOwner();
B、取得该拥有者的窗口类名称:GetClassName(hwndClipOwner,szClassName,32);
C、如果类名与我们的程序名一样,就可以使用带有DSP前缀的剪贴板数据格式了。
(2)使用CF_OWNERDISPLAY格式
①使该格式查看(粘贴)数据时,查看器程序要把自己的DC句柄交给剪贴板的拥有者,让它来帮忙绘制。(注意,完成绘图的是拥有者,即复制端程序而不是粘贴端)
②因为要显示时,才完成绘制,所以要采用“延迟提交技术”,即SetClipboardData(CF_OWNERDISPLAY,NULL);//NULL,指明了延迟提交数据句柄给剪贴板。
③剪贴板拥有者除了处理Windows发送的延迟提交消息外,一般还要处理发送查看器发送的5个消息。(注意这5个消息不是Windows自动发送的,要根据需要自己手动发送。)
消息 |
含义 |
WM_ASKCBFORMATNAME |
获取得到数据格式的名称。 lParam为这个名称的缓冲区。剪贴板拥有者必须把这个名称复制到这个缓冲区 wParam为缓冲区能容纳的最大字符的数量。 |
WM_SIZECLIPBOARD |
剪贴板查看器客户区大小改变时发送这消息。 wParam为剪贴板查看器的句柄。 lParam为客户区新的大小。 |
WM_PAINTCLIPBOARD |
要求剪贴板所有者帮忙更新剪贴板查看器客户区内容。 wParam:为剪贴板查看器的窗口句柄。 lParam:指向PAINTSTRUCT结构的全局句柄。剪贴板拥有者可以锁定此句柄,从中得到hdc,并进行绘制 |
WM_HSCROLLCLIPBOARD WM_VSCROLLCLIPBOARD |
剪贴板查看器移动了滚动条。 wParam指向剪贴板查看器的窗口句柄。 LOWORD(lParam):通知码 HIWORD(lParam):滑块的位置(当通知码是SB_THUMBPOSITION时) |
(3)自定义的数据格式——不必像CF_OWNERDISPLAY那么费劲又允许其他程序从剪贴板里复制数据(只要知道了数据的格式就可以正确显示出来)。
①注册自定义的格式:iFormat = RegisterClipboardFormat(szFormatName);//iFormat要介于0xC000~0xFFFF之间。这种格式也可以被EnumClipboardFormats枚举出来。要获取该名称,可以调用:GetClipboardFormatName(iFormat,psBuffer,iMaxCount)取得。
②注册完就可以像CF_TEXT一样的使用这种格式了。
//自定义要传送的结构体 Struct MyFormatData { long val1; int val2; } //注册自定义数据格式 UINT iFormat = RegisterClipboardFormat(“MY_CUSTOM_FORMAT”); //复制到剪贴板 if(OpenClipboard(hwnd)) { MyFormatData data; data.var1 = 100; data.var2 =200; HGLOBAL hGlobal; EmptyClipboard(); hGlobal = GlobalAlloc(GHND |GMEM_SHARE, sizeof(MyFormatData)); MyFormatData * pGlobal = (MyFormatData*)GlobalLock(hGlobal); *pGlobal = data; //保存数据 GlobakUnlock(hGlobal); SetClipboardData(iFormat,hGlobal); CloseClipboard(); } //从剪贴板中获取数据,读取数据使用以下代码: UINT iFormat = RegisterClipboardFormat("MY_CUSTOM_FORMAT"); // MyFormatData data;
if(OpenClipboard(hwnd)) { HANDLE hGlobal =GetClipboardData(iFormat); MyFormatData * pGlobal = (MyFormatData*)GlobalLock(hGlobal); data = * pGlobal; GlobalUnlock(hGlobal); CloseClipboard(); }
【ClipCustomFormat程序】
效果图
/*------------------------------------------------------------
ClipCustomFormat.C -- The Clipboard and Text (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" TCHAR szAppName[] = TEXT("ClipCustomFormat"); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { TCHAR szCaption[] = TEXT("Clipboard Custom Format Transfers"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name szCaption, // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } typedef struct _tag_MyFormatData MyFormatData; struct _tag_MyFormatData { long var1; int var2; }; LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int nSize = 64; TCHAR szBuffer[64]; HDC hdc; static PAINTSTRUCT ps; LPPAINTSTRUCT lpps; RECT rect; static PTSTR pText; PTSTR pOwnerText; HGLOBAL hGlobal; PTSTR pGlobal; HWND hwndClipOwner; static UINT iFormat; static TCHAR szFormatName[] = TEXT("MY_CUSTOM_FORMAT"); static MyFormatData data; switch (message) { case WM_CREATE: data.var1 = 100; data.var2 = 200; iFormat = RegisterClipboardFormat(szFormatName); //注册自定义的数据格式。 return 0; case WM_INITMENUPOPUP: break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_W_PASTE: //伪标准数据格式 hwndClipOwner = GetClipboardOwner(); GetClassName(hwnd, szBuffer, nSize); if (lstrcmp(szBuffer, szAppName) == 0) { OpenClipboard(hwnd); hGlobal = GetClipboardData(CF_DSPTEXT); if (hGlobal != NULL) { pGlobal = GlobalLock(hGlobal); //锁定内存块,获取指针 if (pText) { free(pText); pText = NULL; } wsprintf(szBuffer, TEXT("Data From CF_DSPEXT!")); pText = malloc((lstrlen(szBuffer) + 1)*sizeof(TCHAR)); lstrcpy(pText, szBuffer); GlobalUnlock(hGlobal); InvalidateRect(hwnd, NULL, TRUE); } CloseClipboard(); } return 0; case IDM_W_COPY: //伪标准数据格式 if (!pText) free(pText); pText = malloc((nSize + 1)*sizeof(TCHAR)); lstrcpy(pText, TEXT("Data From CF_DSPTEXT!")); //分配内存并拷贝数据到全局内存块里 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, (lstrlen(pText) + 1)*sizeof(TCHAR)); pGlobal = GlobalLock(hGlobal); lstrcpy(pGlobal, pText); GlobalUnlock(hGlobal); //将内存块传入剪贴板 OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_DSPTEXT, hGlobal); CloseClipboard(); return 0; case IDM_C_COPY: //自定义的数据格式 //分配内存并拷贝数据到全局内存块里 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(MyFormatData)); pGlobal = GlobalLock(hGlobal); *((MyFormatData*)pGlobal) = data; GlobalUnlock(hGlobal); //将内存块传入剪贴板 OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(iFormat, hGlobal); CloseClipboard(); return 0; case IDM_C_PASTE: //自定义的数据格式 OpenClipboard(hwnd); hGlobal = GetClipboardData(iFormat); if (hGlobal != NULL) { pGlobal = GlobalLock(hGlobal); //锁定内存块,获取指针 if (pText) { free(pText); pText = NULL; } data = *((MyFormatData*)pGlobal); wsprintf(szBuffer, TEXT("Data From MyFormatData var1 =%d,var2=%d"), data.var1, data.var2); pText = malloc((lstrlen(szBuffer) + 1)*sizeof(TCHAR)); lstrcpy(pText, szBuffer); GlobalUnlock(hGlobal); InvalidateRect(hwnd, NULL, TRUE); } return 0; case IDM_O_PASTE: //OwnerDisplay数据,注意这里不GetClipboardData,而是将hdc交给剪贴板拥有者去帮忙绘图。 hwndClipOwner = GetClipboardOwner(); hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(PAINTSTRUCT)); lpps = (LPPAINTSTRUCT)GlobalLock(hGlobal); memcpy(lpps, &ps, sizeof(PAINTSTRUCT)); GlobalUnlock(hGlobal); SendMessage(hwndClipOwner, WM_PAINTCLIPBOARD, (WPARAM)hwnd, (LPARAM)hGlobal); GlobalFree(hGlobal); return 0; case IDM_O_COPY: //OwnerDisplay数据 OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_OWNERDISPLAY, NULL); //OwnerDisplay;NULL——延迟提交 CloseClipboard(); return 0; } break; //处理延迟提交 case WM_RENDERALLFORMATS: OpenClipboard(hwnd); EmptyClipboard(); case WM_RENDERFORMAT: //分配内存并拷贝数据到全局内存块里 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(MyFormatData)); pGlobal = GlobalLock(hGlobal); *((MyFormatData*)pGlobal) = data; GlobalUnlock(hGlobal); SetClipboardData(CF_OWNERDISPLAY, hGlobal); //这里不需要OpenClipboard! if (message == WM_RENDERALLFORMATS) CloseClipboard(); return 0; //处理OwnerDispay的消息 //在剪贴板查看器的WM_PAINT消息中,一般要手动发送WM_PAINTCLIPBOARD消息。 case WM_PAINTCLIPBOARD: //wParam为查看器窗口句柄,lParam为PAINTSTRUCT结构 OpenClipboard(hwnd); hGlobal = GetClipboardData(CF_OWNERDISPLAY); pGlobal = GlobalLock(hGlobal); data = *((MyFormatData*)pGlobal); wsprintf(szBuffer, TEXT("OwnerDisplay Data From MyFormatData var1 =%d,var2=%d"), data.var1, data.var2); pOwnerText = malloc((lstrlen(szBuffer) + 1)*sizeof(TCHAR)); lstrcpy(pOwnerText, szBuffer); GlobalUnlock(hGlobal); hdc = GetDC((HWND)wParam); TextOut(hdc, 0, 0, pOwnerText, lstrlen(pOwnerText)); ReleaseDC((HWND)wParam, hdc); CloseClipboard(); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); DrawText(hdc, pText, -1, &rect, DT_EXPANDTABS | DT_WORDBREAK); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 ClipCustomFormat.rc 使用 // #define IDM_W_COPY 40001 #define IDM_W_PASTE 40002 #define IDM_O_COPY 40003 #define IDM_O_PASTE 40004 #define IDM_C_COPY 40005 #define IDM_C_PASTE 40006 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40023 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//ClipCustomFormat.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h " END 2 TEXTINCLUDE BEGIN "#include ""winres.h"" " "