1

我知道,这种方法已经过时了,只是好奇。当我从 atexit 处理程序调用 ChangeClipboardChain() 时,它成功了。当 precc Ctrl-C 时,它会失败。我知道,因为其他剪贴板查看器不会收到 WM_CHANGECBCHAIN。

此示例程序在将某些内容复制到剪贴板 4 次时退出:

#ifndef _WIN32_WINNT        // Allow use of features specific to Windows XP or later.                   
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif                      

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

static void pWin32Error(const char* fmt, ...);

static int counter=0;

static HWND nextWnd = NULL;

static
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    switch (uMsg) {
        case WM_CHANGECBCHAIN:
            {
                HWND wndRemove = (HWND)wParam;
                HWND wndNextNext = (HWND)lParam;
                printf("WM_CHANGECBCHAIN %p %p\n", (void*)wndRemove, (void*)wndNextNext);
                if (nextWnd == wndRemove) {
                    printf("saving next window %p\n", (void*)wndNextNext);
                    nextWnd = wndNextNext;
                } else if (nextWnd) {
                    printf("notifying next window %p\n", (void*)nextWnd);
                    return SendMessage(nextWnd,uMsg,wParam,lParam);
                } else {
                    printf("not notifying next window %p\n", (void*)nextWnd);
                }
            }
            break;
        case WM_DRAWCLIPBOARD:
            counter++;
            if (counter > 4) exit(0);
            printf("WM_DRAWCLIPBOARD\n");
            if (nextWnd) {
                printf("notifying next window %p\n", (void*)nextWnd);
                return SendMessage(nextWnd,uMsg,wParam,lParam);
            } else {
                printf("not notifying next window %p\n", (void*)nextWnd);
            }
            break;
        default:
            return DefWindowProc( hwnd,uMsg,wParam,lParam);
    }
    return 0;
}

static volatile HWND global_hwnd = NULL;

WNDCLASS wndclass = {
    0,/*    UINT        style;*/
    WindowProc,/*    WNDPROC     lpfnWndProc;*/
    0,/*    int         cbClsExtra;*/
    0,/*    int         cbWndExtra;*/
    NULL,/*    HINSTANCE   hInstance;*/
    NULL,/*    HICON       hIcon;*/
    NULL,/*    HCURSOR     hCursor;*/
    NULL,/*    HBRUSH      hbrBackground;*/
    NULL,/*    LPCWSTR     lpszMenuName;*/
    _T("myclipmonitor")/*    LPCWSTR     lpszClassName;*/
};

static void unreg() {
    HWND hwnd;
    hwnd = (HWND)InterlockedExchangePointer(&global_hwnd, NULL); /* ignore the "cast to greater size" warning */
    if (hwnd) {
        printf("Removing self from chain: %p <- %p\n", (void*)hwnd, (void*)nextWnd);
        if (!ChangeClipboardChain(hwnd, nextWnd) && GetLastError() != 0) {
            pWin32Error("ChangeClipboardChain() failed");
        }
    }
}

static void exitproc() {
    fprintf(stderr, "exitproc()\n");
    unreg();
}

static
BOOL WINAPI CtrlHandler( DWORD fdwCtrlType )
{
    fprintf(stderr, "CtrlHandler()\n");
    unreg();

    switch ( fdwCtrlType ) {
        case CTRL_C_EVENT:
            fprintf(stderr, "\n\n Stopping due to Ctrl-C.\n" );
            break;

        case CTRL_CLOSE_EVENT:
            fprintf(stderr, "\n\n Stopping due to closing the window.\n" );
            break;

        case CTRL_BREAK_EVENT:
            fprintf(stderr, "\n\n Stopping due to Ctrl-Break.\n" );
            break;

        // Pass other signals to the next handler - ret = FALSE

        case CTRL_LOGOFF_EVENT:
            fprintf(stderr, "\n\n Stopping due to logoff.\n" );
            break;

        case CTRL_SHUTDOWN_EVENT:
            fprintf(stderr, "\n\n Stopping due to system shutdown.\n" );
            break;

        default:
            fprintf(stderr, "\n\n Stopping due to unknown event.\n" );
    }

    return FALSE;
}

int _tmain(int argc, _TCHAR* argv[])
{
    ATOM classatom;
    HINSTANCE hinst = GetModuleHandle(NULL);
    MSG msg;

    wndclass.hInstance = hinst;
    classatom = RegisterClass(&wndclass);
    if (classatom == 0) {
        pWin32Error("RegisterClass() failed");
        return -1;
    }
    global_hwnd = CreateWindowEx(0, (LPCTSTR)classatom, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
    if (!global_hwnd) {
        pWin32Error("CreateWindowEx() failed");
        return -1;
    }

    printf("hwnd = %p\n", (void*)global_hwnd);
    nextWnd = SetClipboardViewer(global_hwnd);
    if (!nextWnd && GetLastError() != 0) {
        pWin32Error("SetClipboardViewer() failed");
        return -1;
    }
    printf("nextWnd = %p\n", (void*)nextWnd);

    atexit(exitproc);

    if (0 == SetConsoleCtrlHandler( CtrlHandler, TRUE )) {
        pWin32Error("SetConsoleCtrlHandler() failed");
        return -1;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}


static char *cleanstr(char *s)
{
    while(*s) {
        switch((int)*s){
            case 13:
            case 10:
            *s=' ';
            break;
        }
        s++;
    }
    return s;
}

static void __pWin32Error(int level, DWORD eNum, const char* fmt, va_list args)
{
    char emsg[1024];
    char *pend = emsg + sizeof(emsg);
    size_t count = sizeof(emsg);
    unsigned u;

    do {
        u = (unsigned)_vsnprintf(pend - count, count, fmt, args);
        if (u >= count) break;
        count -= u;

        u = (unsigned)_snprintf(pend - count, count, ": ");
        if (u >= count) break;
        count -= u;

        u = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                                            NULL, eNum,
                                                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                                                            pend - count, (DWORD)count, NULL );
        if (u == 0) {
            u = (unsigned)_snprintf(pend - count, count, "0x%08x (%d)", eNum, eNum);
        }
    } while(0);

    emsg[sizeof(emsg)-1] = '\0';
    pend = cleanstr(emsg);

    if (pend < emsg + sizeof(emsg)-1) {
        pend++;
        *pend = '\0';
    }
    pend[-1] = '\n';
    puts(emsg);
}

static void pWin32Error(const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    __pWin32Error(0, GetLastError(), fmt, args);
    va_end(args);
}
4

0 回答 0