ウィンドウクラスの登録


カスタムウィンドウクラス

前回は、すでに定義されているウィンドウクラスを用いてウィンドウを生成しました
しかし、通常はボタンやラベルだけのウィンドウなど使いません
ここでは、一般的に見られるアプリケーションウィンドウを作成してみましょう

ウィンドウの定義で重要なもう一つの項目がウィンドウクラスでした
ウィンドウクラスは、大まかなウィンドウの汎用的な設定を行います
まず、ウィンドウクラスの登録にはWNDCLASS構造体型変数を用います
typedef struct _WNDCLASS { 
    UINT    style; 
    WNDPROC lpfnWndProc; 
    int     cbClsExtra; 
    int     cbWndExtra; 
    HANDLE  hInstance; 
    HICON   hIcon; 
    HCURSOR hCursor; 
    HBRUSH  hbrBackground; 
    LPCTSTR lpszMenuName; 
    LPCTSTR lpszClassName; 
} WNDCLASS; 
これが WNDCLASS の定義です
私たちはこの型の変数を宣言し、初期化しなければいけないのです

style には、ウィンドウクラスの基本スタイルを表す定数を指定します
この場は、よく使われる CS_HREDRAWCS_VREDRAWを用いましょう
CS_HREDRAW は水平に、CS_VREDRAW は垂直に、ウィンドウサイズが変更されると
ウィンドウの内容を再描画します

WNDPROC 型とは、ウィンドウプロシージャと呼ばれる関数のポインタ型です
lpfnWndProc にウィンドウプロシージャを設定します
ウィンドウプロシージャとは、ウィンドウで発生したイベントを処理する関数なのですが
これに関してはまだ説明していないので、デフォルトの DefWindowProc()を渡します
この関数は、ウィンドウの移動などの基本的な動作をサポートします

LRESULT DefWindowProc(
  HWND hWnd,
  UINT Msg, 
  WPARAM wParam, 
  LPARAM lParam 
);
今は、この関数について知る必要はありません
この関数を呼び出すのはプログラマではなくウィンドウズなのです(後記)
この場では、イベントが発生した時にこの関数を呼び出すように
ウィンドウクラスに、この関数のポインタを渡しているのだということを理解してください

次の二つの引数 cbClsExtra と cbWndExtra は
クラス構造体、ウィンドウ構造体の追加領域をバイト単位で予約するものです
通常はその必要がないので、多くの場合ここは 0 を指定します

hInstance には、インスタンスハンドルを渡します

hIcon には、タスクバーやタイトルバーに表示されるアイコンのビットマップを指定します
HICON 型は、アイコンのハンドルです
アイコンのビットマップを渡すにはLoadIcon()関数を使用します

HICON LoadIcon(HINSTANCE hInstance , LPCTSTR lpIconName);

hInstance には、アイコンのリソースが入っているモジュールのインスタンスを指定しますが
システム定義のアイコンの場合は NULL にします

lpIconName は、アイコンの名前を指定します
第一引数が NULL の場合は、用意されているアイコンの定数を渡します
IDI_APPLICATION が、アプリケーションのアイコンを表します

hCursor は、ウィンドウのクライアントエリア上のマウスカーソルを指定します
HCURSOR 型 とは、カーソルのハンドルです
定義済みのカーソルは LoadCursor() 関数で取得します

HCURSOR LoadCursor(HINSTANCE hInstance , LPCTSTR lpCursorName);

hInstance はカーソルのリソースが入っているモジュールのインスタンスを指定します
アイコン同様に、システム定義のカーソルの場合は NULL を指定します
lpCursorName には、カーソルの名前を指定します
第一引数が NULL であれば、定義されているマウスカーソルの定数を指定します

hbrBackground は、クライアントエリアの背景色を指定します
ここで渡すのは HBRUSH 型の、ブラシのハンドルです
ブラシとは、グラフィックスの概念なので詳しくは後記します

ブラシのハンドルはGetStockObject()関数を使用します
この関数は、定義済みのブラシやフォントのハンドルを取得できます

HGDIOBJ GetStockObject( int fnObject );

fnObject に、取得したいハンドルの定数を指定します
この関数はブラシのほかにも、ペン、パレットといったハンドルも取得できます
グラフィックス関係の説明の時に、さらに詳しく解説します
白いブラシはWHITE_BRUSHを指定します

この関数の戻り値は HBRUSH ではありません
HGDIOBJ 型 は、グラフィック関連のハンドルです
先ほど説明した通り、この関数はペンやフォントのハンドルも返します
要求する型、HBRUSH にキャストすれば問題ありません(しなくても良いです)

lpszMenuName には、クラスメニューを指定しますが
今回のプログラムにメニューはないので、ここは NULL としましょう

最後の lpszClassName は、このウィンドウクラスの名前です
CreateWindow() 関数の第一引数で指定しましたね

これで、WNDCLASS 型変数の初期化ができますね
しかし、この時点ではまだウィンドウクラスは登録されていません
次に、ここで初期化した変数をRegisterClass()関数に渡します
この関数にウィンドウクラスを渡して、はじめて登録されます

ATOM RegisterClass(CONST WNDCLASS *lpwcx);

