ディレイドレンダリング


遅延レンタリング

ユーザーによっては、クリップボードに転送したデータをすぐに使うとは限りません
そうした場合、別のデータが転送されるかペーストされるまで
クリップボードにあるデータは無意味な状態にあると考えられます

一般に、テキストでータであればこの程度のことは問題ありません
しかし、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 を返します

クリップボードのオーナーでなくなる時、何らかのデータ保存処理が必要な場合は
このメッセージを処理して、これに備えることも可能です



前のページへ戻る次のページへ