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

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

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

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

ページ移動

2-1-3. クラスとは何か

 「クラス」とは、良く使う言葉です。種類・階級・学級と言う意味ですが、C++のクラスライブラリにも使います。しかし、WindowsのAPIに関するクラスとは、RegisterClass 関数で登録した内容と言っても良いでしょう。クラスとは、正確にはウィンドウクラスと言います。ウィンドウを作成するためには、予めクラスを登録して置かねばいけないからです。ウィンドウはクラスなしでは、存在しえません。メッセージボックスやコントロールなど、クラスを登録せずにウィンドウを表示するAPIは多数あります。しかしそれらは、システムがクラスを登録する作業を代行しているに過ぎません。例外はありません。

 しかし残念ながらウィンドウクラスは、RegisterClass 関数だけを調べれば、理解できると言う訳にはいきません。クラスを正しく理解するには、ウィンドウプロシージャやメッセージを含んだ、Windowsのウィンドウ管理の仕組みを理解する必要があります。

クラスとプロシージャとメッセージ

 RegisterClass 関数はいろいろなパラメータを設定しますが、一番重要なパラメータは、ウィンドウプロシージャを定義することです。ウィンドウプロシージャは、ユーザが作成する関数のことで、そのポインタを RegisterClass 関数で設定します。プロシージャは、Windowsがコールを行なうため、ある決まったパラメータと決まった処理を行なわなければいけません。つまり仕様に従ってコーディングする必要があります。システムの内部構造に直結した機能です。システムがコールする関数をプロシージャと命名します。またはコールバック関数と言うこともありますが、Windowsシステムではなく、ユーザが同等な構造を作成してもこの言い方は通用します。プロシージャはたくさんあります。ダイアログボックス、Enum系関数、ウィンドウズフックなどなどです。よってクラスで登録するのは、ウィンドウプロシージャと呼びます。

 ではシステムは、いつ・どんな場合に・どのような形式でウィンドウプロシージャをコールするのでしょうか。これの答えがメッセージです。ウィンドウをキーやマウスで操作した時や、ウィンドウの作成や操作などを行なうAPIをコールした時などにコールします。それもメッセージと言う、ある決まったデータ形式に、コンパクトにまとめた形式にします。例えば、WM_CREATE はウィンドウを作成した時、WM_MOVE は移動、WM_SIZE はリサイズ、WM_MOUSEMOVE はこのウィンドウの上をマウスカーソルが移動した時に発生します。これらのメッセージは、システム内のキューと言う先入れ先出し(FIFO)のデータ域に蓄えられます。システムが行なうのはここまでです。キューからメッセージを受け取り、それをメッセージごとに異なった処理を行なったり、プロシージャに配信したりする処理は、通常WinMainの関数内でユーザが処理します。この処理は、メセージを得てプロシージャに配信する作業を繰り返しますので、メッセージループと呼びます。詳しくは、APIの基本の「1-3-6. メッセージループ」をご覧ください。メッセージのことは、APIの基本の「1-3-7. メッセージ」もご覧ください。

ウィンドウクラスの属性

 クラスは、プロシージャだけでなく、いろいろなウィンドウの属性も規定します。登録時にだけ設定可能な属性もありますが、大部分は後で変更できます。

ウィンドウクラスのスタイル

 ウィンドウクラスには、いろいろなスタイルを付加できます。詳細は、クラスの登録をご覧ください。
  • ウィンドウのクライアント域をバイト境界に揃えて描画を高速化する。
  • ウィンドウをバイト境界に揃えて、移動やサイズ変更を高速化する。
  • デバイスコンテキストを共有化することで、効率化を計る。
  • ダフルクリックを可能にしメッセージを発行する。
  • アプリケーショングローバルクラスであることを明示する。
  • 横か縦方向にサイズ変更した場合に、ウィンドウ全体を再描画する。
  • [閉じる]コマンドとコントロールメニューを使用不能にする。
  • 一意なデバイスコンテキストを割り当てる。
  • 親ウィンドウのデバイスコンテキストを子ウィンドウに与える。
  • 隠されたウィンドウの画面イメージをビットマップとして保存し、描画時に WM_PAINT を発行しない。

ウィンドウクラスの運用

 ウィンドウクラスは、RegisterClass 関数で登録します。ちなみに、ウィンドウは「作成」すると言いますが、クラスは「登録」するといいます。こんな言い方をするのは、たぶんウィンドウと違って表示する「物」が無いからでしょう。
 ウィンドウクラスは、CreateWindow 関数で使用されます。つまりウィンドウは、クラスの情報と、CreateWindow のパラメータに従って作成されます。その場合は、クラスは名称で識別します。クラスにハンドルはありません。またクラスを使用する関数は、CreateWindow 関数が大部分です。例外的に登録したクラスの情報を得る、GetClassInfo 関数もありますが、あまり使うことはありません。
 登録したクラスは、UnregisterClass 関数を使って解除します。解除すると、クラスに関連付けられていたメモリ領域を解放します。

 なおWIN32のAPIの場合は、RegisterClass の変わりに、RegisterClassEx を使用します。また、CreateWindow の拡張機能に、CreateWindowEx 関数もあります。

