ディレイドレンダリング
遅延レンタリング
ユーザーによっては、クリップボードに転送したデータをすぐに使うとは限りません
そうした場合、別のデータが転送されるかペーストされるまで
クリップボードにあるデータは無意味な状態にあると考えられます
一般に、テキストでータであればこの程度のことは問題ありません
しかし、WAVA 音声ファイルやビットマップなどの場合はそうはいきません
クリップボードに大量のデータを格納すると、それだけメモリを使用することになります
そこで、クリップボードに要求が発生した時にデータを転送する方法が考えられます
このような技術を ディレイドレンダリング(delayed rendering)と呼びます
「遅延提出」という意味が示す様に、即座にクリップボードにデータを置くのではなく
GetClipboardData() が呼び出された時に、データを転送するというものです
これには、まず最初にクリップボードに対して SetClipboardData() の
第二引数でグローバルハンドルではなく NULL を渡します
この場合、アプリケーションに WM_RENDERFORMAT と
WM_RENDERALLFORMATS メッセージを処理する義務が生まれます
WM_RENDERFORMAT は GetClipboardData() が呼び出された時
Windows はクリップボードのオーナーウィンドウプロシージャにこれを送ります
WPARAM に要求されたクリップボードデータ形式が格納されています
LPARAM は無く、このメッセージを処理した場合 0 を返さなければいけません
WM_RENDERALLFORMATS は、クリップボードを所有するプログラムが終了しようとし
クリップボードにプログラムが設定した NULL ハンドルが残っている場合に送られます
パラメータはありません、処理した場合は 0 を返します
このメッセージが送られた場合は、アプリケーションが終了するということなので
クリップボードを開き、内容を EmptyClipboard() で初期化し
NULL ハンドルを持つデータ型を有効なグローバルハンドルに設定しなおします
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
HGLOBAL hg;
PTSTR strText;
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_RENDERALLFORMATS:
OpenClipboard(hwnd);
EmptyClipboard();
case WM_RENDERFORMAT:
hg = GlobalAlloc(GHND | GMEM_SHARE , 1024);
strText = GlobalLock(hg);
lstrcpy(strText , TEXT("Kitty on your lap"));
GlobalUnlock(hg);
SetClipboardData(CF_TEXT , hg);
if (msg == WM_RENDERALLFORMATS)
CloseClipboard();
return 0;
case WM_CREATE:
if (!OpenClipboard(hwnd)) return 0;
EmptyClipboard();
SetClipboardData(CF_TEXT , NULL);
CloseClipboard();
return 0;
}
return DefWindowProc(hwnd , msg , wp , lp);
}
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
PSTR lpCmdLine , int nCmdShow ) {
HWND hwnd;
HACCEL haccel;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = 0;
winc.cbWndExtra = DLGWINDOWEXTRA;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
winc.hCursor = LoadCursor(NULL , IDC_ARROW);
winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winc.lpszMenuName = NULL;
winc.lpszClassName = TEXT("KITTY");
if (!RegisterClass(&winc)) return -1;
hwnd = CreateWindow(
TEXT("KITTY") , TEXT("Kitty on your lap") ,
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL , hInstance , NULL
);
if (hwnd == NULL) return -1;
while(GetMessage(&msg , NULL , 0 , 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
このプログラムを実行したとき、クリップボードに NULL のハンドルをセットします
実際にクリップボードにデータが転送されるのは
何らかのプログラムが GetClipboardData() を呼び出すか、アプリケーションを終了した時です
このような処理をする時、他のプログラムがクリップボードを開く可能性もあります
他のプログラムがクリップボードのオーナーになる時 EmptyClipboard() を呼びます
この時、現在のオーナーには WM_DESTROYCLIPBOARD が送られます
パラメータは無く、処理した場合は 0 を返します
クリップボードのオーナーでなくなる時、何らかのデータ保存処理が必要な場合は
このメッセージを処理して、これに備えることも可能です