第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"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""
"
""
END
3 TEXTINCLUDE
BEGIN
"
"
""
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

//

原文地址:https://www.cnblogs.com/5iedu/p/4695129.html