《Windows程序设计》读书笔十二 剪贴板

来源:互联网 发布:济宁知豆电动汽车电话 编辑:程序博客网 时间:2024/05/10 02:36

第十二章 剪贴板


12.1 剪贴板的简单用法

12.1.1 剪贴板数据的标准格式

CF_TEXT  一种以NULL结尾的ANSI字符集字符串,字符串的每行结尾有一个回车换行符。

CF_OEMTEXT 包含文本数据(CF_TEXT)但使用OEM字符集的内存块。 在窗口运行MS-DOS程序时如果使用剪贴板需要使用这种类型

CF_UNICODETEXT 包含Unicode文本的内存块。类似于CF_TEXT, 以回车换行结束,字符NULL(两个0字节)标志整个数据结束。

CF_LOCALE  指向区域设置标识符的句柄,表明了与剪贴板相关的区域设置


CF_SYLK  包含微软符号链接格式数据的内存块。用作multiplan, chart Excel程序之间交换数据。 一种ASCII格式,每行以回车换行符结束。

CF_DIF 含有数据交换格式DIF数据的内存块。 


与位图相关的剪贴板格式有三种。即位图对应于输出设备像素的矩形位数组。

CF_BITMAP 设备相关位图。 (程序把位图传给剪贴板之后不应该继续使用此位图)

CF_DIB 定义了设备无关位图的内存块。

CF_PALETTE 指向调色板的句柄。 通常和CF_DIB一起使用,用来定义设备相关位图中使用的调色板。

CF_TIFF 包含标签图像文件格式(Tag Image File Format)数据的内存块。

还有两种图元格式(以二进制形式存储的绘图命令的集合)

CF_METAFILEPICT 基于windows过去支持的图元文件的“图元文件图片”。

CF_ENHMETAFILE 指向32位windows版本支持的增强型图元文件的句柄


CF_PENDATA  和windows画笔一起使用

CF_WAVE 声音波形文件

CF_RIFF  资源交换文件格式(RIFF)的多媒体数据

CF_HDROP 和拖放服务一起使用的文件列表。


12.1.2  内存分配

由于剪贴板中存储的内存块必须在windows下运行的应用程序之间共享,malloc函数不足以完成此任务。


取而代之的是,windows早起设计的内存分配函数,

hGlobal = GlobalAlloc(uiFlags, dwSize);

返回HGLOBAL类型的句柄,称为 指向全局内存块的句柄(handle to a global memory block) "全局句柄"

返回NULL表示没有足够的内存空间可以分配。

uiFlags  0  使用GME_FIXED   函数返回的全局句柄实际是一个指向被分配内存块的指针

   GME_ZEROINIT    把分配的内存块初始化为0.

#define GPTR (GMEM_FIXED | GMEM_ZEROINIT)

内存重分配函数

hGlobal = GlobalReAlloc(hGlobal, dwSize, uiFlags);

取得内存分配大小

dwSize = GlobalSize(hGlobal);

释放内存的函数是

GlobalFree(hGlobal);


#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT)

GMEM_MOVEABLE 使得windows能在虚拟内存中移动内存块。 并不意味内存块绘制物理内存中移动,仅仅是此应用程序用来读写内存块的地址可能会改变。


GMEM_MOVEABLE 仅用16位系统上。

如果应用程序频繁分配,重分配,释放不同大小的内存块,应用程序虚拟机制控件会变得七零八碎。可能会把虚拟内存地址用完。如果是个潜在问题,就需要使用可移动内存。


做法如下

定义一个指针

int * p;

GLOBALHANDLE hGlobal;


分配内存

hGlobal = GlobalAlloc(GHND, 1024);

p = (int *) GlobalLock(hGlobal);  //把全局内存句柄转换为指针, windows会修复内虚拟内存地址。内存块不会移动。

使用完以后调用

GlobalUnlock(hGlobal); 解锁内存块

释放内存 GlobalFree(hGlobal); //参数是全局内存句柄而非指针

如果没有可访问的句柄可以使用

hGlobal = GlobalHandle(p);

