Windowsプログラミング(1) 窓を作る

と、言うわけで基本から調べることに。昔ちょろっとやったことはあるので、それほど拒否反応はないんだけど結構忘れてるところが・・・。GUIってUNIXな人から見ると*1かなり慣れないというか派手っていう印象だよねー。

猫でもわかるプログラミング
http://www.kumei.ne.jp/c_lang/index.html

標準 Windows API
http://wisdom.sakura.ne.jp/system/winapi/win32/index.html

この辺が参考になりそうです。

サンプル

#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int nCmdShow){
     HWND hWnd;
     MSG msg;
     WNDCLASSEX wc;

     wc.cbSize        = sizeof(wc);              /* 構造体の大きさ */
     wc.style         = CS_HREDRAW | CS_VREDRAW; /* スタイル */
     wc.lpfnWndProc   = WndProc;                 /* メッセージ処理関数 */
     wc.cbClsExtra    = 0;            /* ウインドウクラスが使用する余分のメモリ */
     wc.cbWndExtra    = 0;            /* ウインドウが使用する余分のメモリ*/
     wc.hInstance     = hInstance;    /* モジュールのインスタンスハンドル */
     wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);    /* アイコン */
     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);        /* カーソル */
     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); /* 背景 */
     wc.lpszMenuName  = NULL;                                /* メニュー名 */
     wc.lpszClassName = "Sample001";                         /* クラス名 */
     wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);     /* 小さなアイコン */

     RegisterClassEx(&wc); /* ウインドウクラスを登録 */

     hWnd = CreateWindow(
          "Sample001",         /* ウインドウクラス名 */
          "Window",            /* ウインドウのタイトル */
          WS_OVERLAPPEDWINDOW, /* ウインドウスタイル */
          32,32,               /* ウインドウ表示位置 */
          256,256,             /* ウインドウの大きさ */
          NULL,                /* 親ウインドウのハンドル */
          NULL,                /* メニューのハンドル */
          hInstance,           /* インスタンスのハンドル */
          NULL);               /* 作成時の引数保存用ポインタ */
     
     ShowWindow(hWnd, nCmdShow); /* ウインドウを表示 */
     UpdateWindow (hWnd);        /* 再描画 */
     
     while(GetMessage(&msg, NULL, 0, 0)){
          TranslateMessage(&msg);
          DispatchMessage(&msg);
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
     switch(nMsg){
     case WM_DESTROY:
          PostQuitMessage(0);
          break;
     default:
          return DefWindowProc(hwnd, nMsg, wParam, lParam);
     }
     return 0;
}

WindowsプログラムはWinMain()から始まります。

hInstance
現在のアプリケーションのハンドル
hPrevInstance
以前のインスタンス(win32では常にNULL)
szCmdLine
引数
nShowCmd
ウインドウの状態

で、プログラムの流れとしては

  1. ウインドウクラスを登録
  2. 登録したクラスのインスタンスを作成
  3. ウインドウの表示
  4. メッセージ(イベント)に対する処理のループ

という流れになる。何かイベントが発生するとWndProc()というコールバックルーチンが呼ばれるので、そこに適当に処理を書いておけばよい。つまりWinMain()の中身は大体同じような感じで、肝心の処理はコールバックルーチンに書く、ということになるのかと。

WinMain()の中のループ。

GetMessage()
スレッドのメッセージキューからメッセージを取ってきます。
TranslateMessage()
でキーボード入力をcharに変換します。
DispatchMessage()
ウインドウプロシージャーにメッセージをディスパッチします。

ってな感じで♪*2

*1:俺だけかもしれませんが

*2:プリキュアS☆S風に