SDK で行こう!
Win32 プログラミング入門
もくじ
はじめに
ということで何となくWin32プログラミング講座開いてみました。 今日び Win32 プログラミングと言えばやれ C++ だの MFC だの STL だの C# だの COM だの COM+ だの DCOM だのってようわからんことになってますが、やっぱ基本は SDK! 何事も基本を押さえとかなきゃあきません。
ちなみに SDK ってのは Software Development Kit の略(だったと思う)で、 正確には開発キットの名前(元々 Win32 SDK と呼ばれていた(ような気がする)ものが 最近はいろいろ入って Platform SDK と呼ばれているみたい)だと思うのですが、 結局そのキットにはライブラリ(とヘッダファイル)しか含まれていなかったので、 コンパイラとSDKだけでプログラム作ることを SDK プログラミング、略して SDK と呼ぶようになったみたいです。 なのでここでもそういう感じで SDK って言葉使ってますので悪しからず。
ちうことでここでは一応 C 言語は知ってるけど Windows プログラミングはよくわからん、という人を対象に話していくつもりです。
あ、あと方針として「用語などはあくまでも僕が普段使っているものを基本」 としますので、使い方間違ってたりするかもしれません。 でも大抵ちょっとぐらい間違っててもプログラム組む上で困ることはまずありません(だって僕がそうだから)。 なので細かいところは気にしない気にしない。 まぁ、一応わからんとことか「ここはさすがに間違いやろ」みたいなことがあればサポートページ用意してます(談話室の中です)のでそこに書いてみてください。
開発ツールをダウンロードしよう!
で、開発ツールには Borand (インプライズ)の C++ Compiler を使うことにします。 理由はただだからです。 フリーなコンパイラとしては他にも GNU の GCC とかが有名ですが、 Win32(GUI) なプログラムを作るのにはあまり向いていません。
ということで早速 インプライズのホームページ から、コンパイラをダウンロードしましょう。「製品情報」のところにある、「C++ Compiler」ってやつです。ちょっとサイズでかいですけど(約9M)がんばってね。あ、ソフトバンク社のCマガジンにもついてたりするみたいですので、そっち買った方が早いかもしれません。
まずはやっぱり...
「Hello World」ですね ^^; とりあえず出してみましょう。 コンパイラのインストールはお済みでしょうか? では以下のプログラムをコンパイルしてみてください。
C:\SDK\>bcc32 hello.c
ってな感じです。
#include <windows.h> int main( int argc, char **argv ) { MessageBox(NULL, "Hello World!", NULL, MB_OK); return 0; }
コンパイルできたら実行してみましょう。出ましたか? もうおわかりかと思いますが、このプログラムで使ってる唯一の関数 MessageBox() ってのがメッセージを表示する関数なわけです(Win32 API とか呼ばれます)。
MessageBox() に渡してる引数の説明をしておきましょう。 MessageBox() は四つの引数を受け取ります。順に
- 親ウインドウハンドル
- 表示文字列
- タイトル文字列
- オプション
となってます。表示文字列とタイトル文字列はわかりますよね? ちなみにこの例のようにタイトル文字列を指定しない(=NULL)と デフォルトの「エラー」というタイトルが使われます。 オプションってのは表示するボタンの種類(OKとかキャンセルとか、はい/いいえにするとか)やアイコンの表示を指示するものです。フラグの組み合わせになってます。
では最後に残った親ウインドウハンドルってのはなんでしょう? 親のウインドウのハンドル、ということなんですが、 その前に Windows における「ウインドウ」についてちょっと説明しておきます。
ウインドウって?
Windows において画面上に配置される GUI 部品は、 タイトルバーがあるいわゆるウインドウはもちろんのこと、 プッシュボタンやチェックボタン、文字入力用のテキストボックス全て 「ウインドウ」です。 で、種別によって見栄えや処理を変えているわけです。
これら全てのウインドウを識別するのに、Windows プログラムでは「ウインドウハンドル」と呼ばれる値を使うわけです。まぁ要はウインドウの番号みたいなもんです。 つまり MessageBox() ではメッセージボックスを表示する親元のウインドウを指定していたわけです。 例では NULL を指定していたため親はいないことになっていましたが、 親ウインドウを指定した場合は、メッセージボックス表示中は 親ウインドウでは他の一切の入力を受け付けなくなります(これを「モーダルウインドウ」と言います)。
それでは試しにウインドウを作ってみましょう。 以下のサンプルをコンパイルして実行してみてください。
あ、その前に。先ほどのサンプルは実はいわゆるコンソールアプリというやつでした。 エクスプローラーとかからダブルクリックしたりすると MS-DOS プロンプト とか コマンドプロンプトとか言われるウインドウが開いちゃうやつね。
今度のは純粋な(?) GUI アプリなのでコンパイル時にそのように指示する必要があります。
C:\SDK\>bcc32 -tW hello.c
のようにやってください。じゃないとリンカに怒られます。 このあたりの細かい話はまた機会があれば...
#include <windows.h> #define SZ_CLASSNAME "sampleWindow" LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow ) { WNDCLASS wc; HWND hWnd; MSG msg; wc.style = 0; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = SZ_CLASSNAME; if (!RegisterClass(&wc)) { return -1; } hWnd = CreateWindow(SZ_CLASSNAME, "サンプルウインドウ", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return -1; } ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }
うーん、一気にコード量が増えてしまいました... だから Windows プログラミングってイヤなんだよなぁ... ^^;
まぁそれはサテオキ、実行してみてください。真っ白なウインドウが表示されましたか? これが基本です。あとはこれにいろいろ付け足していけばオッケー。 ってなわけで入門編はこのへんで...