lpwcx に、WNDCLASS型の変数のポインタを渡します
成功すると登録されたクラスを一意的に識別するアトムというものが返ります
アトムについて、この場では説明しません
ただ、失敗すると 0 が返って来るので、基本的にエラーチェックしましょう
#include<windows.h>

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

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= DefWindowProc;
	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 0;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW ,
			100 , 100 , 200 , 200 , NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return 0;

	ShowWindow(hwnd , SW_SHOW);
	MessageBox(NULL , TEXT("Kitty on your lap") ,
			TEXT("Kitty") , MB_ICONINFORMATION);

	return 0;
}


いかがなものでしょうか
道のりは険しかったですが、それっぽいウィンドウが完成しました
DefWindowProc() のおかげで、ウィンドウの移動や最大化といった
ウィンドウが持つ最低限の動作もサポートされています

このような長いコードや、多くの型や関数を記憶しているプログラマはいません
通常は、こうしたソースを使いまわしているのです(コピー&ペースト)


DefWindowProc()

LRESULT DefWindowProc(HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam);

デフォルトウィンドウプロシージャを呼び出します
デフォルトウィンドウプロシージャは、ウィンドウが持つ基本的なふるまいをサポートします

hWnd - メッセージを受け取ったウィンドウのハンドルを指定します
Msg - メッセージを指定します
wParam - メッセージの追加情報を指定します
lParam - メッセージの追加情報を指定します

戻り値 - メッセージ処理の結果が返ります。意味はメッセージにより異なります

LoadIcon()

HICON LoadIcon(HINSTANCE hInstance , LPCTSTR lpIconName);

インスタンスに関連付けられた実行ファイルからアイコンリソースをロードします

hInstance - ロードするインスタンスを指定します。システム定義の場合は NULL
lpIconName - ロードするアイコンをあらわす文字列を指定します

戻り値 - ロードされたアイコンのハンドルを返します。失敗した時は NULL

定数解説
システム定義のアイコン
IDI_APPLICATION アプリケーションアイコン
IDI_ASTERISK アスタリスクのアイコン (吹き出しの中に i の文字)
IDI_EXCLAMATION 感嘆符のアイコン
IDI_HAND ストップ印のアイコン
IDI_QUESTION 疑問符のアイコン
IDI_WINLOGO Windows ロゴアイコン

LoadCursor()

HCURSOR LoadCursor(HINSTANCE hInstance , LPCTSTR lpCursorName);

hInstance - ロードするインスタンスを指定します。システム定義の場合は NULL
lpIconName - ロードするカーソルをあらわす文字列を指定します

戻り値 - ロードされたカーソルのハンドルを返します。失敗した時は NULL

インスタンスに関連付けられた実行ファイルからカーソルリソースをロードします

定数解説
システム定義のマウスカーソル
IDC_APPSTARTING 標準矢印カーソルおよび小型砂時計カーソル
IDC_ARROW 標準矢印カーソル
IDC_CROSS 十字カーソル
IDC_IBEAM アイビーム (縦線) カーソル
IDC_ICON 現在は使われません
IDC_NO 禁止カーソル
IDC_SIZE 現在は使われません
IDC_SIZEALL 4 方向矢印カーソル
IDC_SIZENESW 斜め左下がりの両方向矢印カーソル
IDC_SIZENS 上下両方向矢印カーソル
IDC_SIZENWSE 斜め右下がりの両方向矢印カーソル
IDC_SIZEWE 左右両方向矢印カーソル
IDC_UPARROW 垂直の矢印カーソル
IDC_WAIT 砂時計カーソル

GetStockObject()

HGDIOBJ GetStockObject( int fnObject );

定義済みのペン、ブラシ、フォント、パレットのいずれかのハンドルを取得します

fnObject - 要求するハンドルの定数を指定します

戻り値 - 成功すると要求したハンドルが、失敗すると NULL が返ります

定数解説
ストックオブジェクト
BLACK_BRUSH 黒のブラシ
DKGRAY_BRUSH 濃い灰色のブラシ
GRAY_BRUSH 灰色のブラシ
HOLLOW_BRUSH 中空のブラシ (NULL_BRUSH と同じ)
LTGRAY_BRUSH 明るい灰色のブラシ
NULL_BRUSH 空のブラシ (HOLLOW_BRUSH と同じ)
WHITE_BRUSH 白のブラシ
BLACK_PEN 黒のペン
NULL_PEN 空のペン
WHITE_PEN 白のペン
ANSI_FIXED_FONT Windows 文字セットの固定幅システムフォント
ANSI_VAR_FONT Windows 文字セットの可変幅システムフォント
DEVICE_DEFAULT_FONT Windows NT のみ : デバイス依存のフォント
DEFAULT_GUI_FONT Windows 95 のみ : ユーザーインターフェイス用のデフォルトフォント
(メニューやダイアログボックスなどで使われる)
OEM_FIXED_FONT OEM 文字セットの固定幅フォント
SYSTEM_FONT システムフォント
デフォルトでメニューやダイアログボックスなどで使われる可変幅フォント
SYSTEM_FIXED_FONT 古い Windows との互換性で残されている
現在は使わない
DEFAULT_PALETTE デフォルトのカラーパレット
(システムパレット内のスタティックカラーで構成されます。)

RegisterClass()

ATOM RegisterClass(CONST WNDCLASS *lpwcx);

ウィンドウクラスを登録します

lpwcx - ウィンドウクラスのポインタを指定します

戻り値 - 成功すると登録されたクラスを一意的に識別するアトムが、失敗すると0が返ります



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