Saturday, January 05, 2008

3.ウィンドウの作成

RegisterClassEx()関数で定義したウィンドウクラスをシステムに登録し終わったら,次にウィンドウを作成する.CreateWindow()関数またはCreateWindowEx()関数を使用:(後者は拡張スタイルも使用できる点だけ前者と異なる.)

HWND CreateWindow(

  • LPCTSTR lpClassName, // クラス名
  • LPCTSTR lpWindowName, // ウィンドウ名,タイトル
  • DWORD dwStyle, // ウィンドウスタイル
  • int x, // x位置
  • int y, // y位置
  • int nWidth, // 幅
  • int nHeight, // 高さ
  • HWND hWndParrent, // 親ウィンドウのハンドル
  • HMENU hMenu, // メニューハンドルまたは子ウィンドウID
  • HINSTANCE hInstance, // インスタンスハンドル
  • LPVOID lpParam // ウィンドウ作成データ

);

まず,...
lpClassNameはWNDCLASSEX構造体のlpszClassNameメンバに指定したウィンドウクラス名を指定.自分で登録したウィンドウクラス以外に,システムで定義されたクラスを使うことができる.(後述)

続いて,...
lpWindowNameはウィンドウの名前,タイトル

続いて,...
dwStyleはウィンドウスタイルを指定.サイズ変更可能,タイトルバーにコントロールメニューボックス,最大化,最小化ボタンを持つ一般的なオーバーラップウィンドウであるWS_OVERLAPPEDWINDOWを指定.

続いて,...
x, yはウィンドウが表示される座標を指定.

続いて,...
nWidth, nHeightはウィンドウの幅,高さ.x,y,nWidth,nHeightそれぞれCW_USEDEFAULTを指定することができる.そうすると適当な位置とサイズをシステムが決めてくれる.

続いて,...
hWndParrentには親ウィンドウのウィンドウハンドルを指定.親がないときはNULL.

続いて,...
hMenuにはメニューを指定.そのほかの使い方もあるが後述.

続いて,...
hInstanceにはインスタンスハンドルを指定.Windows NT/2000/XPは無視される.

続いて,...
lpParamはいろいろ面白い使い方があるが後述.ここではNULL.気になる~

これで登録を行い失敗したらNULLが返ってくる.成功するとウィンドウのハンドルを返される.以後,このウィンドウを操作するにはこのハンドルをいじる

登録が終わるとウィンドウが表示されない.表示するにはShowWindow()関数を使用:

ShowWindow(

  • HWND hWnd, // ウィンドウハンドル
  • int nCmdShow // 表示状態

);

nCmdShowは次の値をとる:

オプション 意味
SW_HIDE 非表示
SW_MAXIMIZE 最大表示
SW_MINIMIZE 最小表示
SW_RESTORE 最大化または最小化されたウィンドウを元のサイズに戻す
SW_SHOW ウィンドウをアクティブにして,現在の位置とサイズで表示
SW_SHOWNORMAL ウィンドウをアクティブにして表示.初めてウィンドウを表示するときはこれを指定.

UpdateWindow()関数はウィンドウを更新する.

BOOL UpdateWindow(

  • HWND hWnd;

);
この関数はどのような役割をもつのかな?プログラムをこの部分をコメントアウトしてもウィンドウは普通に表示された.

その3.p28~p31

2.ウィンドウクラスの内部

  1. WNDCLASSEX構造体のメンバー指定
  2. RegisterClassex関数で登録

typedef struct WNDCLASSEX, *PWNDCLASSEX{

  • UINT cbSize; // 構造体のサイズ
  • UNIT style;   // クラスのスタイル
  • WNDPROC lpfnWndProc; // ウィンドウプロシージャ
  • int cbClsExtra; // 補助メモリ
  • int cbWndExtra; // 補助メモリ
  • HINSTANCE hInstance; // インスタンスハンドル
  • HICON hIcon; // アイコン
  • HCURSOR hCursor; // カーソル
  • HBRUSH hbrBackground; // 背景ブラシ
  • LPCTSTR lpszMenuName; // メニュー名
  • LPCTSTR lpszClassName; // クラス名
  • HICON hIconSm; // 小さいアイコン

}

指定方法:
WNDCLASSEX wc;

まず...
wc.cbSize = sizeof(WNDCLASSEX);

