ウィンドウ情報


インスタンスを得る

これまで、コントロールを作成するときは常に WinMain() 内で処理していました

無論、これでも問題はないのですが
当然、別の関数でコントロールを作成したい場合もあるでしょう

しかし、CreateWindow() 関数の問題はインスタンスハンドルの引数です
これは WinMain() 関数の引数として Windows から渡される値ですが
コールバック関数で CreateWindow() を行いたい場合に問題が発生します

コールバック関数にインスタンスハンドルを渡す方法の一つとしては
グローバル変数として、ウィンドウのハンドルを用意する方法です
が、とくに熟練プログラマであればグローバル変数を使うことは好まないでしょう
そこで、考えられるのが WM_CREATE のパラメータを使う 方法です

WM_CREATE の LPARAM には、CREATESTRUCT 構造体のポインタが格納されています
この構造体の hInstance メンバにインスタンスハンドルが格納されています
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		CreateWindow(
			TEXT("BUTTON") , TEXT("Kitty") ,
			WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
			0 , 0 , 100 , 30 ,
			hwnd , (HMENU)1 , ((LPCREATESTRUCT)(lp))->hInstance , NULL
		);
		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)) DispatchMessage(&msg);
	return msg.wParam;
}
ウィンドウプロシージャの仮引数 lp はそのままでは使えないので
LPCREATESTRUCT 型にキャストして hInstance メンバにアクセスしています

このように行えば、コントロールのハンドルが必要なプログラムでも
コントロールのハンドルを関数のローカル変数として格納できます


ウィンドウ情報を得る

上記した方法では、それでも WM_CREATE メッセージ内でしか処理できません
それ以外のメッセージのときに、コントロールを作りたい場合はどうしましょうか?

このように、他のウィンドウとの関係や情報が重要な場合
とくに、子コントロールなどを使用するプログラムにはウィンドウの細かい情報を
プログラム中に必要とするケースが多くなってくるでしょう

ウィンドウの情報を得るには GetWindowLong() 関数を使います

LONG GetWindowLong(HWND hWnd , int nIndex);

hWnd には、調べたいウィンドウのハンドルを
nIndex には、どの情報を取得したいかを表す定数を指定します
要求したデータが戻り値となり、失敗すれば 0 が返ります

これを利用すれば、アプリケーションのインスタンスハンドルや
ウィンドウのスタイルなどを知ることができます
インスタンスハンドルを得るには GWL_HINSTANCE を使います
その他の定数は、下記するリファレンスを参照してください
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	static HWND button = 0;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_LBUTTONDOWN:
		if(!button)
			button = CreateWindow(
				TEXT("BUTTON") , TEXT("Kitty") ,
				WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
				0 , 0 , 100 , 30 ,
				hwnd , (HMENU)1 ,
				(HINSTANCE)GetWindowLong(hwnd , GWL_HINSTANCE) ,
				NULL
			);
		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)) DispatchMessage(&msg);
	return msg.wParam;
}
ウィンドウのクライアントエリア上で、マウスを左クリックすると
ウィンドウ上にボタンコントロールが生成されるプログラムです

CreateWindow() 関数で GetWindowLong() 関数を使っています
この関数でインスタンスハンドルを返すように指定しているので
戻り値はこのアプリケーションのインスタンスハンドルになります


GetWindowLong

LONG GetWindowLong(HWND hWnd , int nIndex);

ウィンドウの情報を返します

hWnd - 情報を取得したいウィンドウのハンドル
nIndex - 取得したい情報を表す定数

戻り値 - 要求したデータ。失敗したら 0

nIndex は、拡張ウィンドウメモリ以外のデータを取得するときは以下の定数を指定します

定数解説
GWL_EXSTYLE 拡張ウィンドウスタイルを取得します
GWL_STYLE ウィンドウスタイルを取得します
GWL_WNDPROC ウィンドウプロシージャのアドレス
またはウィンドウプロシージャのアドレスを示すハンドルを取得します
GWL_HINSTANCE アプリケーションのインスタンスハンドルを取得します
GWL_HWNDPARENT アプリケーションのインスタンスハンドルを取得します
GWL_ID ウィンドウの ID を取得します
GWL_USERDATA ウィンドウに関連付けられた
アプリケーション定義の 32 ビット値を取得します




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