<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href='base.xsl'?>

<desc title="ウィンドウを作って表示させる最小プログラム">

	<source>#include &lt;windows.h&gt;

//クラス名定義
#define	CLASS_NAME	"sample"

//メッセージの対応
LRESULT CALLBACK WinProc( HWND h, UINT m, WPARAM w, LPARAM l )
{
	return DefWindowProc( h, m, wm, l );
}

//メイン
int WINAPI WinMain( HINSTANCE hinst, HINSTANCE, LPSTR, int )
{
	WNDCLASS	wc;
	HWND		hwnd;
	MSG		 	msg;

	//アプリケーションの設定
	memset( &amp;wc, 0, sizeof(wc) );
	wc.hbrBackground	= (HBRUSH)GetStockObject( BLACK_BRUSH );
	wc.hCursor			= LoadCursor( NULL, IDC_ARROW );
	wc.hIcon			= LoadIcon( NULL, IDI_WINLOGO );
	wc.hInstance		= hinst;
	wc.lpfnWndProc		= WinProc;
	wc.lpszClassName	= CLASS_NAME;

	//アプリケーション登録	
	if( !RegisterClass( &amp;wc ) ) return 1;

	//ウィンドウ作成	
	hwnd = CreateWindow( CLASS_NAME, "Skeleton Window Sample",
				WS_OVERLAPPEDWINDOW|WS_VISIBLE,
				0, 0, 320, 240,
				NULL, NULL, hinst, NULL
				);

	//メッセージループ
	while( GetMessage( &amp;msg, NULL, 0, 0 ) &gt; 0 )
	{
		DispatchMessage( &amp;msg );
	}

	return 0;
}
	</source>

	<r/>

	Win32 API を使い、ウィンドウを表示させる最小プログラムです。<r/>
	これを更に削ろうとしたら、CLASS_NAME をベタ書きすることになりそうです。<r/>

	<r/>

	それでは、上から順番に説明して行きます。<r/>

	<r/>

	<font bold="yes">#include &lt;windows.h&gt;</font><r/>
	Win32 API を使う場合、windows.h のインクルードは必須です。<r/>

	<r/>

	<font bold="yes">#define	CLASS_NAME	"sample"</font><r/>
	２箇所で使いまわすため、デファインしておきます。<r/>
	const char * const CLASS_NAME = "sample"; のように、定数を使う方法もあります。<r/>

	<r/>

	<font bold="yes">LRESULT CALLBACK WinProc( HWND h, UINT m, WPARAM w, LPARAM l )</font><r/>
	ウィンドウが作られた、ウィンドウが破棄された、ウィンドウの上でマウスカーソルが動いた、
	ウィンドウの上でクリックされた…などのイベントが起きたときに、
	この関数を呼び出します。<r/>
	正確に言うと、呼び出すべきです。<r/>

	<r/>

	イベントが起きたときに呼び出す関数は、
	wc.lpfnWndProc = WinProc; の行で指定しています。<r/>
	戻り値と引数が同じ Test という関数を別に作って、
	wc.lpfnWndProc = Test と指定すれば、
	メッセージを受け取った時に Test 関数を呼び出すことができます。<r/>

	<r/>

	要するに関数の名前は命名規則にのっとっていれば、何でも構いません。<r/>
	このような関数をプレースホルダと呼びます。<r/>
	Win32 API では度々登場するので、覚えておくと後で役に立つかも知れません。<r/>

	<r/>

	この関数はウィンドウを作った後に変更することもできますし、
	複数設定することもできます。<r/>

	<block>

		LRESULT は int を #define したものです。<r/>
		このように別の名前が付けられた型は、Win32 API には沢山存在します。<r/>
		実際の型が何であるか？というよりも、
		戻り値にどういう意味があるのか？が重要視されているように思えます。<r/>
		型名に RESULT という単語があるので、関数の結果を返すことが想像できます。<r/>
		L は恐らく LONG の頭文字です。<r/>
		このことから、LRESULT は、
		関数で処理した結果をロング型で返すということが推察できます。<r/>
		「結果」というからには、
		「関数内でこういう処理が行われました。」という値を示すものである可能性があります。<r/>
		逆に戻り値を int にした場合、関数の戻り値がイント型であるという以上の情報は得られません。<r/>
		それが関数内で行われた処理の結果を返すのか、
		呼び出し元に次の処理を支持するための値を返すのか、
		エラーを示す値を返すのか、
		何かのハンドルを示す値なのか…など、無数の選択肢がある中で、
		その中のどれにあたるのかを特定することができません。<r/>
		使う側にとっては覚えることが増えてしまいますが、
		このように戻り値に別の名前を付けるということには、
		それなりの意味があるということが伺えます。<r/>

		<r/>

		CALLBACK は、関数の呼び出し規約を #define したものです。<r/>
		デファインされている呼び出し規約は PASCAL か FAR PASCAL です。<r/>
		これは言語仕様に関することですので、割愛します。<r/>
		C 呼び出し規約 pascal で検索すれば、沢山のウェブページが見つかるはずです。<r/>

		<r/>

		WinProc( HWND h, UINT m, WPARAM w, LPARAM l )<r/>
		前述した通り、関数名は WinProc である必要はありません。<r/>
		引数の名前は面倒なので一文字にしています。<r/>

		<r/>

		h には、イベントが起きたウィンドウのハンドルが渡されます。<r/>
		ウィンドウにボタンやエディットボックスを貼り付ける場合、
		これらは全て子ウィンドウとして作成しなければいけません。<r/>
		WinProc は子ウィンドウで起きたイベントもまとめて呼び出すことができます。<r/>
		その場合「どのウィンドウでイベントが起きたのか？」を知るためには、
		この引数は必要です。<r/>

		<r/>

		m には、どのイベントが起きたのか？を示すメッセージが渡されます。<r/>

		<r/>

		w と l(L) には、メッセージと一緒に渡されるパラメータが渡されます。<r/>
		例えば、マウスカーソルが動いたメッセージの場合、
		マウスカーソルの座標が w か l に渡されます。<r/>
		キーが押された場合、どのキーが押されたのかを知る必要があるかも知れません。<r/>
		このようにメッセージに付随する情報が必要な状況があり、
		そのような状況で w と l は役に立つことがよくあります。<r/>

	</block>

	<font bold="yes">return DefWindowProc( h, m, wm, l );</font><r/>
	何も処理するべきメッセージがない場合、
	この関数を呼び出すことで、この関数が適切な処理を行ってくれます。<r/>
	自分で全てのメッセージを捕捉する処理を書くのは、
	とても面倒ですし、時間の無駄です。<r/>
	必要がないなら、後始末はこの関数に任せてしまうのが賢明でしょう。<r/>

	<r/>

	MSDNライブラリでの説明
	<list>
		<item>
			DefWindowProc<r/>
			<link url='http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_defwindowproc.asp?frame=true'>http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_defwindowproc.asp?frame=true</link>
		</item>
	</list>

	<r/>

	<font bold="yes">int WINAPI WinMain( HINSTANCE hinst, HINSTANCE, LPSTR, int )</font><r/>
	コンソールアプリケーションの main 関数にあたるのが WinMain です。<r/>
	Win32 ウィンドウアプリケーションでは WinMain は必須です。<r/>

	<block>

		WINAPI<r/>
		CALLBACK と同じく、関数の呼び出し規約をデファインしたものです。<r/>
		ウィンドウズ環境では __stdcall になるようです。<r/>
		呼び出し規約については割愛します。<r/>

		<r/>

		HINSTANCE hinst, HINSTANCE, LPSTR, int<r/>
		最初の引数にのみ名前を付けているのは、
		この引数しか使わないためです。<r/>
		使わない引数に名前を付けると、
		コンパイル時に「～は一度も使われていません。」という警告が出て、
		煩わしいからです。<r/>
		引数の名前を省略する以外に、
		関数の冒頭で (void) にキャストする方法もあります。<r/>
		名前を省略する方が楽なので、このような書き方をしています。<r/>

		<r/>

		最初の引数 HINSTANCE は、
		インスタンスハンドルと呼ばれていますが、
		インスタンスが何かをきちんと理解するには、
		C++ のクラスについての勉強が必要です。<r/>
		なので、インスタンスが何か？については省略します。<r/>
		この引数がなければウィンドウを作ることができません。<r/>
		また、この引数の値は Win32 API を使っていると、
		たびたび要求されます。<r/>

		<r/>

		２番目の HINSTANCE は、
		Win16 API との互換性を保つためだけに残されている引数で、
		私の経験上使ったことはありません。<r/>

		<r/>

		３番目の LPSTR は、コマンドライン引数が渡されます。<r/>
		Win32 ウィンドウアプリケーションにコマンドライン引数を渡すには、
		ショートカットを作る必要があります。<r/>
		コマンドプロンプト(DOS窓)が扱えるなら、
		コンソールアプリケーションと同じように、
		コマンドライン引数を付けてアプリケーションを起動すればＯＫです。<r/>
		コマンドライン引数については、
		ここでの説明は省略します。<r/>

		<r/>

		最後の引数は、ウィンドウを作ったときに、
		どのような状態で表示させるべきか…を示す値が渡されます。<r/>
		状態には、最小化、最大化、通常の３つがあります。<r/>
		アプリケーション起動時のウィンドウの状態は、
		ショートカットを作らなければ設定できません。<r/>
		最小化で起動するように設定すると、
		この引数にそれを示す値が渡されます。<r/>
		この値は「できればそうして下さいね。」というものなので、
		今回のサンプルのように無視しても全く問題はありません。<r/>

	</block>

	<font bold="yes">WNDCLASS	wc;</font><r/>
	ウィンドウクラスの基本設定を行うための構造体です。<r/>
	ウィンドウクラスは恐らく、ウィンドウズが持っている機能のひとつです。<r/>
	これも恐らくですが、全てのアプリケーションはウィンドウクラスの機能を使って、
	作られることになります。<r/>
	この構造体には、アプリケーションのアイコンはどうするか、
	メニューはあるのか…などを設定します。<r/>

	<block>

		memset( &amp;wc, 0, sizeof(wc) );<r/>
		使わない変数はすべて memset を使って 0 で初期化します。<r/>

		<r/>

		wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );<r/>
		ここではウィンドウのクライアント領域を塗りつぶす色を設定しています。<r/>
		BLACK_BRUSH は、黒でクライアント領域を塗りつぶします。<r/>
		グレーにしたい場合は GRAY_BRUSH を指定します。<r/>

		<r/>

		wc.hCursor = LoadCursor( NULL, IDC_ARROW );<r/>
		LoadCursor 関数を使って、
		ウィンドウズ側で用意されているデフォルトのカーソルを使うように設定しています。<r/>
		マウスカーソルがこのアプリケーションのウィンドウの上に来ると、
		ここで設定したカーソルに変わります。<r/>

		<r/>

		wc.hIcon = LoadIcon( NULL, IDI_WINLOGO );<r/>
		実行ファイルや、タイトルバーの左隅に表示されるアイコンを設定しています。<r/>
		ここではウィンドウズ側で用意されているアイコンを指定しています。<r/>
		アプリケーションのアイコンは、ここで指定したものになります。<r/>

		<r/>

		wc.hInstance = hinst;<r/>
		WinMain 関数の最初の引数を指定します。<r/>

		<r/>

		wc.lpfnWndProc = WinProc;<r/>
		イベントが起きたときに、
		メッセージを送信する関数名を指定します。<r/>

		<r/>

		wc.lpszClassName = CLASS_NAME;<r/>
		クラス名を指定します。<r/>
		クラス名は何でも構いません。<r/>
		ウィンドウを作るときにも要求されます。<r/>

		<r/>

	</block>

	<font bold="yes">if( !RegisterClass( &amp;wc ) ) return 1;</font><r/>
	WNDCLASS構造体でアプリケーションの設定ができたら、
	RegisterClass 関数を使ってウィンドウズに登録します。<r/>
	登録に成功して初めて Win32 アプリケーションとして、
	ウィンドウズ上で動作することができるようになります。<r/>
	この作業を飛ばすと、以降 Win32 API を使ったあらゆる処理に失敗します(全てではありません)。<r/>
	当然、ウィンドウも作ることができません。<r/>
	ですから登録に失敗した場合は、直ちにプログラムを終了する必要があります。<r/>
	登録に失敗する理由のほとんどは、
	WNDCLASS構造体に設定した値が間違っていたり、
	使わない値を 0 で初期化していなかったりなど、
	プログラムする側のミスです。<r/>
	登録に失敗するようだったら、
	WNDCLASS構造体に設定した値を注意深く確認しましょう。<r/>

	<r/>

	<font bold="yes">hwnd = CreateWindow( CLASS_NAME, "Skeleton Window Sample",...</font><r/>
	メインウィンドウを作ります。<r/>
	CreateWindow 関数は成功時にウィンドウを識別するためのウィンドウハンドルを返します。<r/>
	失敗すると NULL を返します。<r/>
	今後、このウィンドウに対して何かしたい場合は、
	ウィンドウハンドルが必ず必要になります。<r/>

	<block>

		CLASS_NAME<r/>
		最初の引数にはクラス名を指定します。<r/>
		WNDCLASS の lpszClassName に指定したのと同じものである必要があります。<r/>
		異なる文字列を指定した場合、関数は失敗します。<r/>

		<r/>

		"Skeleton Window Sample"<r/>
		２番目の引数には、ウィンドウのタイトルバーに表示させる文字を指定します。<r/>
		この文字はウィンドウを作った後でも、
		SetWindowText 関数を使うことで変更できます。<r/>
		クラス名とは関係がないので、
		単純にタイトルバーにどんな文字を表示したいか？だけを考えて決めれば良いと思います。<r/>

		<r/>

		WS_OVERLAPPEDWINDOW|WS_VISIBLE<r/>
		３番目の引数には、ウィンドウのスタイルを設定するためのフラグを指定します。<r/>
		ウィンドウはサイズ変更可能か、タイトルバーのボタンは何を表示させるか、
		ウィンドウに枠をつけるのか、子ウィンドウを作る予定なのか…などを、
		指定できます。<r/>
		フラグは沢山あるので、詳しい説明は MSDN にお任せします。<r/>

		<r/>

		<link url='http://msdn.microsoft.com/library/ja/vclib/html/_mfc_window_styles.asp'>http://msdn.microsoft.com/library/ja/vclib/html/_mfc_window_styles.asp</link><r/>

		<r/>

		複数指定するときは |(OR演算子) を使って連結します。<r/>
		ここで指定しているフラグは、
		基本的なウィンドウスタイルを指定するフラグ(WS_OVERLAPPEDWINDOW)と、
		ウィンドウを作ったらすぐに表示させるフラグ(WS_VISIBLE)です。<r/>

		<r/>

		0, 0, 320, 240<r/>
		４～７番目の引数には、ウィンドウを表示するＸ位置、Ｙ位置、
		ウィンドウの横幅、高さを指定します。<r/>

		<r/>

		NULL<r/>
		８番目の引数には、親ウィンドウのウィンドウハンドルを指定します。<r/>
		ここでは親ウィンドウを作るので、指定するべきウィンドウハンドルがありません。<r/>
		なので NULL を指定しています。<r/>

		<r/>

		NULL<r/>
		９番目の引数には、メニューハンドルか、子ウィンドウのハンドルを指定します。<r/>
		どちらも使わないので NULL を指定しています。<r/>

		<r/>

		hinst<r/>
		１０番目の引数には、WinMain 関数の最初の引数に渡された値をそのまま指定します。<r/>

		<r/>

		NULL<r/>
		１１番目の引数には、CREATESTRUCT構造体か、CLIENTCREATESTRUCT構造体のポインタを指定します。<r/>
		ウィンドウを作成すると WM_CREATE メッセージが WinProc 関数に送信されるのですが、
		その関数の LPARAM 引数に、ここで指定した値が渡されます。<r/>
		WinProc 関数の WM_CREATE を捕捉している箇所で、
		CreateWindow 関数に指定した引数の値を受け取りたい状況などで使うのでしょうか？<r/>
		この引数も私の経験上使ったことがありません。<r/>
		今回も必要ないので NULL を指定しています。<r/>

		<r/>

		サンプルソースを以下のように変更すれば、
		LPARAM 引数に渡って来る値を確認できます。<r/>

		<r/>

		<source>
#include &lt;stdio.h&gt;	//#include &lt;windows.h&gt;の下に追加。

//LRESULT CALLBACK WinProc ... の下に追加。
	switch( m )
	{
	case WM_CREATE:
		{
			CREATESTRUCT *cs = (CREATESTRUCT*)l;
			char text[512];
			sprintf( text,
				"cs=%d\r\n"
				"cy=%d\r\n"
				"dwExStyle=%d\r\n"
				"hInstance=%d\r\n"
				"hMenu=%d\r\n"
				"hwndParent=%d\r\n"
				"lpCreateParams=%x\r\n"
				"lpszClass=%s\r\n"
				"lpszName=%s\r\n"
				"style=%d",
				cs-&gt;cx, cs-&gt;cy, cs-&gt;dwExStyle, cs-&gt;hInstance, cs-&gt;hMenu, cs-&gt;hwndParent,
				cs-&gt;lpCreateParams, cs-&gt;lpszClass, cs-&gt;lpszName, cs-&gt;style
				);
			MessageBox( NULL, text, NULL, MB_OK );
		}
		return 0;
	}
//ここまで

//CreateWindowの部分を以下のように変更。
CREATESTRUCT cs;
HWND hwnd = CreateWindow( /*省略*/, &amp;cs );
		</source>

	</block>

	<r/>

	<font bold="yes">メッセージループ</font><r/>

	<r/>

	<source>
while( GetMessage( &amp;msg, NULL, 0, 0 ) &gt; 0 )
{
	DispatchMessage( &amp;msg );
}
	</source>

	<r/>

	この部分がメッセージループと呼ばれる処理です。<r/>
	ウィンドウを使ったアプリケーションは、
	一定時間毎にメッセージを処理しなければなりません。<r/>
	よく重い処理を行うとウィンドウが固まってしまうアプリケーションがありますが、
	あのような現象は重い処理を行ったまま全くメッセージを処理しないために起きます。<r/>
	業務用ならば重い処理はマルチスレッドで行い、
	ウィンドウが固まらないように処理するべきなのですが、
	できていないソフトウェアを良く見かけます。<r/>

	<r/>

	プログラムがメッセージループに到達すると、
	WM_QUIT メッセージが送信されるまで、
	そこで無限ループします。<r/>
	WM_QUIT メッセージの送信は、
	ウィンドウが破棄されたときに DefWindowProc 関数が勝手に行ってくれます。<r/>

	<block>

		<font bold="yes">while( GetMessage( &amp;msg, NULL, 0, 0 ) &gt; 0 )</font><r/>
		GetMessage 関数がエラーを返すか、WM_QUIT メッセージを受信して 0 を返すまで、
		ループし続けます。<r/>

		<r/>

		GetMessage の２番目の引数にはウィンドウハンドルを指定します。<r/>
		このプログラムではメッセージを処理するべきウィンドウがひとつしかなく、
		このウィンドウが破棄されたらプログラムを終了させたいので、
		ここに hwnd を指定しても問題ありません。<r/>
		NULL を指定すると、
		メッセージを受け取るもの(ウィンドウだけとは限りません)全てが対象になります。<r/>
		例えば、ウィンドウが２つある場合、
		どちらのメッセージもひとつの GetMessage 関数で受け取りたいときは、
		NULL を指定しておけば問題ありません。<r/>

		<r/>

		３番目には受け取りたいメッセージに割り当てられた数値の最小値を指定します。<r/>
		例えば、44 以降の値が割り振られているメッセージのみ受け取りたい場合、
		44 を指定します(例えなので 44 が何のメッセージかは気にしないで下さい)。<r/>

		<r/>

		４番目には、最大値を指定します。<r/>
		例えば、100 までの値が割り振られているメッセージのみ受け取りたい場合、
		100 を指定します。<r/>
		３番目に 44 を指定し、４番目に 100 を指定した場合は、
		44 ～ 100 までのメッセージのみを受け取るようになります。<r/>

		<r/>

		特に受け取るメッセージを制限する必要はないので、
		全てのメッセージを受け取る値(0)を両方に指定しています。<r/>

	</block>

	<r/>

	<font bold="yes">DispatchMessage( &amp;msg );</font><r/>
	この関数は、GetMessage 関数で受け取ったメッセージの情報を、
	WinProc 関数に引き渡します。<r/>

	<r/>

	コンピュータープログラミングでの Dispatch という単語は、
	受け取ったものを素早く別の処理に引き渡すというような意味があります。<r/>
	似たような単語でデイスパッチャー(Dispatcher)というものがあります。<r/>
	これはディスパッチを行う関数・クラス・モジュール・ライブラリなどに対して使います。<r/>

	<r/>

	この関数は WinProc 関数を呼び出しているだけなので、
	以下のように変更しても動作はします。<r/>

	<r/>

	<source>
//本来は DispatchMessage( &amp;msg ); と書くべき。
DefWindowProc( hwnd, msg.message, msg.wParam, msg.lParam );
	</source>

	<r/>

	DispatchMessage を使わない方法は、
	「Win32 API といえばこのコード！」といったセオリーにのっとっていないので、
	判読性が良くお行儀が良いコードとは言えないと思います。<r/>

	<r/>

	また、WinProc 関数を呼び出す必要がなくなりますが、
	この関数は省略はできません。<r/>
	WNDCLASS 構造体の lpfnWndProc メンバ変数に必ず指定しなければなりません。<r/>
	ここに NULL を指定するとコンパイルとリンクは通りますが、
	実行時にエラーが出ます。<r/>
	上記をクリアしたからといって、
	WinProc 関数をプロトタイプ宣言のみにしてしまうと、
	実態がないためリンクに失敗します。<r/>
	どうしても WinProc 関数を使いたくないのであれば、
	最低限 return 0; くらいは書いておく必要があります。<r/>
	ただし DispatchMessage 関数を使わない方法は推奨できません。<r/>

	<r/>

	参考になりそうなサイト
	<list>
		<item>
			<link url='http://www.arcpit.co.jp/winapi/api_02/ap020102.htm'>2-1-2. ＷｉｎＭａｉｎ関数とその仕様</link>
		</item>
	</list>

	<post/>

</desc>

