iooiau.net

クリップボードの変化の検知を簡単に

クリップボードに新しくデータがコピーされたことを検知するためには、 古くからある仕組みとしてクリップボードチェインという少し面倒なものを利用する必要がありました。

クリップボードチェインを使ってクリップボードの変化を検知するコードは、以下のようになります。


LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hwndNextClip;

    switch (uMsg) {
    case WM_CREATE:
        hwndNextClip = SetClipboardViewer(hwnd);
        return 0;

    case WM_DRAWCLIPBOARD:
        /* クリップボードの内容が変化した */
        if (hwndNextClip)
            SendMessage(hwndNextClip, uMsg, wParam, lParam);
        return 0;

    case WM_CHANGECBCHAIN:
        if ((HWND)wParam == hwndNextClip)
            hwndNextClip = (HWND)lParam;
        else if (hwndNextClip)
            SendMessage(hwndNextClip, uMsg, wParam, lParam);
        return 0;

    case WM_DESTROY:
        ChangeClipboardChain(hwnd, hwndNextClip);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

チェインの関係を、各アプリケーション側で管理しなければならないのが嫌ですね。

Windows Vista では、Clipboard Format Listener という仕組みが用意され、 クリップボードの変化の検知が簡単に行えるようになりました。
実際のコードは以下のようになります。


LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_CREATE:
        AddClipboardFormatListener(hwnd);
        return 0;

    case WM_CLIPBOARDUPDATE:
        /* クリップボードの内容が変化した */
        return 0;

    case WM_DESTROY:
        RemoveClipboardFormatListener(hwnd);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

AddClipboardFormatListener 関数でウィンドウハンドルを登録すれば、 後はクリップボードの内容が変化する度に WM_CLIPBOARDUPDATE (0x031D) が送られてきます。
最後に RemoveClipboardFormatListener で登録を解除します。

シンプルな仕組みで良いのですが、難点は Vista 以降でしか利用できないことです。
もう XP は忘れましょう…。