システムパレット


システムパレットを参照する

私たちアプリケーションプログラマが操作するパレットは「論理パレット」でした
この論理パレットをどのように扱おうと、このパレットはメモリ上のパレットでしかないので
ディスプレイに表示されている色に、何の影響を与えることもありません

これを、Windows パレットマネージャーが管理する
ディスプレイのハードウェアパレットを参照するシステムパレット
リアライズすることで、実際に表示されるいろとして使うことができました

システムパレットは、論理的にディスプレイのハードウェアパレットと同じです
これを参照することによって、実際の物理パレットの状態を知ることができるため
例えば、デバッグやシステム管理アプリケーションなどで使うことができます

システムパレットを参照するアプローチはいくつか考えることができますが
最も正攻法なのは GetSystemPaletteEntry() を用いることです
UINT GetSystemPaletteEntries(
	HDC hdc , UINT iStartIndex ,
	UINT nEntries , LPPALETTEENTRY lppe
);
hdc にはデバイスコンテキストのハンドルを指定します
iStartIndex は取得する最初のパレットエントリ番号を
nEntries は iStartIndex から、パレットエントリのデータを何個取得するかを指定します
lppe には、パレットエントリを格納する PALETTEENTRY 構造体へのポインタを指定します
ここに NULL を指定すると、関数はパレットエントリの総数を返します
関数は成功するとパレットエントリの総数を、失敗すると 0 を返します

この関数が正常に動作するためには、デバイスコンテキストがパレットをサポートしている必要があります
これを調べるには GetDeviceCaps() 関数で調べれば良いですね
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	HBRUSH hBrush;
	int count , x = 15 , y = 10;
	static LOGPALETTE * lpPalette;
	HPALETTE hPalette;
	
	switch (msg) {
	case WM_DESTROY:
		free(lpPalette);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hdc = GetDC(hWnd);
		if (GetDeviceCaps(hdc , SIZEPALETTE) != 256) return -1;
		ReleaseDC(hWnd , hdc);

		lpPalette = malloc(sizeof (LOGPALETTE) +
				256 + sizeof (PALETTEENTRY));
		lpPalette->palVersion = 0x0300;
		lpPalette->palNumEntries = 256;
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);
		GetSystemPaletteEntries(hdc , 0 , 256 , lpPalette->palPalEntry);
		hPalette = CreatePalette(lpPalette);
		SelectPalette(hdc , hPalette , FALSE);

		for (count = 0 ; count < 256 ; count++ , x += 15) {
			hBrush = CreateSolidBrush(PALETTEINDEX(count));
			SelectObject(hdc , hBrush);

			Rectangle(hdc , x , y , x + 10 , y + 20);
			if (x > 600) { y += 25; x = 0; }
			SelectObject(hdc , GetStockObject(WHITE_BRUSH));
			DeleteObject(hBrush);
		}
		DeleteObject(hPalette);
		EndPaint(hWnd ,&ps);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style 		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	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;
}


このプログラムは、システムパレットを PALETTEENTRY 構造体に取得し、
それを用いて論理パレットを新たに作成してデバイスコンテキストに設定します
デバイスコンテキストに設定しなくては、パレットインデックスを指定しても正しく動作しないためです
因みに、システムパレットから取得して作った論理パレットなので
システムパレットと同じなのだから、これをリアライズする必要はありません

ピクセルビットの先頭と末尾の10のエントリは、Windows が予約している色です
先頭から、ブラック、ダークレッド、ダークグリーン、ダークイエロー
末尾から、ホワイト、シアン、マゼンタ、ブルー、イエロー…、と正しく並んでいます
この他の部分は、環境とタイミングによって異なりますが
システムが予約しているいろに関しては、どの環境で実行しても同じでしょう

このプログラムでは、システムパレットの色を取得して
その論理パレットをデバイスコンテキストに設定するという方法を用いていますが
単純にシステムパレットを視覚的に確認したい場合は DDB を用いると良いでしょう
8カラービットの DDB が指すピクセルビットは、純粋にシステムパレットのインデックスです


GetSystemPaletteEntry()

UINT GetSystemPaletteEntries(
	HDC hdc , UINT iStartIndex ,
	UINT nEntries , LPPALETTEENTRY lppe
);
指定したデバイスコンテキストに関連付けられている
システムパレットから、指定範囲のパレットエントリを取得します

hdc - デバイスコンテキストのハンドルを指定します
iStartIndex - 取得する最初のパレットエントリ番号を指定します
nEntries - パレットエントリのデータを何個取得するかを指定します
lppe - PALETTEENTRY 構造体へのポインタを指定します
戻り値 - パレットエントリの総数を、失敗すると 0



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