第12章 剪貼板_12.2 剪貼板的高級用法


12.2.1 使用多種數據項

(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

 

//


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM