アークピットのホームページに戻る

WinAPIトピックのトップページに戻る

APIトピックの各章に移動する

ダウンロードのページに移動する
ダウンロードができ
ない場合の対処法
 

ページ移動

1-3-5. クラスとウィンドウの作成

クラスの登録

 Windowsのアプリケーションでは、ウィンドウクラスを登録し、ウィンドウを作成する必要があります。例外的に、メッセージボックスだけとか、コンソール仕様のアプリケーションとかありますが、通常は、クラスを登録して、ウィンドウを作成します。
    WNDCLASSEX wc;
    static LPSTR pClassName = "ApHelloClass";
    static LPSTR pAppName = "ApHello";

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)ApHelloProc;       // (A)プロシージャ
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(hInstance,pAppName);
    wc.hCursor       = LoadCursor(NULL,IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = pAppName;
    wc.lpszClassName = pClassName;
    wc.hIconSm       = LoadImage(hInstance,pAppName,IMAGE_ICON
                                          ,16,16,LR_DEFAULTCOLOR);
    if (!RegisterClassEx(&wc)) return FALSE;
 上記のコードでクラスを登録します。このコードの要は、(A)のプロシージャを登録している部分です。プロシージャとは、システムがコールする関数です。何かあるとシステムは、メッセージと言う形で、ユーザが作成したこの関数をコールします。逆に言うとクラスとは、プロシージャを登録するための手段です。ウィンドウを作成するためには、必ずクラスを登録しなければいけません。違う種類のウィンドウは、別のクラスを登録しますが、同じ種類や似たウィンドウは、同じクラスを使います。つまりクラスとウィンドウは1対多の関係です。前にハンドルの説明をしました。ウィンドウはハンドルで識別しますが、クラスにはハンドルはありません。クラスを識別するのは名前です。wc.lpszClassName で設定した名前がクラス名になりこの名前で識別します。

 クラスでは、ウィンドウの基本的な型も設定します。style でスタイルを、hIcon,hCursor,hbrBackground,lpszMenuName でそれぞれ、アイコン・カーソル・背景色・メインメニューを定義します。これらは、ウィンドウ別の違いはあまりありませんので、ここで設定しておけば簡単です。しかしここでは指定せずに、ウィンドウの作成時点で設定したり、途中で変更したりすることも可能です。
 WIN32では、小さいアイコンを多用します。よって、hIconSm でそのアイコンのビットマップを設定できます。これを行なわなければ、大きいアイコンをシステムが縮小して表示しますので、非常に見難くなってしまいます。アイコンエディタで大・小の2つのアイコンを作成しましょう。ところでアイコンとは、アプリケーションを示す小さなビットマップのことです。ウィンドウの左上に表示します。またエクスプローラやデスクトップなど、あらゆる個所で表示します。アプリケーションを代表する必要がある場合は、このアイコンで行ないます。

 cbSize と言う変数があり、これに構造体のサイズを設定していますが、なぜでしょう。WIN32では、良く使う技法です。これには2つの大きな意義があります。まず改訂による拡張機能との互換性をこれで吸収します。

    WNDCLASS wc;

    wc.cbSize = sizeof(WNDCLASS);
 Windows v3.1 の16ビットのころは、上記のルーチンでした。これをそのままWIN32環境で実行しても、またWIN32でリコンパイルし直して実行しても、動作に問題はありません。それは、cbSize で、WNDCLASS,WNDCLASSEX のどちらを使用するか明示しているからです。WNDCLASSEX の変数である、hIconSm は、cbSize が sizeof(WNDCLASSEX) のときだけ有効です。この様にしとけば、古い版との互換性の他に、拡張機能が欲しいときだけ、サイズを変えその機能を使えば良いので、非常に便利です。
 またサイズを設定する技法は、互換性のためだけでなく、いろいろなプログラミングの側面で役立ちます。例えば、サイズの後方を使用する時や、いくつかの構造体を連ねた時などです。

 では1行づつ見てみましょう。最初の行は、クラス構造体を宣言しています。次ぎの2行で、クラス名、そしてアプリケーション名を定義しています。ここでは、関数内で、static 宣言していますが、もし他の関数で使用するときは、外に出し、他のファイルで使用するときは、static 宣言をやめ、グローバル化します。
 cbSize は説明しました。style で、「ウィンドウを上下か左右にリサイズして、大きさが変わったときに、WM_PAINT メッセージを発行せよ」と設定しています。これはApHelloにとっては非常に重要な指定です。WM_PAINT の個所で説明します。次ぎはプロシージャの設定で、前述しました。
 cbClsExtra,cbWndExtra の2つの変数も非常におもしろい機能を提供してくれます。ここでは使用しませんが、ちょっと違うウィンドウを1つのプロシージャで管理する場合の、ちょっと違う部分を設定することができます。これにはメモリブロックのサイズを設定します。するとシステムは、内部にここで設定したサイズだけエリアを確保します。いつでも、SetClassLong,getClassLong や SetWindowLong,GetWindowLong で設定や取得ができます。cbClsExtra はクラスに付随する補足メモリで、cbWndExtra はウィンドウに付随する補足メモリです。これはコンポーネント技術を考える上で非常に重要な点です。またこの技法を使って、コンパクトでおもしろい機能を盛り込む事もできます。クラスとウィンドウの章で触れます。
 hInstance でインスタンスを明示します。hIcon でリソースから、ApHello と言う名前のアイコンをロードして設定します。hCursor はシステムが用意している矢印のカーソルを使用します。hbrBackground でシステムのウィンドウの色(通常は白)を設定し、lpszMenuName でリソースから、ApHello と言う名前のメニューをロードして設定します。
 lpszClassName でクラス名を指定し、hIconSm で小さなアイコンを指定します。そして、RegisterClassEx 関数でクラスを登録します。間違いがれば、0を返します。通常、コードに間違いが無ければエラーにはなりません。偶然に同じクラス名が登録されていれば、エラーになりますので、クラス名の命名には気を付けてください。

ウィンドウの作成

 クラスの登録が終われば、ウィンドウを作成します。CreateWindow を使用しますが、この関数は、システムで既に登録しているクラスである「コントロール」の作成にも使用しますので、非常にたくさんのバラエティがあります。しかし、コントロール関係以外は比較的簡単です。
    hWndMain = CreateWindow(pClassName,NULL,WS_OVERLAPPEDWINDOW,
                            CW_USEDEFAULT,CW_USEDEFAULT,
                            CW_USEDEFAULT,CW_USEDEFAULT,
                            NULL,NULL,hInstance,NULL);
    if (!hWndMain) return FALSE;
    SetWindowText(hWndMain,pAppName);
    ShowWindow(hWndMain,nCmdShow);
    UpdateWindow(hWndMain);
 CreateWindow 関数は、まずクラス名を指定してクラスを識別します。次のNULLは、ウィンドウのタイトルは設定しないことを示しています。SetWindowText 関数が後にありますが、これと同じ動作を行ないます。
 次がウィンドウのスタイルを設定するパラメータです。ウィンドウは、オーバーラップとポップアップ、そして子ウィンドウの3つの大きなタイプがあります。通常のアプリケーションのはオーバーラップウィンドウです。一時的な表示を行なうのが、ポップアップウィンドウで、ウィンドウの中に子ウィンドウを設定することもできます。
 つぎの4つが、起動時のウィンドウの位置とサイズです。矩形では無く左上の位置と幅と高さを設定します。すべて、CW_USEDEFAULT ですが、これはシステムのデフォルト値を指定します。これを指定すれば、スクリーンの解像度に合わせて適当な位置に、適当な大きさのウィンドウを作成します。実に、安直で無責任な指定です。普通はウィンドウの位置やサイズは、前回の終了時点を再現することが多いので、レジストリから読み込んで設定する方法が一般的でしょう。またここではすべて0を設定して、WM_CREATE やその他のメッセージで設定することもあります。
 次が親ウィンドウのハンドルです。NULL なのは、これがトップウィンドウで親が無いことを示します。前記の子ウィンドウを作成する場合に使用します。次ぎはメインメニューのハンドルを指定します。ApHelloではクラスでメニューを指定しますので、ここは NULL にします。hInstance でインスタンスハンドルを指定します。これはウィンドウはクラスとインスタンスに関連付けられていることを表します。つまりアプリケーションを終了し、インスタンスが破棄されると、このウィンドウも破棄されることを意味します。
 最後のパラメータは、WM_CREATE メッセージに渡すパラメータを指定します。ちょっと違うウィンドウの場合は、その違いをこのパラメータを通じて、プロシージャに知らせることもできます。この技法も良く使われています。

 CreateWindow はHWNDのウィンドウのハンドルを返します。NULL ならエラーですので終了します。SetWindowText 関数はウィンドウのタイトルを設定します。ApHelloの場合は、変更の必要がないので、CreateWindow の二つ目のパラメータで指定しても良かったのですが、データファイルを使う場合は、それをタイトルにしますので、通常は、SetWindowText 関数を使ってウィンドウのタイトルを設定します。
 CreateWindow のスタイルで、WS_VISIBLE を指定すると、この関数をコールしただけで、ウィンドウを表示しますが、この指定がないと表示は行ないません。実際には、ShowWindow 関数で表示します。ここのパラメータで、WinMainで説明したウィンドウの状態を指定します。この関数だけでも表示しますが、WM_PAINT メッセージはシステムのキューにたまり、やや遅れる可能性があります。よって、UpdateWindow 関数で直ちに表示を行ないます。メッセージやキューに関しては、メッセージループで説明します。

ページ移動