ウィンドウを作ろう!

今回やっとウィンドウを作ります。ではさっそくソースコードです。打ち込んでビルドしちゃってください。面倒な方はダウンロードを。 解説は後でひとつひとつゆっくりしてゆくので、コツコツ打ち込んでください。


#include <windows.h>

///// プロトタイプ宣言

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int);
LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp);

///// 変数宣言

const char *strClassName="SAMPLE"; // ウィンドウクラスの名前
const char *strTitle="サンプル"; // タイトル

///// WinMain

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	// ウィンドウクラスの登録
	WNDCLASSEX wcx;
	wcx.cbSize			= sizeof(WNDCLASSEX);
	wcx.style			= NULL;
	wcx.lpfnWndProc		= WindowProc;
	wcx.cbClsExtra		= 0;
	wcx.cbWndExtra		= 0;
	wcx.hInstance		= hInstance;
	wcx.hIcon			= LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION));
	wcx.hCursor			= LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW));
	wcx.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcx.lpszMenuName	= NULL;
	wcx.lpszClassName	= strClassName;
	wcx.hIconSm			= NULL;

	if(!RegisterClassEx(&wcx)) return 0; // クラス登録

	// ウィンドウ作成
	HWND hwnd;
	hwnd=CreateWindowEx(NULL,strClassName,strTitle,WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
			NULL,NULL,hInstance,NULL);
	if(!hwnd) return 0;

	ShowWindow(hwnd,nCmdShow); // Window表示

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

	return msg.wParam;
}

///// ウィンドウプロシージャ

LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
	switch(msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default: return DefWindowProc(hwnd,msg,wp,lp);
	}
	return 0;
}

///// End of Source


DownLoad!ソースファイルをDownLoad!

このソースをビルドすると、↓のようなウィンドウが表示されます。といってももっとでかいですが。



もっとも基本的な、ウィンドウアプリケーションはどのように作られるのでしょうか。主な作業は、

の3個です。

1:ウィンドウクラスの登録

ではまず、「ウィンドウクラス」について説明します。 これは作りたいウィンドウの仕様のようなもので、最初にこれを作って登録しておきます。 すると登録したウィンドウクラスに基づくウィンドウが作れるようになります。 ウィンドウクラスは「WNDCLASSEX構造体」で作成し、「RegisterClassEx関数」で登録します。

WNDCLASSEX
UINT cbSize; WNDCLASSEX構造体のサイズをいれます。普通、sizeof(WNDCLASSEX)をいれておきます。
UINT style; ウィンドウクラスのスタイル
WNDPROC lpfnWndProc; ウィンドウプロシージャを指定します
int cbClsExtra; 拡張用。
int cbWndExtra; 拡張用。
HANDLE hInstance; インスタンスハンドル
HICON hIcon; アイコンのハンドル
HCURSOR hCursor; カーソルのハンドル
HBRUSH hbrBackground;背景のブラシのハンドル
LPCTSTR lpszMenuName; メニュー
LPCTSTR lpszClassName;ウィンドウクラスの名前
HICON hIconSm; 小さいアイコンのハンドル


ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx // 登録するウィンドウクラス構造体のポインタ );
ウィンドウクラスを登録します。戻り値は登録したウィンドウクラスがATOM(unsigned short)というデータ型で返されます。

さて、たくさんメンバがありますね。ここでひとつひとつ説明していくとまず覚えきれないので、また後にまわします(^_^;)。 ひとまず使わないところは0に指定しておけば大丈夫です。
lpfnWndProcにはウィンドウプロシージャをいれますが、これはOSからのメッセージを受け取る関数のことです。 ウィンドウプロシージャは重要なので後で説明します。
hInstanceにはWinMainの引数になっているのをそのまま使います。 インスタンスハンドルというのはそのスレッド(実行されているプログラム一つ一つ)に個別に割り当てられているIDの様なものです。

2:メインのウィンドウ作成

ここで初めてウィンドウが作成されます。 スタイルや大きさ、位置、タイトルなどを指定して作ることが出来ます。

HWND CreateWindowEx( DWORD dwExStyle, // 拡張スタイル LPCTSTR lpClassName, // ウィンドウクラス名 LPCTSTR lpWindowName, // ウィンドウの名前(タイトル) DWORD dwStyle, // スタイル int x, // ウィンドウの位置(縦) int y, // ウィンドウの位置(横) int nWidth, // 横幅 int nHeight, // 高さ HWND hWndParent, // 親ウィンドウのハンドル HMENU hMenu, // メニューのハンドル。子ウィンドウならID HINSTANCE hInstance, // アプリケーションのインスタンスハンドル LPVOID lpParam // ウィンドウを作るときのデータ );
ウィンドウを作成します。スタイルの指定でいろんなウィンドウを作れます。戻り値に作成したウィンドウハンドルが返ります。

lpClassNameの所にさっき作成したウィンドウクラス名を指定します。 ここに"EDIT""BUTTON"などをしていするとエディタコントロールやボタンなどのコントロールを作成することが可能です。 じつはあらゆるコントロールもウィンドウの一種なんですね。 スタイルにはここではWS_OVERLAPPEDWINDOWというのを指定しています。これは普通のウィンドウを作るのには最適です。 位置と大きさにはCW_USEDEFAULTというのを指定しています。これはOSに全部任せちゃうという意味です。
さて、この関数を呼び出して返ってきた「HWND」というデータ型。前々から登場してきた型なんですが、とっても重要なものです。 ウィンドウハンドルといい、ウィンドウを識別するIDの様なものです。ここで返ってきたハンドルを使うことでウィンドウを操作することが出来ます。 作った後にShowWindow関数で早速HWNDを使っています。


BOOL ShowWindow( HWND hWnd, // ウィンドウハンドル int nCmdShow // ウィンドウをどのように表示するか );
ウィンドウの表示方法をnCmdShowに変えます。

ここでWinMainから送られてきた表示方法をそのまま引数として渡しています。 この関数を使うとウィンドウを最大化させたり、最小化させたり、見えなくさせることも出来ます。

3:メッセージループ

メッセージというのはWindowsのアプリケーションの特徴です。 イベントドリブンという仕組みで、イベントが起きるとそれに合ったメッセージがアプリケーションに送られます。 そしてプログラムの方はそのメッセージ別にコードを書けば作りたいアプリケーションを作ることが出来ます。
まずメッセージループは、メッセージキュー(メッセージの溜まり場)からメッセージを取得します。 そして翻訳し、ウィンドウプロシージャに送出します。

GetMessage関数 スレッドの一つ一つに用意されているメッセージキューから取得します。
TranslateMessage関数仮想キーメッセージを文字メッセージに変換します。文字などを入力したときに使われます。
DispatchMessage関数 メッセージをウィンドウプロシージャに送出します。

ここで送出先になるプロシージャは引数であるMSG構造体内のhwndメンバのウィンドウクラスに指定したプロシージャです。 いろいろなコントロール(ボタンなど)にもメッセージは送られてきますが、全てOSが処理してくれるので気にする必要はありません。 自分で登録したウィンドウクラスに指定したプロシージャ(上のソースの場合WindowProc)に送られてくるものだけを使います。 メッセージループは、「WM_QUIT」というメッセージを受け取るとwhileループから抜け出して終了します。

さて、今回はどうだったでしょうか。分からない方はばんばん掲示板などで質問してください。ちょくちょくなおしていきます。 次回はプログラムの心臓部、ウィンドウプロシージャを説明します。ではでは・・・


★INDEX★

Copyright(C) へぽぽ