[index] [MS-DOS] [はじめに] [level1] [level2] [level3] [level4]


Windows API プログラミング
特有の言葉

 

ネット上のサンプルで折角説明してくれてるのにさっぱりわけのわからない言葉たち。

 

 ここまではコンパイル作業におけることでしたが、それとは区別して、具体的にプログラムを組む際の「言葉」 を見ていきたいと思います。完全に無関係であるとは言いきれない部分もありますが、プログラミングを書く際のこととしてまとめてしまってもいいだろうと思われること等です。プログラミングといってつまりは何を書けばいいんだ!というなげやりな問いかけに対しては答えということになります。冒険の道筋に従って上から正しい順番で構成されています。また、色づけは面白半分でしているものではありません。

 

 

 (Windows API (Win32 API)と C/C++ のプログラミングでは) 書くものは、ソースプログラム(.cpp や .c)リソーススクリプト(.rc)ヘッダファイル(.h)3点としておくのがふつうです。これらのうち 「これは必ずしも必要でない」 とか、「結局 .cpp だけでもやれる、またはやれなくはない 」 とか、理屈もすこしありますので、強情なひとのためには、それらは以下の中で再度説明を加えることにします  

 

 以下で中心となるのは、 ソースプログラム(.cpp)リソーススクリプト(.rc) 2点に関しての、具体的なコーディング作業での 「言葉」 です。リソーススクリプトとは初耳にして多少反則かもしれませんが、このような反則はここで終了です。また、残り1点の、ヘッダファイルの「記述」 に関してはたいして述べることがありません。まぁ、見ていきましょう。主にで太で書かれているものは、いわば 「Windows API 語」です。

 

 また、ここに来てはじめて、以下で "ウィンドウ" と言っているものはいったいなんなのか知って、API のプログラミングだとそんなことが出来るのか、ということを知ってもいいと思います。

 


 

 [これ]スケルトンコードです。
 もちろんソースコード(.c 又は .cpp)です。
 C/C++ と Windows API でプログラムを書く際のものです。

 ここにたどり着くとようやく、いよいよプログラミング開始、という気がしてきます。 スケルトンコードは、これから何かアプリケーションを作るときはいつも土台になるもの [土台?] ですが、同時に、これをそのままコンパイルすると、特になにをするわけでもないがでっかいウィンドウが一つ出てくるアプリケーション、を作ることもできます。一息つくにはいい材料ですが、ここにたどり着くまでが大変だった、ということもあるでしょう。ここでもまだ、「何もしないアプリケーション」 なんてものに付き合わなくてはならないなら、[それよりはこっちのほうがマシ]。 先に進みましょう。

 

 みてみると、大文字のなにやら書いてあるもの (HWND など) があります。少しくらいわかる人ならこれが、「データ型 : (宣言シンボル)」 であることがわかると思います。あちこちに分散しているから把握に一苦労ですが、わたくしがかわりにピックアップしてみるとせいぜい、

HWND、HINSTANCE、MSG、LPARAM、WPARAM

です。このうち、さしあたり説明を要するのは、HWND、HINSTANCE の2つです。スケルトンコードを眺めてみないことにははじまりませんが、HWND hWnd ; の hWnd はウィンドウハンドル、HINSTANCE hAppInst ; の hAppInst はインスタンスハンドルといいます。特に、ウィンドウハンドル"ウィンドウ" を識別するための値で、左の例は "HWND 型の変数 hWnd" ということもできます。ここでは出てきませんが、ウィンドウを識別するための値としてもう一つ、コントロールID もあります。一つの "ウィンドウ" を識別するのに2つの値があることになりますが、あまり混乱せず、2つセットで考えておきます。せっかく説明を用意しました [HWND] [HINSTANCE] 。とくに インスタンスハンドルは、思いがけなく必要となる場面があるので、少し見ておかないとそのときになっててんてこ舞いをします。マチガイない(2005/1)。・・・"マチガイない" とかはどうでもいいから、そもそも ウィンドウってなに?

 

 その他の、MSG 構造体などは、それこそおまじないと思っておきましょう。Windows API により意識せずに処理されているメッセージを、[奪ってしまおう] というときは若干内容を見る必要がありますが、それでもせいぜい4つの主要メンバ(と実は2ないし3メンバ)を持つ構造体です。 また、LPARAMWPARAM に至っては、意味も実体も、 32 ビット値の整数であって、両者を役割の上から区別するとおおざっぱには、WndProc 内をはじめとするメッセージ処理における、整数値パラメータとしての、右手と左手、くらいの区別です。

 更に、WNDCLASS 構造体なども見られます。これも型宣言子(構造体)ですが、このあたりになってくると、これは、具体的な関数、 RegisterClass() を使用する際に必要になる構造体で、関数とペアになって説明されます型の大半は、"特定の関数" と深く結びついて使用されます。だから、いろんな型があるとはいえ、関数の説明と併せて記されている説明や関連事項をあてにしていればよいので、あまり心配することはありません。

 "WinMain" は Win32 API における、固有な名前のエントリー関数です。また、"WINAPI" はデータ型(型宣言子)というよりは、「型修飾子」の部類です。<windef.h> [...more ]

 