使用可移动内存的原因是防止内存碎片,在使用剪贴板时也可以使用可移动内存。

为剪贴板分配内存使用  GlobalAlloc   标志使用  GMEM_MOVEABLE 和  GMEM_SHARE标志作为参数。GMEM_SHARE标志使得内存能被其他应用程序共享


12.1.3 把文本传到剪贴板

hGlobal = GlobalAlloc(GHND | GMEM_SHARE, iLength + 1); //给字符串终止符预留空间

如果分配失败 hGlobal = NULL

如果分配成功,锁定此空间

pGlobal = GlobalLock(hGlobal);

把字符串复制到内存块

for ( i  = 0; i < wLength; i++)

    *pGlobal++ = *pString++;   //不需要加终止符,因为GHND标志初始化时全部填充0

解锁内存

GlobalUnlock(hGlobal);

现在可以传入剪贴板

OpenClipboard(hwnd);

EmptyClipboard(); 清空剪贴板


SetClipboardData(CF_TEXT, hGlobal); // 把全局句柄传入,标志设置为CF_TEXT

CloseClipboard();  完事


注意:

在单个消息过程中调用OpenClipboard 和CloseClipboard. 避免不必要长时间打开剪贴板

不要把锁定的内存传给剪贴板 (应该解锁)

调用SetClipboardData 以后不可再使用该内存块,他已经不再属于程序。 如果需要继续使用,应该在复制一份或者从剪贴板中读取。

在SetClipboardData 和  CloseClipboard之间,可以继续应用该内存块,但是不要使用传给SetClipboardData函数的全局句柄。

你可以使用SetClipboardData返回的句柄,并锁定来修改内存。  在调用CloseClipboard之前解锁这个句柄。



12.1.4  从剪贴板中取得文本

判断是否存在文本

bAvailable = IsClipboardFormatAvailable(CF_TEXT);

若存在返回TRUE


OpenClipboard(hwnd)    打开剪贴板

hGlobal = GetClipboardData(CF_TEXT);  获取全局句柄,如果无CF_TEXT 则返回NULL,并关闭剪贴板 CloseClipboard

pText = (char *)malloc(GlobalSize(hGlobal));   申请内存

pGlobal = GlobalLock(hGlobal);   锁定全局句柄

strcpy(pText, pGlobal); 拷贝数据

或者  while( *pText++ = *pGlobal++)

;

GlobalUnlock(pGlobal);   解锁全局句柄

CloseClipboard 关闭剪贴板


12.1.5 打开和关闭剪贴板

尽可能快的操作剪贴板,不要长时间占用。防止别的程序无法访问


12.1.6 剪贴板和Unicode

windows剪贴板能自动维护各种编码的转换。

但在SetClipboardData 和GetClipboardData的时候尽可能使用符合他版本的文本类型


cliptext 程序

