ウィンドウの作成

CreateWindow関数

さて、いよいよウィンドウの作成の説明に入ります。
ウィンドウを作るにはCreateWindow関数を使用します。

HWND CreateWindowW(
 LPCWSTR lpClassName,
 LPCWSTR lpWindowName,
 DWORD dwStyle,
 int X,
 int Y,
 int nWidth,
 int nHeight,
 HWND hWndParent,
 HMENU hMenu,
 HINSTANCE hInstance,
 LPVOID lpParam
);
ウィンドウを作成する。
戻り値は作成したウィンドウのハンドル。
作成に失敗した場合はNULLを返す。

当サイトでは基本的にワイド文字版の関数を使用して説明します。
マルチバイト文字版の関数を使用したい場合は関数名の末尾に「A」を付け、文字列はワイド文字からマルチバイト文字に変更してください。
(例:LPWSTR→LPSTR)

関数名の末尾に「W」も「A」も付けずに使用した場合、ワイド文字版が呼び出されます。
(ただし設定によって変わります。三種類の同名関数も参照のこと)


#include <windows.h>

int APIENTRY wWinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPWSTR lpCmdLine, 
	int nCmdShow)
{
	//ウィンドウ作成
	HWND hWnd = CreateWindow(
		L"STATIC", L"テストアプリ",
		WS_OVERLAPPEDWINDOW,
		100, 100,
		300, 300,
		NULL,
		NULL,
		hInstance,
		NULL
	);

	if (!hWnd)
	{
		//ウィンドウ作成の失敗
		return 0;
	}
	//作成したウィンドウの表示
	ShowWindow(hWnd, nCmdShow);

	MessageBox(NULL, L"ウィンドウアプリのテスト", L"タイトル", MB_OK);

	return 0;
}

このコードを実行すると以下のようなウィンドウが作られます。
同時にメッセージボックスが開き、OKを押下するとプログラムが終了します。
まだウィンドウを「作って表示しただけ」で、操作することはできません。
CreateWindow関数の実行

この関数は引数が多いので、順を追って説明します。

lpClassName

第一引数lpClassNameウィンドウのクラス名を指定します。

ウィンドウクラスとは、ウィンドウの機能を決めるものです。
これは通常は自分で定義したものを使用します。
しかしまだその手順を説明していないので、ここではSTATICという文字列を指定しています。
これはWindowsが最初から用意しているクラス名(システムクラス)のひとつで、「STATIC」は単純な文字列を表示する機能を持つウィンドウです。
ウィンドウ作成の説明のためにとりあえずこのウィンドウクラスを使用します。

lpWindowName

第二引数のlpWindowNameはウィンドウのタイトルバーに表示される文字列です。
第一引数がSTATICの時、ウィンドウ内にも同じ文字列が表示されます。

dwStyle

第三引数dwStyleはウィンドウのスタイルを定数で指定します。
スタイルはウィンドウの見た目のほか、ウィンドウに対して可能な操作に関わります。
WS_OVERLAPPEDWINDOWは一般的なウィンドウアプリのスタイルです。
ここに指定できる定数は後でまとめて説明します。

X、Y、nWidth、nHeight

第四、第五、第六、第七引数は、デスクトップ画面の左上を基点(0, 0)としたウィンドウの位置とサイズの指定です。
Xは横位置、Yは縦位置です。
nWidthは横幅、nHeightは縦幅です。

ウィンドウが子ウィンドウの場合、親ウィンドウの左上が基点となります。

CW_USEDEFAULT

位置とサイズにはCW_USEDEFAULTという定数が使用できます。
位置やサイズに数値を指定すると、指定した通りの位置とサイズでウィンドウが起動します。
これでも構わないのですが、例えば同じアプリを複数同時に起動した場合に同じ位置とサイズにウィンドウが表示されることになり、少し使いづらいことがあります。
CW_USEDEFAULTを指定すると、現在開かれている別のウィンドウを基準にしてWindowsが適当な位置とサイズでウィンドウを生成してくれます。

特にこだわりがない場合はこの定数を指定したほうが良いでしょう。
ただしウィンドウスタイルによってはCW_USEDEFAULTが使用できず、0を指定したものとみなされます。

hWndParent

第八引数hWndParentは親ウィンドウ、またはオーナーウィンドウのウィンドウハンドルを指定します。
NULLを指定すると独立したウィンドウを作成します。