Windows API のデータ型 [構造体と32ビット値]、加えてハンドル(なんとかハンドル)について。

 

 ひといきついて、おおきく眺めます。スケルトンコードの中での処理の流れは、複雑でばらばらな処理の連続のように見えて、ほんとうのところは大きく、メッセージループウィンドウクラスの登録処理、ウィンドウプロシージャ の3つから成り立っています [3つのおいたち] 。実際の、ソースプログラムにたいする主なプログラミングの作業は、ウィンドウプロシージャ に対するコーディングです(若干不正確)。通常はじめは、 [これら3つ] の細かいことには立ち入りません。

 

ダイアログボックスとメニューと、リソーススクリプト

 ソースプログラム(.cpp)のほかに書く(べき)ものとして、リソーススクリプト (.rc) があります。リソーススクリプトには、ダイアログボックス [?] メニュー [?] などのデザイン (どんなコントロールアイテム(子ウィンドウ) [?] を貼り付けるとか、表示される文字はどうするとか)、について記述します。これら、リソーススクリプトやダイアログボックスを使わない場合はリソーススクリプトは必要ありません。リソーススクリプトも、書いてコンパイルするもので、その点はソースプログラムとかわりません ( これもまたコンパイルするのかよ・・・ )。ただ、なんらかの一連の"処理の流れ" が書かれているソースプログラムにくらべ、リソーススクリプトは、ダイアログボックスやメニューのデザイン(定義)などを単に記述してあるだけなので、「プログラム」 と呼ばずに、「スクリプト」 といいます。でも、プログラムの流れがあっても VB のプログラムは 「VBスクリプト」 などとも言うし、あまり正確な説明ではありませんね。

 さて、C/C++ 言語 (ソースプログラム) の文法の世界はメジャーであるのに対し、リソーススクリプトの文法の世界はマイナーです。正式な資料を得たい場合は、MSDN[ここ] をあたります。また、リソーススクリプトに関しても、いちいち文法的なことを把握しながら1から構成していかず、修正や追加ですすめていくスケルトンコードのような [考え方] でやっていけます。そうそう、"リソースエディタ" というツールがあって、ダイアログボックスをビジュアルデザインでき、リソーススクリプトを出力してくれます。IDE には標準で付属するのが普通ですが、無料のものもあるようです。わたくしには自分で作ってしまったリソースエディタがあります。ごり押しで作りましたが C 言語のべんりさを知るにはいい機会でした。

 

 リソーススクリプトにデザインを記述するものの代表的なもの※としては、ダイアログボックス [DIALOGテンプレート] や、メニュー [MENUテンプレート] があります。念のため、ダイアログボックスは 「メッセージボックス」 とは異なります。ダイアログボックスを 「呼ぶ」 のには、それはソースプログラム内での記述として例外ではなく、そのための主要な関数として CreateDialog() 関数 (モードレスダイアログ用) や DialogBox() 関数 (モーダルダイアログ用) があります。この関数のパラメータの一つに、あらかじめリソーススクリプト内に記述しておいたダイアログボックスの、「ダイアログボックス名」 を指定します。メニューは、LoadMenu() 関数。この関数にはおなじように、 「メニュー名」 を指定します。詳しくはそれぞれの関数リファレンスを参照します。

 

 ダイアログボックスに関しては、それを使うためには、ソースプログラム中の「"関数"を使って呼ぶ」 部分に加えて、おなじソース中、 ダイアログプロシージャ (place-holder : DialogProc() ) も記述する必要があります。これは ウィンドウプロシージャ (place-holder : WindowProc() ) と同じ仲間だと考えて大丈夫です(コールバック関数)。また、ダイアログボックスもまた、HWND 型の変数 : ウィンドウハンドル によって管理・識別される"ウィンドウ"です。

 結局、ダイアログボックスの要点は、CreateDialog() 関数(など) と、ダイアログプロシージャ(要プロトタイプ宣言)、そして、リソーススクリプト の [3点] です。補足としては適宜ヘッダファイルを作って、その中で #define 文によりコントロールID の定義を行います。

 さらに、リソーススクリプトのテンプレートから CreateDialog() なりで作ったダイアログボックスに、追加的に、プログラムの上から(programatically) に コントロールアイテムを付け加えることももちろん可能です。

 そして最後に、張り付いたコントロールアイテム (子ウィンドウ) のウィンドウハンドルを得るには、GetDlgItem() 関数によることを付け加えておきます

 

 ※ リソーススクリプトに記述するものとしては、ダイアログボックス (DIALOG、DIALOGEX)、メニュー (MENU)、アクセラレータ (キーボードのキーと、整数値 (メッセージID) を対応させるためのもので、"ショートカットキー" の考え方です。)、ストリングテーブル、ビットマップ・アイコン・カーソル・など [ これらはリソーススクリプトに、文法に従い、ビットマップファイルなどの "ファイル名" を記述するのみ]、など。

 補1 リソーススクリプトの文法は C/C++ の文法とは基本的に違うものですが、#include 指令は使えます。そしてリソーススクリプトの先頭に、#include <windows.h> と #include <commctrl.h> は常に記述しておくのが無難です。さもないと、IDOK や IDCANCEL また、ウィンドウスタイル ( WS_HSCROLL など ) といったシンボル定数が使えません。

 補2 リソーススクリプト内には、1つ1つのダイアログボックスやメニューを、かたまりのようにして、つぎつぎ書いていきますが、スクリプト内のそれぞれ1つの記述の部分、またコンパイルされたものの実体中のそれぞれの部分、とかまた、メモリ中に構成された構造体、を指して、ダイアログテンプレートとか、メニューテンプレート、と表現します。そして、平易には 「ダイアログボックスの名前」 であるところ、(ダイアログ) テンプレート名 のように述べられる場合があります。

 


 "最終的に"、ソースファイル、リソーススクリプト (およびヘッダファイル) を書き上げたら、

 

 bcc32 -tW myprog.cpp
 brc32 -iC:\borland\bcc55\include myprog.rc myprog.exe

 

