>> WINAPI入門トップに戻る

ウィンドウの作成

今回はウィンドウの作成について説明します。
前回説明したとおり、ウィンドウの作成でしなければならないのは

①ウィンドウクラスの登録
②ウィンドウの作成

の二つです。
まずはウィンドウクラスの登録から説明します。

ウィンドウクラスを登録するには、WNDCLASS構造体を定義し、
RegisterClass関数にそのアドレスを渡します。
下記のコードをごらん下さい。

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	WNDCLASS wc;

	wc.style=CS_HREDRAW | CS_VREDRAW;//縦横の再描画をする
	wc.lpfnWndProc=WinProc;//ウィンドウプロシージャの名前
	wc.cbClsExtra=wc.cbWndExtra=0;//使わないから0かNULL
	wc.hInstance=hInstance;//インスタンスハンドル
	wc.hCursor=wc.hIcon=NULL;//NULLで問題なし
	wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//背景を黒に設定
	wc.lpszClassName="test";//クラス登録名は「test」に設定
	wc.lpszMenuName=NULL;//メニューは使用しないのでNULL
	
	if(!RegisterClass(&wc)){
		return -1;
	}

まずWNDCLASS構造体を宣言して、色々なメンバに値を代入しています。
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;

styleメンバはウィンドウクラスのスタイルを指定します。
lpfnWndProcメンバはウィンドプロシージャの関数を指定します。
hInstanceメンバはインスタンスハンドルを指定します。
hCursorはカーソルのハンドルを指定します。
hIconはアイコンのハンドルを指定します。
hbrBackgroundメンバは背景色を設定します。
lpszClassNameメンバは登録するクラスの名前を指定します。
lpszMenuNameメンバはメニューのハンドルを指定します。

ただの平凡なwindowアプリケーションであれば、上記のメンバを設定するだけで十分です。
hIcon,hCursor,lpszMenuName,cbClsExtra,cbWndExtraメンバーは
NULLを指定しても問題なく動作します。

styleメンバに指定してる、CS_HREDRAWとCS_VREDRAWはウィンドウのリサイズ時に
縦横を再描画するかしないかの設定です。
基本はこの二つを指定しておけばokです。

hbrBackgroundメンバで、GetStockObject関数を使っています。
この関数は引数に指定した定数のGDIオブジェクトを取得する関数です。
描画専用のオブジェクトだと思ってもらえれば問題ありません。
それを取得し、HBRUSH型にキャストしてます。
hbrBackgroundメンバはHBRUSH型なので、これをする必要があります。
その他のメンバについては、コード内に記述している通りです。

これでウィンドウクラスの定義が出来ました。
これを、RegisterClass関数に渡して、登録を行います。

RegisterClass関数にはWNDCLASS構造体のアドレスを渡します。
関数が成功すれば、0以外の値が返ります。失敗すれば0が返ります。
上記のコードでは失敗した場合はプログラムを終了するようにしています。
ここまでが、ウィンドウクラスの登録になります。
また、プログラム終了時には、UnregisterClass関数で、
ウィンドウクラスを破棄する必要があります。
この関数の第一引数にはクラス名、第二引数にはインスタンスハンドルを指定して下さい。

次にウィンドウの作成を説明します。
ウィンドウの作成には、CreateWindow関数を使います。
引数は以下のようになっています。

HWND CreateWindow(
LPCTSTR lpClassName, // RegisterClass関数で登録したクラス名
LPCTSTR lpWindowName, // ウィンドウの名前
DWORD dwStyle, // ウィンドウスタイル
int x, // ウィンドウの横方向の位置
int y, // ウィンドウの縦方向の位置
int nWidth, // ウィンドウの幅
int nHeight, // ウィンドウの高さ
HWND hWndParent, // 親ウィンドウまたはオーナーウィンドウのハンドル
HMENU hMenu, // メニューハンドルまたは子ウィンドウ ID
HINSTANCE hInstance, // アプリケーションインスタンスのハンドル
LPVOID lpParam // ウィンドウ作成データ
);

関数が成功すると、作成したウィンドウのウィンドウハンドルが返ります。
失敗するとNULLが返ります。
ウィンドウハンドルとはどのウィンドウなのかを識別するための番号です。
CreateWindow関数は実は、CreateWindowA関数とCreateWindowW関数の二つのどちらかが実行されています。
実はプロジェクトの文字コードの設定によって、都合の良い方にtypedefで名前が変えられています。
プロジェクトアイコンをクリックしてプロパティを見てみてください。

この文字セットの設定が「マルチバイト文字セットを使用する」になっていれば、CreateWindowA関数が、
「Unicode文字セットを使用する」になっていれば、CreateWindowW関数が実行されます。
これによって影響してくるものは、第一引数と第二引数です。
ここは文字列を指定しますが、マルチバイトの文字セットは単純に
「"test"」とダブルクオテーションで指定すれば良いのに対し、
Unicode文字セットを使用する場合は文字の前に大文字のLを置いて、
「L"test"」と書かなければなりません。
もっと詳しく言うと、マルチバイト文字セットの場合は、第一、二引数の方がLPCSTR(const char)型なのに対し、
Unicode文字セットだとLPCWSTR(const w_char)型になります。
ですので引数の指定方法が違うんですね。
この仕組みは他にも沢山ある関数についても言えることです。
何か文字列関連のコンパイルエラーが出たらまずコレを疑いましょう。

さて話がそれましたが、実際のCreateWindow関数のコードを見てください。
関数はCreateWindowA関数を使っていますが、CreateWindow関数を使っても、
文字セットをマルチバイト文字セットに指定してれば、自動的にCreateWindowA関数が実行されます。

	hwnd=CreateWindowA("test","テストウィンドウ",WS_VISIBLE | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
		0,0,WIDTH,HEIGHT,NULL,NULL,hinst,NULL);

	if(hwnd==NULL){
		return -1;
	}

第一引数には先程ウィンドウクラスを登録する際に指定したクラス名を指定しています。
第二引数にはウィンドウの名前を指定しています。
第三引数はウィンドウスタイルを指定しています。
上記のコードだと、システムメニュー、システムメニュー、タイトルがあり、
ウィンドウを表示する、という指定になります。
ウィンドウスタイルは他にも沢山ありますので、コチラを参照して下さい。
親ウィンドウハンドル、メニューハンドル、ウィンドウ作成データは今回は必要ないので、
NULLを指定しています。
その他のメンバは関数の説明とコードの通りです。

ここまでがウィンドウの登録になります。
引数が非常に多くて覚えるが大変ですが、
まずは絶対使う必要のあるメンバや引数だけ覚えてください。

次回はメッセージループについて説明します。


>> 【メッセージループ】に進む
>> WINAPI入門トップに戻る