第12章 剪贴板_12.3 实现一个剪贴板查看器

 12.3.1 剪贴板查看器链

(1)Windows下可运行任意个剪贴板查看器,但只有一个是“当前剪贴板查看器”,Windows只维护这个剪贴板查看器的窗口句柄,并在剪贴板内容改变时,通知它。

(2)当A程序注册为剪贴板查看器时,就成为当前查看器。Windows会把上个当前查看器B的窗口句柄交给A程序来保存。当A收到剪贴板消息时,要发送给查看器链中的下一个程序,即B的窗口过程。

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

(1)将程序加入剪贴板查看器链

 static HWND hwndNextViewer;

 case WM_CREATE:

hwndNextViewer =SetClipboardViewer(hwnd);//hwndNextViewer得保存下来,这是

                                        //剪贴板消息的下一个接收者。

 (2)WM_DRAWCLIPBOARD消息

     ①剪贴板内板改变时,会发送这消息给当前查看器(最新注册的那个)。

     ②剪贴板查看器链中的每个程序都应通用SendMessage把消息传给下一个查看器

(hwndNextViewer),直到hwndNextViewer为NULL。

③不要把WM_DRAWCLIPBOARD与WM_PAINTCLIPBOARD混为一谈

 消息

消息发起者

WM_DRAWCLIPBOARD

Windows自动发送的,通知查看器剪贴板内容发生了变化。

WM_PAINTCLIPBOARD

查看器(即手动发送的),发给使用CF_OWNERDISP格式的程序

④WM_DRAWCLIPBOARD消息的处理

    case WM_DRAWCLIPBOARD:

       if(hwndNextViewer)SendMessage(hwndNextViewer,message,wParam,lParam);

       InvalidateRect(hwnd,NULL,TRUE);

       return 0;

(3)退出剪贴板查看器链:ChangeClipboardChain(hwnd,hwndNextViewer);

  ①当某个程序退出查看器链时,Windows会向当前查看器发送WM_CHANGECBCHAIN消息。

case WM_CHANGECBCHAIN:  //wParam:要退出链的窗口句柄。lParam:它的下个剪贴板查看器
     if((HWND)wParam == hwndNextViewer) //要退出的窗口w是不是我的下个查看器消息接收者?
          hwndNextViewer =(HWND)lParam; //如果是,将A的消息接收者(lParam)转到我的接收者。
     else if(hwndNextViewer)   //如果要退出的不是我的下个接收者,将退出消息转发下去。
        SendMessage(hwndNextViewer,message,wParam,lParam);

     return 0;

  ②程序终止时,必须从查看器链退出中。

   case WM_DESTROY:

        ChangeClipboardChain(hwnd,hwndNextViewer);

        PostQuitMessage(0);

(4)获得第一个剪贴板查看器(即当前查看器)的窗口句柄:hwndViewer= GetClipboardViewer();

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

  ①可实时感知剪贴板内容发生变化(eg.迅雷的下载地址监测)

  ②本程序只监测CF_TEXT的变化。

【ClipView程序】
效果图

/*------------------------------------------------------------
CLIPVIEW.C -- Simple Clipboard Viewer
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("ClipView");
    HWND         hwnd;
    MSG          msg;
    WNDCLASS     wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    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;
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    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);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC         hdc;
    PAINTSTRUCT ps;
    RECT        rect;
    static HWND hwndNextViewer;
    HGLOBAL     hGlobal;
    PTSTR       pGlobal;
    switch (message)
    {
    case WM_CREATE:
        //加入剪贴板查看器链
        hwndNextViewer = SetClipboardViewer(hwnd);
        return 0;
    case WM_CHANGECBCHAIN: //当有程序退出剪贴板查看器链时
        //wParam:要退出查看器链的窗口句柄,lParam:它的下一个消息接收者。
        if ((HWND)wParam == hwndNextViewer) //退出窗口是我的下个消息接收者?
        {
            hwndNextViewer = (HWND)lParam; //如果是,将该窗的下个消息接收者(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 UNICODE
        hGlobal = GetClipboardData(CF_UNICODETEXT);
#else 
        hGlobal = GetClipboardData(CF_TEXT);
#endif
        if (hGlobal != NULL)
        {
            pGlobal = 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);
}
原文地址:https://www.cnblogs.com/5iedu/p/4695148.html