|
|
|
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. メッセージ」もご覧ください。 ウィンドウクラスの属性 クラスは、プロシージャだけでなく、いろいろなウィンドウの属性も規定します。登録時にだけ設定可能な属性もありますが、大部分は後で変更できます。 ウィンドウクラスには、いろいろなスタイルを付加できます。詳細は、クラスの登録をご覧ください。
ウィンドウクラスの運用 ウィンドウクラスは、RegisterClass 関数で登録します。ちなみに、ウィンドウは「作成」すると言いますが、クラスは「登録」するといいます。こんな言い方をするのは、たぶんウィンドウと違って表示する「物」が無いからでしょう。ウィンドウクラスは、CreateWindow 関数で使用されます。つまりウィンドウは、クラスの情報と、CreateWindow のパラメータに従って作成されます。その場合は、クラスは名称で識別します。クラスにハンドルはありません。またクラスを使用する関数は、CreateWindow 関数が大部分です。例外的に登録したクラスの情報を得る、GetClassInfo 関数もありますが、あまり使うことはありません。 登録したクラスは、UnregisterClass 関数を使って解除します。解除すると、クラスに関連付けられていたメモリ領域を解放します。 なおWIN32のAPIの場合は、RegisterClass の変わりに、RegisterClassEx を使用します。また、CreateWindow の拡張機能に、CreateWindowEx 関数もあります。 ウィンドウクラスは、3つの種類があります。システムグローバル、 アプリケーショングローバル、 アプリケーションローカルのクラスです。これらのクラスは、その適用範囲や、 登録と破棄の時期、およびその方法がそれぞれ異なります。
■ アプリケーショングローバルクラス
Windowsは、アプリケーショングローバルクラスを登録したDLLがアンロードされるときに、そのクラスを破棄します。このため、そのクラスに属するウィンドウを使用しているすべてのアプリケーションは、DLLがアンロードされる前に、そのウィンドウを破棄しなければなりません。これには、UnregisterClass 関数を使ってアプリケーショングローバルクラスを削除し、クラスに関連付けられていたメモリ領域を解放します。 ■ アプリケーションローカルクラス
ローカルクラスの登録は、アプリケーショングローバルクラスのそれと同様ですが、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 の関数で設定や取得を行ないます。これはコンポーネント技術を考える上で非常に重要な機能です。ウィンドウプロシージャで、ウィンドウのユーザの指定する特別機能を識別したり、ウィンドウに密接に関連するデータを設定するのに非常に便利です。
|