クリップボードに新しくデータがコピーされたことを検知するためには、 古くからある仕組みとしてクリップボードチェインという少し面倒なものを利用する必要がありました。
クリップボードチェインを使ってクリップボードの変化を検知するコードは、以下のようになります。
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 は忘れましょう…。