[level4] [ウィンドウ] [ HWND ] [ HINSTANCE ] [ MSG構造体] [Win32 データ型] [コールバック関数]
ウィンドウ
"HWND" は、ウィンドウハンドル型というデータ型 (型名) です。
HWND hWnd ; で宣言された変数 hWnd は、"ウィンドウ" を識別するための値である、"ウィンドウハンドル" を格納するための"変数"です。そして、hWnd に正しい ウィンドウハンドルが入っている上で、hWnd をもってして "ウィンドウハンドル" というのが通常です。だから、気づいた人もいるかもしれませんが、実はこの上のページ (level4) の説明は簡単すぎて少し誤りなのです。
hWnd の名前のつけ方はまったく自由ですが、この "hWnd" という変数名(識別子名)は、とくにローカル変数としては、ごく頻繁に使われます。
ここの構成は順に、
ウィンドウ
コントロール
ウィンドウハンドル
です。
ウィンドウ
さて、ウィンドウハンドルとは、ウィンドウを識別する値です。
ところが、ウィンドウとは、ウィンドウっぽいものとはわかっても、プログラムを組むんだったらもう少し正確なことがわからないと、ウィンドウハンドルはつかみどころのないものとなってしまいます。
スケルトンコードで現れるでっかいウィンドウもウィンドウ、ボタンコントロールやエディットコントロール、リストボックス、スクロールバー・・・etc などの コントロールアイテムもウィンドウとして扱うほか、ダイアログボックスもウィンドウ。 |
こんな分類はあまり重要ではありませんが、ウィンドウを扱う場合に即してわけると、おおよそこのような3つに分けてよいと思います。
あと少し特殊なものに MDI 子ウィンドウなどがあります。
トップレベルのウィンドウは、ウィンドウらしく見え、それは一つのウィンドウです。ダイアログボックスもウィンドウです。さらに、ボタンやエディット(記入欄) などのパーツ(部品)もすべて一つ一つ、 「コントロール」 と呼んで扱い、これらもウィンドウです。コントロールもコントロールアイテムもおなじです。( Windows API または、ウィンドウズという OS でのこと )
これらのウィンドウに関しては、これ以上のことは実際に使ってみるほかはありません。ここで詳しく説明することをわたくしはきらいます。とくに、機能豊富なコントロールのことを説明しようとすると、ついつい楽しくなってわたくしが脱線してしまうのです。
ここでは、ウィンドウハンドルにまとを絞って、以下のことが比較的大切です。
・ トップレベルのウィンドウ及びコントロールの作成には、 CreateWindow() か CreateWindowEx() 関数をつかう。・ そして、ダイアログボックスの作成には、CreateDialog() ( : モードレス) をはじめとする関数をつかう。 ・ ほかに、基本的なウィンドウ作成関数として CreateMDIWindow() がある。 |
ウィンドウハンドルは、ウィンドウを作成したとき、具体的にこれら "ウィンドウ作成関数"の戻り値として得られます。"モーダル(な)ダイアログボックス"用の、
DialogBox() 関数とその仲間だけ例外です。関数の 戻り値が HWND 型であることを確認しましょう。
次に、コントロールアイテムについて少しまとめておきましょう。
コントロール
あるウィンドウの上にコントロール(等)を作成すると (貼り付けると)、それぞれ 「親ウィンドウ」 と 「子ウィンドウ」 の関係になります。親ウィンドウ/子ウィンドウ の 「言い回し」 が要点です。そのほか、
・ (作成された)各コントロールには、コントロールID があるが、トップレベルのウィンドウとダイアログボックスには、コントロールID がない。 ・ コントロールID から ウィンドウハンドルを取得するときは、GetDlgItem() 関数を使う。この関数は親ウィンドウのハンドルも必要。 ・ コントロール と SendMessage() 関数はセット(不可分)。SendMessage() 関数はおよそ、"コントロールに特化した操作" のためにある。 ・ 各コントロールにおこったイベントは、親ウィンドウの、ウィンドウプロシージャ(WndProc) やダイアログプロシージャで受ける ( = "親"ウィンドウに知らされる。& そういう仕組みになっている )。 ・ コントロールを扱うときは、SendMessage() 関数と GetDlgItem() 関数は避けて通れない。 |
※ コントロールID については、すこし離れて以下に述べるところです。
色々な概観や機能を持つ以下のようなコントロールがあります。
[ 表 : 各コントロールとそのウィンドウクラス名 ]
コントロール名 | ウィンドウクラス名 | ||||||||||||||||||||||||||||||||||||||||||||||
標準コントロール ( 要 #include <windows.h> 。ただし正確には winuser.h ) | |||||||||||||||||||||||||||||||||||||||||||||||
スタティックコントロール | "STATIC" | ||||||||||||||||||||||||||||||||||||||||||||||
エディットコントロール | "EDIT" | ||||||||||||||||||||||||||||||||||||||||||||||
リストボックス | "LISTBOX" | ||||||||||||||||||||||||||||||||||||||||||||||
スクロールバー | "SCROLLBAR" | ||||||||||||||||||||||||||||||||||||||||||||||
コンボボックス | "COMBOBOX" | ||||||||||||||||||||||||||||||||||||||||||||||
拡張コントロール ( 要 #include <commctrl.h> ) | |||||||||||||||||||||||||||||||||||||||||||||||
リストビュー | "SysListView32" | ||||||||||||||||||||||||||||||||||||||||||||||
プログレスバー | "msctls_progress32" | ||||||||||||||||||||||||||||||||||||||||||||||
トラックバー | "msctls_trackbar32" | ||||||||||||||||||||||||||||||||||||||||||||||
ステータスバー | "msctls_statusbar32" | ||||||||||||||||||||||||||||||||||||||||||||||
タブコントロール | "SysTabControl32" | ||||||||||||||||||||||||||||||||||||||||||||||
ツールバー | "ToolbarWindow32" | ||||||||||||||||||||||||||||||||||||||||||||||
ツールチップ | "tooltips_class32" | ||||||||||||||||||||||||||||||||||||||||||||||
ヘッダコントロール | "SysHeader32" | ||||||||||||||||||||||||||||||||||||||||||||||
アップダウンコントロール | "msctls_updown32" | ||||||||||||||||||||||||||||||||||||||||||||||
ツリービュー | "SysTreeView32" | ||||||||||||||||||||||||||||||||||||||||||||||
拡張コンボボックス | "ComboBoxEx32" | ||||||||||||||||||||||||||||||||||||||||||||||
アニメコントロール | "SysAnimate32" | ||||||||||||||||||||||||||||||||||||||||||||||
ホットキーコントロール | "msctls_hotkey32" | ||||||||||||||||||||||||||||||||||||||||||||||
日付時刻コントロール | "SysDateTimePick32" | ||||||||||||||||||||||||||||||||||||||||||||||
(月間)カレンダーコントロール | "SysMonthCal32" | ||||||||||||||||||||||||||||||||||||||||||||||
レバーコントロール | "ReBarWindow32" | ||||||||||||||||||||||||||||||||||||||||||||||
リッチエディット(参考) | "RichEdit" , "RichEdit20A" |
コントロール名称は若干いい加減なところがあります。(〜コントロールをつけたりつけなかったり)
上の表で紹介したものは、「CreateWindow(
[MSDN] "コントロール" |
[MSDN] リソーススクリプトでの"CONTROL" |
[わたしのまとめたもの] (データベース) |
ウィンドウハンドル
ウィンドウはだいたいこんなところで、作成されたウィンドウそれぞれを表す 「値」 がウィンドウハンドルです。上のようなおよそ3つの分類を挙げましたが、分け隔てなく同じ 「HWND 型の変数 : ウィンドウハンドル」 によって識別されます。たとえば、SetWindowText() という関数は、ウィンドウにテキストを表示する関数です。この関数は、SetWindowText( hWndEtc , "おはよう!" ) ; のように使用します。hWndEtc はウィンドウハンドルでありさえすれば上のいずれの種類のウィンドウでもよく、ダイアログボックスや一番親 (トップレベル) のウィンドウなら、ウィンドウのタイトルのところに "おはよう!" と表示されるし、コントロールアイテムでいえば、ボタンならボタンの表示テキストが、エディットコントロールならエディット部のテキストが・・・・・、といった具合に、どれもテキストが表示されるのです。SetWindowText() 関数は特にどのようなウィンドウにも使える汎用的な関数です。この例によらず、ダイアログボックスのウィンドウハンドルだけしか受け付けないような関数ももちろんあります。
[ウィンドウハンドルとコントロールID]
ウィンドウハンドル の値を「取得」 するには、自分でウィンドウを作ったときに戻り値として得たり、または他の手段で得ます。一方 「使う」 のは、そのウィンドウに直接命令を出したり、そのほか間接的な意味で指定を要する場合です。「使う」 局面は特に多岐にわたります。さらに、各"子"ウィンドウ作成時には、つまり CreateWindow() 関数を使うときは、基本的には、任意のID番号を自分でつけます(この関数のパラメータとして指定する)。これが コントロールID (ウィンドウID) という値です。こちらもウィンドウを識別するための値です。コントロールID は、ウィンドウに一意ではありません。コントロールID だけからウィンドウを特定したりもしくはウィンドウハンドルを得ることはできない、ということです。GetDlgItem() 関数でウィンドウハンドルを得るのに、親ウィンドウのハンドルとコントロールID の両方が必要なことからもわかるとおり、子ウィンドウは、この2つがあってはじめて特定されるものです。注意するというよりも、このことを利用して、とくにリソーススクリプトなどでは、上手に コントロールID を付けていきましょう。
[いろいろなウィンドウと、ウィンドウハンドル]
平均的なことを考えると、アプリケーション中一番多いウィンドウは、圧倒的な数でコントロールアイテムです。インターネットエキスプローラ(IE) のブラウザなどを眺めてみると、ボタンも沢山ついているし、コンボボックスがあり、スクロールバー、ステータスバーがあります。そして、そのアプリケーションのコントロールの数だけウィンドウハンドルがあることになります。ただ、それをプログラム中で変数例えば HWND hButton ; を宣言して hButton にそれを代入して確保しておく必要があるかというと、それはそのとき次第です。ウィンドウ作成関数はウィンドウハンドルの値を 「戻り値」 として "返し" ます。が、プログラム上でその値を放置するか確保するかは自由だということです。実際には重要な(プログラム中で頻繁に取り扱う)コントロールアイテムのウィンドウハンドルだけは確保しておけばよく、あとのものは、GetDlgItem() 関数に 親ウィンドウのハンドルとコントロールID を指定すれば、いつでもウィンドウハンドルを得ることができるから、必要なたびにその値を工面するくらいでいいとおもいます。
ここで、ダイアログボックスやトップレベルのウィンドウは、コントロールID を持ちません。それ以外、およそコントロールアイテムには コントロールID という識別番号がつきます。
たいしたやりくりではありませんが、いっそのことすべてのウィンドウハンドルを変数に格納することなどを考えると、プログラムが変数だらけになってしまうから、結局自分のために、プログラム中の HWND 型 ウィンドウハンドル変数の数を、適切に抑えなければいけないということなのです。
[ウィンドウハンドルの正体と、ウィンドウ]
さて、ウィンドウハンドルの実体は、32 ビット値です。そのことは wsprintf 関数など使って実験してみれば容易に確かめることができます (インスタンスハンドルも)。そしてさらに、これはポインタです。そのポインタの指す先には、Windows API に定められたデータ形式で、 「ウィンドウ」 を管理するためのデータが広がっています(あります)。ただし、プログラミング中このポインタの示すアドレスへのアクセスがプログラマーから直接必要となる場面は一度もありません。正式には、ここで言っている 「ウィンドウ」 とは、左のようなことのもとに管理されている 「もの」 ということになってしまうのです。簡単に説明しようとしているわたくしにとってはとても痛い話です。実際、ShowWindow() なんていう関数を使えば、ウィンドウは簡単に見えなくできるし、CreateWindow() で作成したはじめから見えないウィンドウ、なんていうものもあるから、本当にただしく説明するとなると、「ウィンドウらしきもの」、といいたいところが、これさえあいまいな表現であるにこれすらも言えず、その Windows API の構造体でかんりされる 「もの」 くらいにしか言えなくなってしまいます。プログラミング中出会うことはありませんが、そして、HWND はそれへの 「ポインタ」ではありますが、「ウィンドウ定義構造体」 というものが必ずあるはずです。
GUI にとって、ウィンドウはなにが大事かって、つかんで移動することが本来の持ち味です。ウィンドウのタイトルが表示されるから「タイトル部分」ということもあるけれど、この部分はほんとうは、「キャプション」 (Caption : つかむところ) という呼び名がついています。キャプションのないスタイルのウィンドウにすることもできます。( CreateWindow() の、ウィンドウスタイルから WS_CAPTION をはずす )。だから、ウィンドウとはつかんで移動するもの、のように説明しようとしても、これもやっぱり説明不足なのです。
[コントロールと SendMessage() 関数]
コントロールの操作には SendMessage() 関数が欠かせません。その説明は ウィンドウハンドルの"実際" (HWND) で。
このページで中心的だった関数はたかだか、CreateWindow()、CreateWindowEx()、CreateDialog()、DialogBox()、GetDlgItem()、SendMessage() です。