hMenu

第九引数hMenuはウィンドウが持つメニューを指定します。
メニューはあらかじめ作成しておく必要があります。
必要がない場合はNULLを指定します。

子ウィンドウを作成する場合はここに子ウィンドウID(整数値)を指定します。
このIDは親ウィンドウが子ウィンドウを識別するために使用します。

hInstance

第十引数hInstanceはウィンドウのインスタンスハンドルを指定します。
これはWinMain関数の引数で渡されるhInstanceをそのまま指定します。

インスタンスは「実体」という意味で、ハンドルはその(メモリ上の)位置を意味します。
WinMain関数の引数のhInstanceは、プログラム(実行ファイル)をメモリにロードした位置を表します。

インスタンスやハンドルなどの「中身」のデータが具体的にどうなっているかはプログラマは知る必要はありませんし、直接変更してはいけません。
操作する場合は専用の関数が用意されているので、それを使用します。

lpParam

最後のlpParamはウィンドウが作成される時に使用できる任意の値を指定します。
今は使用しないのでNULLを指定します。

戻り値

CreateWindow関数の戻り値は作成したウィンドウのハンドルです。
プログラムはこのウィンドウハンドルでウィンドウを識別します。
ウィンドウ作成に失敗した場合はNULLになります。

ShowWindow関数

CreateWindow関数が成功すればウィンドウが作成されます。
が、そのままではメモリ上に作成されただけであり画面には表示されません。
作成したウィンドウは初期状態では非表示なので、ShowWindow関数で表示する必要があります。

BOOL ShowWindow(
 HWND hWnd,
 int nCmdShow
);
ウィンドウhWndの表示状態をnCmdShowに変更する。
戻り値はウィンドウが表示状態だった場合は0以外を返す。
非表示常態だった場合は0を返す。

hWndには先ほど作成したウィンドウのハンドルを指定します。
nCmdShowは表示状態を表す以下の定数のいずれかを指定します。
ただし、アプリケーションが最初にShowWindow関数を呼び出す場合はWinMain関数の引数nCmdShowをそのまま渡す必要があります。

定数名 説明
SW_HIDE ウィンドウを非表示にし、別のウィンドウをアクティブにする
SW_SHOWNORMAL
SW_NORMAL
ウィンドウをアクティブにし、通常状態で表示
最大化/最小化されている場合はオリジナルサイズに戻す
SW_SHOWMINIMIZED ウィンドウをアクティブにし、最小化
SW_SHOWMAXIMIZED
SW_MAXIMIZE
ウィンドウをアクティブにし、最大化
SW_SHOWNOACTIVATE ウィンドウを通常状態で表示
アクティブにしない
SW_SHOW ウィンドウをアクティブにし、現在の位置とサイズで表示
SW_MINIMIZE 最小化し、次に前面にある別のウィンドウをアクティブにする
SW_SHOWMINNOACTIVE 最小化
ウィンドウをアクティブにしない
SW_SHOWNA ウィンドウを現在の位置とサイズで表示
アクティブにしない
SW_RESTORE ウィンドウをアクティブにし、通常状態で表示
最大化/最小化されている場合はオリジナルサイズに戻す
最小化されたウィンドウを元に戻す場合に使用する
SW_SHOWDEFAULT プログラム起動時の初期状態で表示
SW_FORCEMINIMIZE ウィンドウを強制的に最小化
ウィンドウのスレッドが応答していない場合に、別のスレッドから最小化する場合に使用

dwStyleの定数

CreateWindow関数の引数dwStyleは、ウィンドウのスタイルを指定する定数です。
以下はその定数の一覧です。