で、すべての作業は終了します。よりスマートにやるには、make.exe ユーティリティーや、バッチファイルの使用も考えてみてください。

 後者の brc32 は、リソーススクリプトのコンパイル、と、そのコンパイルしたもの (オブジェクト) を、.exe にくっつけること (リンク) を同時にとりおこなってくれるユーティリティです。後者の 「リンク」 を行わなければ、リソーススクリプトに記述されたダイアログボックスやメニューを表示する段階で、うまく動作しないでしょう。ただ、リンクを行わなくても、出来上がったものは実行ファイルとしては有効です。※ bcc 5.5.1 フリーコンパイラにおけるやりかたです。また、リソーススクリプトを使わない場合は、後者の作業は不要です。

 

 あたかも、ダイアログボックスやメニューの使用には、リソーススクリプトが必須、のように見えて、結論は、リソーススクリプトをまったく記述しなくても、ダイアログボックスやメニューの使用は可能です。特に、メニューに関してはときおり、プログラム内でダイレクトにメニューを作ってしまうことが比較的容易です ( CreateMenu() AppendMenu() )。ダイアログボックスに関しては、こちらは容易ではありませんが、 CreateDialogIndirect() 関数があります。これをつきつめると、リソーススクリプトは必要ないし、ヘッダファイルさえも、ソースプログラムの先頭に書き写してしまえば要らなくなるから、.cpp ソースファイル一本でプログラムが書ける、という結論になります。

 

 最後に。ヘッダファイルは、ソースプログラムと、リソーススクリプト にまたがって、両者から同時に共通してインクルードされるという形で、使用されます。"コントロールID の定義" は、#define 文により、ソースプログラムとリソーススクリプトの"両方"に、「#define ID_EDIT 100」 のように記述することにより、ヘッダファイルによらないことが可能です。一時的、応急措置的な方法として利用できます。でも、普通はヘッダファイル、例えば "myprog.h" に、 「#define ID_EDIT 100」 セミコロン「;」 は要らない。 を書いておいて、ソースプログラムとリソーススクリプトの両方から、「#include "myprog.h"」 のようにします。

 

 

[トップ] <<前へ 次へ>>