続いて...
wc.style = CS_HREDRAW | CS_VREDRAW;
「CS_??」はClass Styleの略.CS_HREDRAWはクライアント領域の横が変わったときにウィンドウ全体を再描画する.H-> Horizon, V -> Vertical.ほかにwinuser.hに多数定義してある.CS_??はただの数字.winuser.hの中に
#define CS_* 0x???
...

続いて,...
wc.lpfnWndProc = ウィンドウのプロシージャ関数のアドレス
これはウィンドウプロシージャ関数アドレスを指定(関数の名前そのもの)

続いて,...
hIcon(大きいアイコン)やhIconSm(小さいアイコン)にはアイコンを指定.hIconSmがNULLであるとシステムはhIconの値を検索する.アイコンをロードする方法は
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
しかし,LoadIcon関数は現在LoadImage関数に取って代わられた

LoadImage関数:
HANDLE LoadImage{

  • HINSTANCE hinst, // インスタンスのハンドル
  • LPCTSTR lpszName, // イメージの名前または識別子
  • UINT uType, // イメージタイプ
  • int cxDesired, // 希望する幅
  • int cyDesired, // 希望する高さ
  • UINT fuLoad // ロードのオプション

};

hinst:インスタンスハンドルを指定する.システムで定義されたアイコンを使う場合はNULLを指定

lpszName:にはアイコンの名前または識別子を使う.識別子で指示するときは

  • MAKEINTRESOURCEマクロ

を使用する

uType:はイメージのタイプを指定する.アイコンならIMAGE_ICONとなる.

LoadImage関数はアイコンだけでなく,マウスカーソルやビットマップもロードできる.カーソルのときはIMAGE_CURSOR,ビットマップはIMAGE_BITMAP,を指定.

cxDesired,cyDesiredはイメージの希望サイズを指定するが,これを0にして,fuLoadパラメータにLR_DEFAULTSIZEを指定するとシステムで定義されたサイズになる.またfuLoadLR_SHAREDも指定する必要がある.このフラグを指定した場合不要なリソースはシステムによって自動的に破棄される.ウィンドウクラスの定義では必ずLR_SHAREDを入れておく!

その2.p23~p26

~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*

LoadImage()関数はカーソルやアイコンを設定できるという話のつづき...
アイコンとカーソルの指定は共通でLoadImage()関数で行うことができるが,異なる点はMAKEINTRESOURCEマクロの設定は

  • MAKEINTRESOURCE(IDC_APPLICATION)->ICONか
    MAKEINTRESOURCE(IDC_ARROW) ->CURSORの点が異なると
  • uTypeの指定はIMAGE_ICONかIMGAE_CURSORかの点で異なる

でした.具体的に,もっと詳細で書くとプログラム内でカーソルの設定の部分は以下のようになる(カーソルはHCURSORでキャッシュしアイコンはHICONでキャッシュしている所に注意!):

wc.hCursor = (HCURRSOR)LoadImage(

  • NULL,
  • MAKEINTRESOURCE(IDV_ARROW),
  • IMAGE_CURSOR,
  • 0,
  • 0,
  • LR_DEFAULTSIZE | LR_SHARED

);

続いて,...
hbrBackgroundには背景を塗りつぶすブラシを指定.(これは後述).サンプルでは:

wc.hbBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

GetStockObject()関数はHGDIOBJ型を返す関数がhbBackgroundはHBRUSH型であるためキャッシュする必要がある.めちゃめちゃキャッシュしてるやなぁ~.こりゃ大変.APIのプログラミングではキャッシュは無数あるらしい...
GetStockObject()関数は定義済み(ストック)オブジェクトのハンドルを取得.戻り値の型はHGDIOBJである(GDIオブジェクトのハンドル).WHITE_BRUSH, GRAY_BRUSH, BLACK_BRUSH...など指定してみた^^

続いて,... 
lpszMenuNameにはメニューの名前を指定.サンプルはメニューがないためNULLを指定した.

続いて,...
lpzClassNameにはクラスの名前を指定.サンプルでは"sample01"とか指定してある.

これでウィンドウクラスの定義が完了!次にはRegisterClassEx()関数でシステムに登録する

ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx);

ATOM型は後述
登録が終わったらウィンドウの作成...

その2.p27~p28