定数名 説明
WS_OVERLAPPED
WS_TILED
オーバーラップウィンドウ
(タイトルバーと枠のあるウィンドウ)
WS_POPUP ポップアップウィンドウ
このスタイルはWS_CHILDと併用できない
WS_CHILD
WS_CHILDWINDOW
子ウィンドウ
このスタイルはWS_POPUPと併用できない
WS_MINIMIZE
WS_ICONIC
最小化状態
WS_VISIBLE 表示(可視)状態
WS_DISABLED 無効な状態のウィンドウ
(ユーザー入力を受け付けない)
WS_CLIPSIBLINGS 子ウィンドウの描画時、兄弟ウィンドウが重なっているときに、重なっている箇所を描画しない(クリッピングする)
子ウィンドウがこのスタイルを持たない場合、重なっている兄弟ウィンドウ内への描画が行われる(上書きする)
WS_CLIPCHILDREN 親ウィンドウの描画時に子ウィンドウ領域を描画しない
このスタイルは親ウィンドウを作成する時に使用する
WS_MAXIMIZE 最大化状態
WS_CAPTION タイトルバーのあるウィンドウ
WS_BORDERも同時に指定される
WS_BORDER 境界線を持つウィンドウ
WS_DLGFRAME ダイアログボックスで通常使われる境界線を持つウィンドウ
このスタイルはタイトルバーを持てない
WS_VSCROLL 垂直スクロールバーを持つウィンドウ
WS_HSCROLL 水平スクロールバーを持つウィンドウ
WS_SYSMENU システムメニューを持つウィンドウ
WS_CAPTIONと同時に指定しなければならない
(システムメニュー→ウィンドウ左上のボタン)
WS_THICKFRAME
WS_SIZEBOX
サイズ変更境界線を持つウィンドウ
WS_GROUP コントロールグループの最初のグループを指定する
次にWS_GROUPを持つコントロールが現れるまでに定義されたコントロールがひとつのグループとなる
このスタイルが指定されたコントロールがWS_TABSTOPスタイルを持つことにより、Tabキーで各グループ間のフォーカスを移動できる
クループ内では方向キーでコントロールのフォーカスを移動できる
WS_TABSTOP このスタイルが指定されたコントロールはTabキーによりフォーカスを受け取ることができる
WS_MINIMIZEBOX 最小化ボタンを持つウィンドウ
WS_SYSMENUと同時に指定しなければならない
拡張ウィンドウスタイルのWS_EX_CONTEXTHELPと同時に指定できない
WS_MAXIMIZEBOX 最大化ボタンを持つウィンドウ
WS_SYSMENUと同時に指定しなければならない
拡張ウィンドウスタイルのWS_EX_CONTEXTHELPと同時に指定できない
WS_OVERLAPPEDWINDOW
WS_TILEDWINDOW
WS_OVERLAPPEDWS_CAPTIONWS_SYSMENUWS_THICKFRAMEWS_MINIMIZEBOXWS_MAXIMIZEBOXの組み合わせ
一般的なオーバーラップウィンドウが作成される
WS_POPUPWINDOW WS_POPUPWS_BORDERWS_SYSMENUの組み合わせ
システムメニューを使用する場合はWS_CAPTIONを同時に指定しなければならない

ウィンドウスタイル定数は「WS_○○」の形式です。
数も多く、ところどころ不明な用語もあるかと思いますが、今はあまり気にしなくて良いです。

なお、複数の定数を同時に指定する場合はビット演算のOR演算子を使用します。
(ビットとビット演算参照)


//WS_OVERLAPPEDWINDOWと同等の指定をビット演算子を使用して行う
HWND hWnd = CreateWindow(
	L"STATIC", L"テストアプリ",
	WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
	WS_THICKFRAME | WS_MAXIMIZEBOX,
	CW_USEDEFAULT, CW_USEDEFAULT,
	CW_USEDEFAULT, CW_USEDEFAULT,
	NULL,
	NULL,
	hInstance,
	NULL
);

CreateWindowEx関数

ウィンドウの作成にはCreateWindowExという関数を使用することもできます。
これは第一引数に拡張ウィンドウスタイルが指定できる以外はCreateWindow関数と同じです。

HWND CreateWindowW(
 DWORD dwExStyle,
 LPCWSTR lpClassName,
 LPCWSTR lpWindowName,
 DWORD dwStyle,
 int X,
 int Y,
 int nWidth,
 int nHeight,
 HWND hWndParent,
 HMENU hMenu,
 HINSTANCE hInstance,
 LPVOID lpParam
);
ウィンドウを作成する。
戻り値は作成したウィンドウのハンドル。
作成に失敗した場合はNULLを返す。

CreateWindow関数の第一引数が拡張スタイルの指定になっています。
以降の引数はCreateWindow関数と同じものです。

拡張スタイルは以下の定数(の組み合わせ)が使用できます。

