2.1 Windows Programming 概論 Menuへ戻る

      ようやく待ちに待ったWindowsへの突入です。まず、はじめに基本としての
    概要をつかんでもらいます。SDK オンリーで単純なソフトを作成します。

      これまで SDK というのを何回も出してきましたが、そもそも SDK とは
    何でしょうか?SoftwareDevelopmentKitの略です。そもそもウィンドウに
    ついて考えてみましょう。外枠を描いてメニューも描いて、それから最小化ボ
    タンなんかも自分で描いて、さらにそこにマウスカーソルが行き、押されたら
    小さくしてアイコンを描いて....てな事を自分でやっていたら、プログラムな
    んか一人でやってられません。

      そこで、Windows は様々な機能(メニュー、アイコン、ボタン、エディット
    ボックス・・・)を提供してくれます。それらの機能を呼び出す為の関数群を
    パッケージにしてMicrosoftはバラまきました。「皆さんどうぞこれでプログ
    ラムを書いて下さい」と。これが Windows SDK です。そうしてプログラマ達は
    従来のDOSより簡単に見栄えのいい、かつ多くの機種で動作するソフトを開
    発しはじめました。こうして Windows は現在の地位を勝ち取ったのです。

      要するにボタンやウインドウなどは SDK の関数を呼び出すだけで作れるので
    す。しかしながら、簡単と言っても素人がフラッとプログラムを作るには SDK
    は大げさすぎました。その後 Microsoft はSDKの中身をC++で包み込んで
    見かけ上、とても簡単にしたのです。SDKの関数は、ほぼ全てC++のクラス
    の概念の中に取り込み、そのクラスの集合体をMFCと名付けました。MFC
    とは MicrosoftFoundationClass Libraly の事です。つまりC++にマイクロ
    ソフトがウインドウズ用クラス群を追加した物が VisualC++ です。

      では簡単になったMFCを使えばいいじゃないかとなるのですが、表面上を
    簡単にするためにもの凄く複雑な内部を持つのです。まるでC++というよりも
    「マイクロソフト語」の用に感じてしまい、理解に時間がかかります。そこで
    非常に簡単な SDK プログラミングをして、まず Windows の仕組みに慣れて
    もらいます。

      さて、前置きが長くなりましたが本題に入ります。従来までの DOSベース
    のプログラムはOSに main 関数を呼び出してもらい、処理が最後までいけば、
    終了するというタイプでした。しかし Windows プログラミングは全く違うモデ
    ルで設計しなければなりません。

      まず、はじめにOSから呼び出してもらうというのには変わりはありません。
    しかし main ではなくて WinMain と名前が変わっています。そして WinMain で
    Windows にどの様なアプリケーションであるかを登録し、後はひたすらWindows
    からの指令を待ちます。指令というのは通常メッセージと呼ばれ、「マウスが動
    いた」とか「ボタンが押された」とか、アプリケーションに関する動きにより
    Windowsが生成します。

      アプリケーションではそのメッセージに対応して処理をします。例えば「終了」
    のメニューが選ばれたというメッセージが送られてきたら、終了の処理を行い、
    ペイントツールであれば、左クリックされたというメッセージが来たら、点を書か
    なければならないでしょう。この様に Windowsアプリケーションでは OS から
    送られてきたメッセージに対して処理を行い、何も送られてこなければ、ただメッ
    セージを待つという事を行います。これをイベンドドリブン型アプリケーションと
    一般に言われます。最近のGUIベースのOSでは皆、同じ様なイベントドリブン
    形式でアプリケーションが作られます。

      ではメッセージが送られてくるというのはどういう事か、となります。それは
    Windows アプリケーションには必ず WndProc という関数がある約束になっていま
    す。(もちろん無い奴もありますが)そして、Windowsは WndProc という関数を
    メッセージを引数にして呼び出してくれるのです。

      WndProcでは受け取ったメッセージの内容により処理をするのです。このように
    OSが呼び出してくれる関数をコールバック関数といいます。コールバック関数に
    は「フォント一覧を教えてもらう」とか「タイマー呼び出しをしてもらう」といっ
    たシステムよりな機能を使う時によく出てきます。

   次に、メッセージについて簡単に説明します。メッセージとは何なのか?という
   風に思うかもしれません。実はメッセージの正体は単に32bitの整数です。ようす
   るに単なる数字なのです。つまり Windows は何らかのイベント(例:マウスが動く)
   があるにつき、その動作に対応した数値を送りつけてくるのです。しかし 100
   だか 500 だか数値が送られてきてもピンと来ません。そこでそれらの数値に、
   名前を付けて分かりやすくしています。例えば左ボタンが押された、というメッセー
   ジは 0x201 が割り当てられていますが(これはWindows3.1)それではわからないの
   でその数を WM_LBUTTONDOWN と名付けています。

    VisualCが入っているフォルダの下の include フォルダにある windows.h を見て
   もらえばわかりますが、すべてのイベントについて

    #define WM_LBUTTONDOWN      0x0201
    #define WM_LBUTTONUP        0x0202
    #define WM_LBUTTONDBLCLK    0x0203
    #define WM_RBUTTONDOWN      0x0204
    #define WM_RBUTTONUP        0x0205
    #define WM_RBUTTONDBLCLK    0x0206

  この様に定義しています。こうする事によってプログラミング上わかりやすいです
し、マイクロソフトが設計を変更して WM_LBUTTONDOWN を 0x02010000 に変更しても
ソースを書き換える事なくコンパイル出来ます。このように #define は後の設計変更
にも柔軟に対応できます。ちなみに数値の表現で 0x**** というのは 16進数表記の事
です。ですから 0x10 は16です。

  さてさて、理論にはもう退屈でしょうから一番簡単な Windows アプリケーションを
書いてみましょう。VCから新規プロジェクトを選択し、プロジェクトの種類は WIN32
アプリケーションを選びます。そして新規のソースファイルを作成し、以下のプログ
ラムを書き、その後適当な名前をつけて保存しプロジェクトに追加します。一応拡張子
は CPP としておいてください。では実行してみましょう。

  できましたか?これが最初のアプリケーションです。次回から何をやっているのか
の説明をします。ではでは
/*---------  PROGRAM START --------------*/

#include >windows.h<

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpszArgs, int nWinMode){
    HWND hwnd;
    MSG msg;
    WNDCLASS wc;

    wc.hInstance = hInstance;
    wc.lpszClassName = "TEST";
    wc.lpfnWndProc = (WNDPROC)WndProc;
    wc.style = 0;
    wc.hIcon = LoadIcon((HINSTANCE)NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
    wc.lpszMenuName = 0;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);

    if (!RegisterClass(&wc)) return FALSE;

    hwnd = CreateWindow("TEST", "TARO++", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        (HWND)NULL, (HMENU)NULL, hInstance, (LPVOID)NULL);

    if (!hwnd) return FALSE;

    ShowWindow(hwnd, nWinMode);
    UpdateWindow(hwnd);

    while(GetMessage(&msg, (HWND)NULL, 0,0)){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
    }
    return msg.wParam;
}

// メッセージ・ループ

LRESULT WINAPI WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){

    switch (message){
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}