#include <windows.h>     #include "resource.h"  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.      #ifdef UNICODE#define CF_TCHAR CF_UNICODETEXTTCHAR szDefaultText[] = TEXT("Default Text - Unicode Version");TCHAR szCaption[] = TEXT("Clipboard Text Transfers - Unicode Version");#else#define CF_TCHAR CF_TEXTTCHAR szDefaultText[] = TEXT("Default Text - ANSI Version");TCHAR szCaption[] = TEXT("Clipboard Text Transfers - ANSI Version");#endif/* UNICODE */int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){static      TCHAR szAppName[] = TEXT("ClipText");HACCELhAccel;HWND        hwnd;MSG         msg;WNDCLASS    wndClass;       //The window Class        wndClass.style = CS_HREDRAW | CS_VREDRAW;wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.        wndClass.cbClsExtra = 0;wndClass.cbWndExtra = 0;wndClass.hInstance = hInstance;wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);  wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);wndClass.lpszMenuName = szAppName;wndClass.lpszClassName = szAppName;//Register the Window Class to the Windows System.         if (!RegisterClass(&wndClass)){MessageBox(NULL, TEXT("This program require Windows NT!"),szAppName, MB_ICONERROR);return 0;}//This function will generate an WM_CREATE message.        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); //This function will generate a WM_PAINT message.     hAccel = LoadAccelerators(hInstance, szAppName);/* The message loop for this program.if received the WM_QUIT message, the function will return 0.*/while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(hwnd, hAccel, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return msg.wParam;}//define the Window Procedure WndProc        LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){static PTSTRpText;BOOLbEnable;HGLOBALhGlobal;HDC             hdc;PTSTRpGlobal;PAINTSTRUCT     ps;RECTrect;switch (message) //get the message        {case WM_CREATE:SendMessage(hwnd, WM_COMMAND, IDM_EDIT_RESET, 0);return 0;case WM_INITMENUPOPUP:EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE,IsClipboardFormatAvailable(CF_TCHAR) ? MF_ENABLED : MF_GRAYED);bEnable = pText ? MF_ENABLED : MF_GRAYED;EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, bEnable);EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, bEnable);EnableMenuItem((HMENU)wParam, IDM_EDIT_CLEAR, bEnable);case WM_COMMAND:switch (LOWORD(wParam)){case IDM_EDIT_PASTE:OpenClipboard(hwnd);if (hGlobal = GetClipboardData(CF_TCHAR)){pGlobal = (PTSTR)GlobalLock(hGlobal);if (pText){free(pText);pText = NULL;}pText = (PTSTR)malloc(GlobalSize(hGlobal));lstrcpy(pText, pGlobal);InvalidateRect(hwnd, NULL, TRUE);}CloseClipboard();return 0;case IDM_EDIT_CUT:case IDM_EDIT_COPY:if (!pText)return 0;hGlobal = GlobalAlloc(GHND | GMEM_SHARE,(lstrlen(pText) + 1) * sizeof(TCHAR));pGlobal = (PTSTR)GlobalLock(hGlobal);lstrcpy(pGlobal, pText);GlobalUnlock(hGlobal);OpenClipboard(hwnd);EmptyClipboard();SetClipboardData(CF_TCHAR, hGlobal);CloseClipboard();if (LOWORD(wParam) == IDM_EDIT_COPY)return 0;// fall through for IDM_EDIT_CUTcase IDM_EDIT_CLEAR:if (pText){free(pText);pText = NULL;}InvalidateRect(hwnd, NULL, TRUE);return 0;case IDM_EDIT_RESET:if (pText){free(pText);pText = NULL;}pText = (PTSTR)malloc((lstrlen(szDefaultText) + 1) * sizeof(TCHAR));lstrcpy(pText, szDefaultText);InvalidateRect(hwnd, NULL, TRUE);return 0;}break;case WM_PAINT:hdc = BeginPaint(hwnd, &ps);GetClientRect(hwnd, &rect);if (pText != NULL)DrawText(hdc, pText, -1, &rect, DT_EXPANDTABS | DT_WORDBREAK);EndPaint(hwnd, &ps);return 0;case WM_DESTROY:if (pText)free(pText);PostQuitMessage(0);return 0;}return  DefWindowProc(hwnd, message, wParam, lParam);}

cliptext.rc

