0

我正在用全局钩子编写 dll。其中一项任务是在有人执行复制操作时查看剪贴板并从中删除所有数据。这是我的窗口回调函数:

string test("my data");

LRESULT CALLBACK WndHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
        case WM_CREATE:
            nextClipboardViewer = SetClipboardViewer(windowHandler);
            MessageBeep(MB_ICONINFORMATION);
            break;
        case WM_CHANGECBCHAIN:
            if((HWND) wParam == nextClipboardViewer) 
                nextClipboardViewer == (HWND) lParam;
            else if(nextClipboardViewer != NULL)
                SendMessage(nextClipboardViewer, msg, wParam, lParam);
            break;
        case WM_DRAWCLIPBOARD:
            if(OpenClipboard(windowHandler)) {
                EmptyClipboard();
                HGLOBAL hClipboardData;
                hClipboardData = GlobalAlloc(GMEM_MOVEABLE, test.size() + 1);
                char * pchData;
                pchData = (char*)GlobalLock(hClipboardData);
                memcpy(pchData, test.c_str(), test.size() + 1);
                GlobalUnlock(hClipboardData);
                SetClipboardData(CF_TEXT, hClipboardData);
                CloseClipboard();
            }
            SendMessage(nextClipboardViewer, msg, wParam, lParam);
            break;
        case WM_DESTROY:
            ChangeClipboardChain(windowHandler, nextClipboardViewer);
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
            break;
    }
    return 0;
}

我只是尝试替换剪贴板中的信息,但此代码不起作用。

更新:现在我使用隐形窗口和 SetClipboardViewer 来监控更改。但是剪贴板中的数据不会改变。

4

1 回答 1

1

我怀疑在处理消息时更改剪贴板的内容是否真的安全WM_DRAWCLIPBOARD- 至少我很惊讶您没有触发无限循环(因为您的调用EmptyClipboard()可能SetClipboardData()会触发另WM_DRAWCLIPBOARD一条消息)。可能系统对此有保护 - 我从来没有试图找出 - 但它仍然感觉不对:)

试试这个版本,它 a) 将剪贴板更新移动到窗口发布给自身的单独消息(将其移动到剪贴板更改通知代码之外)和 b) 使用全局标志来忽略它自己所做的更改。

(注意:我认为您的代码的实际错误是,当您正在处理时WM_CREATEwindowHandler尚未分配。您可能将其设置为CreateWindowEx返回值,但是当WM_CREATE正在处理时CreateWindowEx尚未实际返回。这意味着剪贴板查看器实际上从未正确建立。我已经更改了hwnd用于解决此问题的参考。)

string test("my data");

#define MSG_UPDATECLIPBOARD     (WM_APP + 1)
static bool g_fIgnoreClipboardChange = false;

LRESULT CALLBACK WndHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
        case WM_CREATE:
            nextClipboardViewer = SetClipboardViewer(hwnd);
            MessageBeep(MB_ICONINFORMATION);
            break;
        case WM_CHANGECBCHAIN:
            if((HWND) wParam == nextClipboardViewer) 
                nextClipboardViewer == (HWND) lParam;
            else if(nextClipboardViewer != NULL)
                SendMessage(nextClipboardViewer, msg, wParam, lParam);
            break;
        case WM_DRAWCLIPBOARD:
            if (!g_fIgnoreClipboardChange)
                PostMessage(hwnd, MSG_UPDATECLIPBOARD, 0, 0);
            if(nextClipboardViewer != NULL)
                SendMessage(nextClipboardViewer, msg, wParam, lParam);
            break;
        case MSG_UPDATECLIPBOARD:
            g_fIgnoreClipboardChange = true;
            if(OpenClipboard(hwnd)) {
                HGLOBAL hClipboardData;
                hClipboardData = GlobalAlloc(GMEM_MOVEABLE, test.size() + 1);
                char * pchData;
                pchData = (char*)GlobalLock(hClipboardData);
                memcpy(pchData, test.c_str(), test.size() + 1);
                GlobalUnlock(hClipboardData);
                SetClipboardData(CF_TEXT, hClipboardData);
                CloseClipboard();
            }
            g_fIgnoreClipboardChange = false;
            break;      
        case WM_DESTROY:
            ChangeClipboardChain(hwnd, nextClipboardViewer);
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
            break;
    }
    return 0;
}
于 2013-08-19T19:59:11.913 回答