WS_EX_DLGMODALFRAME 二重の境界線を持つウィンドウ
WS_EX_NOPARENTNOTIFY このスタイルを子ウィンドウに指定すると、ウィンドウの作成や破棄時に親ウィンドウにメッセージを送らない
WS_EX_TOPMOST ウィンドウを常に最前面に表示
この状態はSetWindowPos関数で変更できる
WS_EX_ACCEPTFILES ファイルをドラッグ&ドロップ可能なウィンドウ
WS_EX_TRANSPARENT 透過ウィンドウ
WS_EX_MDICHILD MDI子ウィンドウ
MDI=マルチドキュメントインターフェイス
ウィンドウの中に小さなウィンドウを入れ子にしたもの
WS_EX_TOOLWINDOW フローティングツールウィンドウ
タスクバーに表示されない
WS_EX_WINDOWEDGE 盛り上がった境界を持つウィンドウ
WS_EX_CLIENTEDGE くぼんだ境界を持つウィンドウ
WS_EX_CONTEXTHELP タイトルバーに「?」ボタンを表示
これをクリックするとマウスポインタに「?」アイコンが表示され、その状態で子ウィンドウをクリックするとWM_HELPメッセージが子ウィンドウに送られる
WM_HELPメッセージは親ウィンドウに送らなければならない
親ウィンドウはHELP_WM_HELPメッセージを用いてWinHelpを呼び出さなければならない
このスタイルはWS_MAXIMIZEBOXWS_MINIMIZEBOXと同時に指定できない
WS_EX_RIGHT 右から左へ読む言語(ヘブライ語やアラビア語など)のために、右揃えで表示する
日本語などの環境ではこのスタイルは無視される
WS_EX_LEFT 左揃えで表示
このスタイルは既定(指定しなくても標準で設定されている)
WS_EX_RTLREADING 右から左へ読む言語のために、テキストを右から左に表示する
日本語などの環境ではこのスタイルは無視される
WS_EX_LTRREADING 左から右へテキストを表示
このスタイルは既定
WS_EX_LEFTSCROLLBAR 右から左へ読む言語のために、垂直スクロールバーを左端に表示する
日本語などの環境ではこのスタイルは無視される
WS_EX_RIGHTSCROLLBAR 垂直スクロールバーを右端に表示
このスタイルは既定
WS_EX_CONTROLPARENT このスタイルを指定すると、Tabキー等のフォーカス移動の対象に子ウィンドウが含まれるようになる
WS_EX_STATICEDGE ユーザー入力を受け付けない項目のための、3D境界線を持つウィンドウ
WS_EX_APPWINDOW ウィンドウが可視状態の時、タスクバーにトップレベルウィンドウを強制的に表示
WS_EX_OVERLAPPEDWINDOW WS_EX_WINDOWEDGEWS_EX_CLIENTEDGEの組み合わせ
WS_EX_PALETTEWINDOW WS_EX_WINDOWEDGEWS_EX_TOOLWINDOWWS_EX_TOPMOSTの組み合わせ
WS_EX_LAYERED レイヤーウィンドウ
CS_OWNDCCS_CLASSDCと同時に指定できない
WS_EX_NOINHERITLAYOUT 子ウィンドウにウィンドウレイアウトを渡さない
WS_EX_NOREDIRECTIONBITMAP リダイレクトサーフィスを描画しない
可視コンテンツを持たない場合や、標準以外の方法で描画する場合に使用
(Windows8以降)
WS_EX_LAYOUTRTL 右から左へ読む言語のために、レイアウトの水平方向の起点を右端に設定
座標は右から左へと値が増えていく
WS_EX_COMPOSITED 子孫ウィンドウを下から上へ描画する
CS_OWNDCCS_CLASSDCを同時に指定できない
(Windows XP以降)
WS_EX_NOACTIVATE トップレベルウィンドウはユーザーのクリック等の動作でアクティブにならない
アクティブにするにはSetActiveWindow関数やSetForegroundWindow関数を使用する
標準ではタスクバーに表示されない
タスクバーに表示するにはWS_EX_APPWINDOWを同時に指定する

拡張ウィンドウスタイルの定数はすべて「WS_EX_○○」という形式です。

ウィンドウひとつ作るだけでかなりの情報量ですが、全てを把握する必要はありません。
とりあえずはサンプルコード通りのウィンドウを作成し、必要に応じていろいろと変更してみましょう。