//Microsoft Developer Studio generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///////////////////////////////////////////////////////////////////////////////// Generated from the TEXTINCLUDE 2 resource.//#include "afxres.h"/////////////////////////////////////////////////////////////////////////////#undef APSTUDIO_READONLY_SYMBOLS/////////////////////////////////////////////////////////////////////////////// English (U.S.) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)#ifdef _WIN32LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US#pragma code_page(1252)#endif //_WIN32#ifdef APSTUDIO_INVOKED///////////////////////////////////////////////////////////////////////////////// TEXTINCLUDE//1 TEXTINCLUDE DISCARDABLE BEGIN    "resource.h\0"END2 TEXTINCLUDE DISCARDABLE BEGIN    "#include ""afxres.h""\r\n"    "\0"END3 TEXTINCLUDE DISCARDABLE BEGIN    "\r\n"    "\0"END#endif    // APSTUDIO_INVOKED///////////////////////////////////////////////////////////////////////////////// Menu//CLIPTEXT MENU DISCARDABLE BEGIN    POPUP "&Edit"    BEGIN        MENUITEM "Cu&t\tCtrl+X",                IDM_EDIT_CUT        MENUITEM "&Copy\tCtrl+C",               IDM_EDIT_COPY        MENUITEM "&Paste\tCtrl+V",              IDM_EDIT_PASTE        MENUITEM "De&lete\tDel",                IDM_EDIT_CLEAR        MENUITEM SEPARATOR        MENUITEM "&Reset",                      IDM_EDIT_RESET    ENDEND///////////////////////////////////////////////////////////////////////////////// Accelerator//CLIPTEXT ACCELERATORS DISCARDABLE BEGIN    "C",            IDM_EDIT_COPY,          VIRTKEY, CONTROL, NOINVERT    "V",            IDM_EDIT_PASTE,         VIRTKEY, CONTROL, NOINVERT    VK_DELETE,      IDM_EDIT_CLEAR,         VIRTKEY, NOINVERT    "X",            IDM_EDIT_CUT,           VIRTKEY, CONTROL, NOINVERTEND#endif    // English (U.S.) resources/////////////////////////////////////////////////////////////////////////////#ifndef APSTUDIO_INVOKED///////////////////////////////////////////////////////////////////////////////// Generated from the TEXTINCLUDE 3 resource.///////////////////////////////////////////////////////////////////////////////#endif    // not APSTUDIO_INVOKED

resource.h

//{{NO_DEPENDENCIES}}// Microsoft Developer Studio generated include file.// Used by ClipText.rc//#define IDM_EDIT_CUT                    40001#define IDM_EDIT_COPY                   40002#define IDM_EDIT_PASTE                  40003#define IDM_EDIT_CLEAR                  40004#define IDM_EDIT_RESET                  40005// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        103#define _APS_NEXT_COMMAND_VALUE         40006#define _APS_NEXT_CONTROL_VALUE         1000#define _APS_NEXT_SYMED_VALUE           101#endif#endif


运行结果


12.2 剪贴板的高级用法

在数据准备好以后想剪贴板传输数据需要4个函数调用

OpenClipboard(hwnd);

EmptyClipboard();

SetClipboardData(iFormat, hGlobal);

CloseClipboard();


要取得这些数据需要

OpenClipboard(hwnd);

hGlobal = GetClipboardData(iFormat);

... 其他操作

CloseClipboard();


12.2.1 使用多种数据项

在EmptyClipboard 和CloseClipboard调用之间 可以多次调用SetClipboardData  并使用不同的剪贴板格式。


OpenClipboard(hwnd);

EmptyClipboard();

SetClipboardData(CF_TEXT, hGlobalText);

SetClipboardData(CF_BITMAP, hBitmap);

SetClipboardData(CF_METAFILEPICT, hGlobalMFP);

CloseClipboard();

当三项都存在剪贴板里时, 调用  IsClipboardFormatAvailable 传入CF_TEXT, CF_BITMAP, CF_METAFILEPICT结果都为TRUE

分别调用

hGlobalText = GetClipboardData(CF_TEXT);

...

获取不同类型的数据

等下次windows调用EmptyClipboard时,Windows会释放着三项。

可以在打开剪贴板以后调用EnumClipboardFormats来判断剪贴板里存储的数据格式。

iFormat = 0;

OpenClipboard(hwnd);


while(iFormat = EnumClipboardFormats(iFormat))

{

    针对每个iFormat值的操作

}

CloseClipboard()


iCount = CountClipboardFormats();  获取剪贴板里不同格式的数目


12.2.2 延迟呈现

对于特别大的数据

OpenClipboard(hwnd);

EmptyClipboard();

SetClipboardData(iFormat, NULL);

CloseClipboard();


其中SetClipboardData可以多次调用

当有程序需要改数据,并且其句柄为NULL时,会像该剪贴板所有者发送一条消息。程序这时候必须给出句柄。

处理3条消息