ウィンドウクラスの種類

 ウィンドウクラスは、3つの種類があります。システムグローバル、 アプリケーショングローバル、 アプリケーションローカルのクラスです。これらのクラスは、その適用範囲や、 登録と破棄の時期、およびその方法がそれぞれ異なります。
■ システムグローバルクラス
Windowsは、ボタン、コンボボックス、リストボックス、スクロールバー、エディットコントロール、およびスタティックなどのコントロールをサポートします。これらは、便利なGUIツールですが、実体はシステムが登録したウィンドウクラスです。システム内のプロシージャでこれらの機能を実現しています。これらのコントロールのためのクラスを「システムグローバルクラス」と言い、任意のアプリケーションが、いつでも使うことができます。Windowsは、すべてのアプリケーションのためにシステムグローバルクラスを登録しているため、 アプリケーションが、これらのクラスを破棄することはできません。

■ アプリケーショングローバルクラス

「アプリケーショングローバルクラス」は、ダイナミックリンクライブラリ(DLL)が登録するウィンドウクラスです。システム内のすべてのアプリケーションから利用できます。たとえば、カスタムコントロールをアプリケーショングローバルクラスとして定義すれば、すべてのアプリケーションが、そのカスタムコントロールのインスタンスを作成できるようになります。ウィンドウクラスは、すべてプロセス固有のものになります。アプリケーシは、DLL内でウィンドウクラスを作成し、そのDLLの名前をレジストリの次のキーの下に登録することにより、グローバルクラスを作成できます。
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\ CurrentVersion\Windows\APPINIT_DLLS
プロセスが起動すると、システムは新しく起動したプロセスのコンテキスト内で指定のDLLをロードしてから、プロセス内のメイン関数を呼び出します。DLLはその初期化処理の間にクラスを登録し、CS_GLOBALCLASS スタイルを指定しなければなりません。クラススタイルについて詳しくは、クラススタイルを参照してください。クラスが登録されると、アプリケーションはそれを使って、そのクラスに属するウィンドウをいくつでも作成できるようになります。
Windowsは、アプリケーショングローバルクラスを登録したDLLがアンロードされるときに、そのクラスを破棄します。このため、そのクラスに属するウィンドウを使用しているすべてのアプリケーションは、DLLがアンロードされる前に、そのウィンドウを破棄しなければなりません。これには、UnregisterClass 関数を使ってアプリケーショングローバルクラスを削除し、クラスに関連付けられていたメモリ領域を解放します。

■ アプリケーションローカルクラス

「アプリケーションローカルクラス」は、アプリケーションが専用のクラスとして登録するウィンドウクラスです。アプリケーションは、ローカルクラスをいくつでも登録できますが、通常は1つだけを登録します。このウィンドウクラスは、アプリケーションのメインウィンドウのウィンドウプロシージャをサポートします。
ローカルクラスの登録は、アプリケーショングローバルクラスのそれと同様ですが、WNDCLASS 構造体の style メンバに、CS_GLOBALCLASS スタイルを指定しない点が異なります。Windowsは、ローカルクラスを登録したアプリケーションがクローズされると、そのクラスを破棄します。また、アプリケーションは、UnregisterClass 関数を使ってローカルクラスを削除し、クラスに関連付けられていたメモリ領域を解放することもできます。

ウィンドウクラスの所有権

 クラスのオーナーは、そのクラスを登録したアプリケーションまたは、DLLになります。Windowsは、クラスの登録時に、RegisterClass 関数に渡される WNDCLASS 構造体の hInstance メンバから、クラスの所有権を決定します。WindowsのDLLでは、hInstance メンバは必ずDLLのインスタンスハンドルでなければなりません。クラスは、そのオーナーがクローズするときや、アンロードされるときに破棄されます。このため、クラスに属するウィンドウを使用しているアプリケーションは、クローズする前、または、DLLがアンロードされる前に、それらのウィンドウをすべて破棄しなければなりません。

補足メモリブロックの使用

 ウィンドウクラスを作成する時に、WNDCLASS 構造体の cbClsExtra,cbWndExtra の2つのメンバ変数は、非常におもしろい機能を提供してくれます。この変数には、メモリのサイズを設定します。そして、cbClsExtra には、クラスに、cbWndExtra にはウィンドウに関連付けて、ユーザが自由にメモリブロックにデータを設定し取得できます。SetClassLong,getClassLong や SetWindowLong,GetWindowLong の関数で設定や取得を行ないます。

 これはコンポーネント技術を考える上で非常に重要な機能です。ウィンドウプロシージャで、ウィンドウのユーザの指定する特別機能を識別したり、ウィンドウに密接に関連するデータを設定するのに非常に便利です。

ページ移動