ソースを御用意しましたので、こちらからダウンロードしてみてください。
CMDを起動させ、コンパイルし、作成されたexeファイルを実行すると
以下のようなウィンドウが表示されると思います。
なお、このプリケーションはウィンドウを表示させるためだけに作られているので
自身を終了させる機能を持ち合わせていません。
このアプリケーションを終了させる時は、お手数ですが
「設定」→「メモリ」→「実行中のプログラム」から終わらせてください。
ではとりあえずソースを簡単に見ていきたいと思います。
#include <windows.h>
一番初めはwindowsプログラムには必須、ヘッダーファイルwindows.hを読み込みます。
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int iCmdShow) { ……… }
WinMain 関数は特殊な関数で、プログラムが実行されると
1番始めに自動で呼び出される関数です。Cでのmain関数と似たようなものですね。
ウィンドウズアプリケーションはこの関数によって始まり、
この関数が戻り値を返す事によって、プログラムを終了します。
ここでは引数などは気にせずいきましょう。
const TCHAR szAppName[] = TEXT("sample 01") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ;
WinMain内で使用する変数を宣言します。
szAppName[]:このアプリケーションのクラス名です。
hwnd:メインウインドウのウインドウハンドルです。
msg:メッセージキューから取得したメッセージを格納します。
wndclass:ウインドウクラス登録用の構造体です。
wndclass.lpszClassName = szAppName ; //ウィンドウクラスの名前 wndclass.lpfnWndProc = WndProc ; //ウィンドウプロシージャ関数 wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = 0; //LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = 0; //LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ;
長々と書いていますが、ここでは作成するウィンドウの情報を設定しています。
重要なのは、lpszClassName(ウィンドウクラス名)と
後で書くlpfnWndProc(ウィンドプロシージャ関数)くらいです。
1行目でウィンドウクラス名にアプリケーション名を登録します。
2行目でウィンドウプロシージャに使う関数を登録します。
ちなみにウィンドウプロシージャとは、例えばWINDOWサイズが変更された、
マウスボタンが押された等が起こるとwindowsから発行されるメッセージを受け取り
それぞれの出来事に対する処理を行う関数のことです。
RegisterClass (&wndclass) ;
上で設定した構造体を指定して、RegisterClass 関数により
ウィンドウの作成に使用できるウィンドウクラスを登録します。
hwnd = CreateWindow (szAppName, //前回登録したウィンドウクラスの名前 TEXT("sample 01"), //ウィンドウの名前 WS_VISIBLE, //ウィンドウのスタイル CW_USEDEFAULT, //位置X座標 CW_USEDEFAULT, //位置Y座標 CW_USEDEFAULT, //サイズX CW_USEDEFAULT, //サイズY NULL, //親ウィンドウのハンドル NULL, // hInstance, // NULL // ) ;
CreateWindow 関数によりウィンドウを作成します。
1番目の引数に登録してあるウィンドウクラスの名前を指定することで
そのウィンドウクラスの構造体を使ってウィンドウを作ります。
2番目の引数はウィンドウ名、タイトルバーなんかに表示されるやつです。
第4引数から第7引数まではウィンドウの位置とサイズです。
CW_USEDEFAULTを指定すると勝手に設定してくれます。
第8引数では親ウィンドウのハンドルを指定します。
このウィンドウが最初(=自分自身が親)の場合はNULLを指定します。
9~11は省略します。
ウィンドウの作成に成功すれば、戻り値として
そのウィンドウのハンドルが返されます。
ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ;
ShowWindow 関数により実際に画面上にウィンドウを表示します。
第1引数のhwnd には表示したいウィンドウのハンドルを指定します。
第2引数には、iCmdShow というWinMain()で渡される第4引数を指定してます。
これはwindowsのアプリケーションのショートカットのプロパティにある
実行時の大きさという欄で最小化とか最大化とかいうのを指定したのが渡されるみたいです。
(WindowsCEではこの機能が有効なのかは知りません・・・)
UpdateWindow関数で指定したウィンドウの表示状態を更新します。
while (GetMessage (&msg, NULL, 0, 0)) { //TranslateMessage (&msg) ; DispatchMessage (&msg) ; }
これがwindowsプログラムの特徴であるメッセージループですね。
GetMessage はメッセージキュー(Windowsから送られたメッセージが保管されているところ)から
メッセージを取得し、MSG構造体に格納する関数です。
戻り値として、WM_QUIT(アプリケーションを停止しますよというメッセージ)以外の
メッセージを受け取ったとき0以外(TRUE)を、WM_QUITを受け取ったとき0(FALSE)を返します。
このように、メッセージループではWM_QUITが来るまではwhile内でループして
Windowsから送られてくるメッセージを延々と処理していくことになります。
TranslateMessage は、仮想キーのメッセージを文字メッセージに
変換してくれるという関数です。仮想キーとは、Keyイベントが起こったとき
メッセージに入っている、押されたキーの値のことです。
今回は必要ありませんが、例えばキーが押された時に、Aというボタンが押された場合
そのままではAの仮想キーのメッセージを取得できるだけですが、この関数を使えば
それを文字に変換してくれるので、'A'という文字を取得できるようになる、みたいな感じです。
DispatchMessage は、取得したメッセージをウィンドウプロシージャに送る関数です。
これにより、送られたメッセージがウィンドウプロシージャ内で処理されることになります。
//============================== // ウィンドウプロシージャ LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
イベントを記述するウィンドウプロシージャ関数です。iMsgにwindowsから
発行されたイベントの種類が格納されているので、switchで処理を分岐させます。
「WM_DESTROY」メッセージはウィンドウが破棄されたというメッセージなので
これを受け取るとPostQuitMessage 関数により
「WM_QUIT」メッセージをwindowsにポストさせます。
上にも書いたように「WM_QUIT」メッセージを受けると WinMain内のGetMessage() は FALSE を返して
ループを抜けアプリケーションを終了します。
※正確には、「設定」→「メモリ」→「実行中のプログラム」で
終了しようとすると、「WM_CLOSE」というメッセージが送られるので
caseを使って終了するかどうかを問う処理を足すことが出来るようですが
今回では「WM_CLOSE」をわざとDefWindowProc関数に渡してDestroyWindow関数を呼んでもらい
「WM_DESTROY」を起こしています。
WinMain内の処理をまとめてみると、
1・RegisterClassで作成するウィンドウを登録して
2・CreateWindowでウィンドウを作成して
3・ShowWindowでユーザーに見えるようにウィンドウを表示して
4・GetMessageでwindowsから発行されるメッセージを受け取って
5・それが終了メッセージだったらループを抜けアプリケーションを終了する。
6・そうでなければDispatchMessageでウィンドウプロシージャにメッセージを送り
7・ウィンドウプロシージャ内でそのメッセージに対応する処理を行い
8(4)・また戻ってきてGetMessageでメッセージを受け取って・・・
と4~7をループする感じでしょうか。
2005/5/6