WM_RENDERFORMAT wParam是windows需要的格式,不用打开与清空剪贴板,只需要按照格式创建一个全局内存块,把数据传给它,并用正确的格式调用

SetClipboardData,最后关闭剪贴板。

WM_RENDERALLFORMATS  如果你的程序终止时仍然是剪贴板所有者,并且之前设置的剪贴板里有NULL 句柄。 将受到此消息。你需要重新打开剪贴板,清空之,把数据放入内存块,然后对每个格式调用SetClipboardData,最后关闭剪贴板。此消息是你最后受到的消息之一。

WM_DESTROYCLIPBOARD  别的程序调用EmptyClipboard时 你的程序会收到此消息


case WM_RENDERALLFORMATS:

OpenClipboard(hwnd);

        EmptyClipboard();

case WM_RENDERFORMAT:

准备全局数据

        SetClipboardData(CF_TEXT, hGlobal);

        if(message == WM_RENDERALLFORMATS)

              CloseClipboard();

        return 0;


12.2.3 私有数据类型

CF_DSPTEXT, CF_DSPBITMAP,  CF_DSPMETAFILEPICT    CF_DSPENHMETAFILE   (display)

使用普通的CF_TEXT等的其他应用程序会得不到这些数据。

hwndClipOwner = GetClipboardOwner(); 获得剪贴板所有者句柄

TCHAR szClassName [32];

GetClassName(hwndClipOwner, szClassName, 32);  根据此句柄获得窗口类的名称

如果类名和你程序一样,那么数据是被你程序的另外一个进程放入剪贴板的。


第二种方法, 自定义的一些格式

SetClipboardData(CF_OWNERDISPLAY, NULL);

然后做延迟呈现处理


另外还需要处理5个消息

WM_ASKCBFORMATNAME  询问数据格式的名称

lParam  缓冲区指针

wParam  最大字符


WM_SIZECLIPBOARD  剪贴板查看器客户区的大小改变了

WM_PAINTCLIPBOARD 通知要更新剪贴板查看器的客户区  wParam 剪贴板查看器窗口的句柄,  lParam PAINTSTRUCT结构的全局句柄

WM_HSCROLLCLIPBOARD 通知剪贴板查看器的滚动条被移动

WM_VSCROLLCLIPBOARD 


第三种方法,注册自己的剪贴板格式名。运行在剪贴板查看器里显示数据

iFormat = RegisterClipboardFormat(szFormatName);   (0xC000 ~0xFFFF)

获得此格式的ASCII名称

GetClipboardFormatName(iFormat, psBuffer, iMaxCount);


12.3 实现一个剪贴板查看器

能货值剪贴板内容的改变,称为 剪贴板查看器。

12.3.1 剪贴板查看器链

12.3.2 剪贴板查看器函数和消息

SetClipboardViewer 程序就能称为剪贴板查看器链的一部分。如果主要是作为剪贴板查看器,在处理WM_CREATE消息时调用此函数。返回下一个剪贴板查看器的窗口句柄。

static HWND  hwndNextViewer;


case WM_CREATE:

    ...

   hwndNextViewer = SetClipboardViewer(hwnd);

一旦称为剪贴板查看器会收到  WM_DRAWCLIPBOARD消息。并且调用SendMessage把此消息传递给下一个剪贴板查看器。此链的最后一个程序会收到NULL的hwndNextViewer

WM_PAINTCLIPBOARD是剪贴板发给使用CF_OWNDISPLAY剪贴板格式的程序。

WM_DRAWCLIPBOARD是windows发送给剪贴板查看器的


case WM_DRAWCLIPBOARD:

    if(hwndNextViewer)

       SendMessage(hwndNextViewer, message,wParam, lParam);

    InvalidateRct(hwnd, NULL, TRUE);

    return 0;


处理WM_PAINT消息的时候,可以通过普通的OpenClipboard, GetClipboardData   和  CloseClipboard调用读取剪贴板内容。

若要退出剪贴板查看器链,必须调用 ChangeClipboardChain(hwnd, hwndNextViewer);


