(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\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // CLIPCUSTOMFORMAT MENU BEGIN POPUP "偽標准格式" BEGIN MENUITEM "W_復制", IDM_W_COPY MENUITEM "W_粘貼", IDM_W_PASTE END POPUP "OwnerDisplay格式" BEGIN MENUITEM "O_復制", IDM_O_COPY MENUITEM "O_粘貼", IDM_O_PASTE END POPUP "自定義格式" BEGIN MENUITEM "C_復制", IDM_C_COPY MENUITEM "C_粘貼", IDM_C_PASTE END END #endif // 中文(簡體,中國) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
//