当收到 WM_CHANGECBCHAIN

wParam  是退出链的窗口句柄

lParam  是要退出的窗口的下一个句柄

若wParam == hwndNextViewer  ,  则把他设置为lParam


如果 wParam不等于hwndNextViewer, 并且hwndNextViewer不为NULL 就把消息发送给下一个剪贴板查看器

case WM_CHANGECBCHAIN:

    if((HWND)wParam == hwndNextViewer)

         hwndNextViewer == (HWND)lParam;


    else if (hwndNextViewer)

        SendMessage(hwndNextViewer, message, wParam, lParam);

    return 0;


在程序终止时退出剪贴板查看器链

case WM_DESTROY:

      ChangeClipboardChain(hwnd, hwndNextViewer);

      PostQuitMessage(0);

      return 0;


12.3.3  一个简单的剪贴板查看器

#include <windows.h>     LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.      int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){static      TCHAR szAppName[] = TEXT("ClipView");HWND        hwnd;MSG         msg;WNDCLASS    wndClass;       //The window Class        wndClass.style = CS_HREDRAW | CS_VREDRAW;wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.        wndClass.cbClsExtra = 0;wndClass.cbWndExtra = 0;wndClass.hInstance = hInstance;wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);wndClass.lpszMenuName = NULL;wndClass.lpszClassName = szAppName;//Register the Window Class to the Windows System.         if (!RegisterClass(&wndClass)){MessageBox(NULL, TEXT("This program require Windows NT!"),szAppName, MB_ICONERROR);return 0;}//This function will generate an WM_CREATE message.        hwnd = CreateWindow(szAppName,      //Window class name        TEXT("Simple Clipboard Viewer (Text Only)"),      //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); //This function will generate a WM_PAINT message.     /* The message loop for this program.if received the WM_QUIT message, the function will return 0.*/while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}//define the Window Procedure WndProc        LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){static HWNDhwndNextViewer;HGLOBALhGlobal;HDC             hdc;PTSTRpGlobal;PAINTSTRUCT     ps;RECTrect;switch (message) //get the message        {case WM_CREATE:hwndNextViewer = SetClipboardViewer(hwnd);return 0;case WM_CHANGECBCHAIN:if ((HWND)wParam == hwndNextViewer)hwndNextViewer = (HWND)lParam;else if (hwndNextViewer)SendMessage(hwndNextViewer, message, wParam, lParam);return 0;case WM_DRAWCLIPBOARD:if (hwndNextViewer)SendMessage(hwndNextViewer, message, wParam, lParam);InvalidateRect(hwnd, NULL, TRUE);return 0;case WM_PAINT:hdc = BeginPaint(hwnd, &ps);GetClientRect(hwnd, &rect);OpenClipboard(hwnd);#ifdef UNICODEhGlobal = GetClipboardData(CF_UNICODETEXT);#elsehGlobal = GetClipboardData(CF_TEXT);#endifif (hGlobal != NULL){pGlobal = (PTSTR)GlobalLock(hGlobal);DrawText(hdc, pGlobal, -1, &rect, DT_EXPANDTABS);GlobalUnlock(hGlobal);}CloseClipboard();EndPaint(hwnd, &ps);return 0;case WM_DESTROY:ChangeClipboardChain(hwnd, hwndNextViewer);PostQuitMessage(0);return 0;}return  DefWindowProc(hwnd, message, wParam, lParam);}
运行结果


可以查看文本格式的剪贴板查看器

如果要支持其他数据格式的剪贴板查看器需要调用 EnumClipboardFormats  获得格式名,还可以调用GetClipboardFormatName 获得非标准格式名

使用CF_OWNERDISPLAY格式的剪贴板查看器需要向剪贴板所有者发送一下消息才能显示数据

WM_PAINTCLIPBOARD

WM_SIZECLIPBOARD

WM_VSCROLLCLIPBOARD

WM_HSCROLLCLIPBOARD

使用GetClipboardOwner获得剪贴板所有者窗口句柄,然后想起发送以上这些消息。

0 0
原创粉丝点击