2007 年 8 月 19 日 23 時 57 分

関数の実装


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


今日は、必須の関数の実装を行う。

scrnsave.lib を使う場合、
以下の関数を用意する必要がある。

・RegisterDialogClasses
・ScreenSaverConfigureDialog
・ScreenSaverProc

ScreenSaverProc はプレビューと実行モードの時に使われる。

scrnsave.lib は、最初にウィンドウを作成する。
これは、実行モードの時は、画面全体を覆うサイズに、
プレビューモードの時は、プレビュー画面に収まるように、
自動的にサイズが計算された状態で表示される。

ScreenSaverProc は、そのウィンドウの、
ウィンドウプロシージャとして登録されるため、
ScreenSaverProc 内で、イベントを自由に処理できるのだ。

RegisterDialogClasses と ScreenSaverConfigureDialog は、
設定モードの時に呼び出される関数である。

設定モードの場合、scrnsave.lib は、
ID が DLG_SCRNSAVECONFIGURE のリソースを使って、
ダイアログボックスを作成して表示する。

ScreenSaverConfigureDialog はそのダイアログボックスの、
ダイアログプロシージャとなっている。

もう一つの関数である RegisterDialogClasses は、
ダイアログが作成される直前に呼び出される。
これは、利用者が設計したダイアログリソース上で、
特別なコントロールが使われるケースに対応するためだ。

自作等のコントロールをダイアログボックスで使う場合、
ダイアログボックスが作成される前に、
コントロールのウィンドウクラスを登録しなければならない。
RegisterDialogClasses はそのために存在するのだ。

では、コードを書いていこう。
まず、基本的な環境の設定を含むヘッダを作る。

========== config.hpp ==========

#ifndef z_config
#define z_config

#define WINVER 0x400
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <scrnsave.h>

#endif /* !z_config */

========== end of config.hpp ==========

WINVER が 0x400 で、Windows 95/NT 以降ということ。
STRICT は Windows の型に関する厳格モードを指定する、
WIN32_LEAN_AND_MEAN はコンパイルを迅速に行うおまじない。

続いて、関数の本体を実装する。

========== module.cpp ==========

#include "config.hpp"

BOOL WINAPI RegisterDialogClasses(HANDLE hInst) {
    UNREFERENCED_PARAMETER(hInst);
    return TRUE;
}

BOOL WINAPI ScreenSaverConfigureDialog(
        HWND hdlg, UINT message,
        WPARAM wParam, LPARAM lParam) {

    UNREFERENCED_PARAMETER(wParam);
    UNREFERENCED_PARAMETER(lParam);

    switch (message)  {

    case WM_COMMAND:

        switch (wParam) {

        case IDOK:
            EndDialog(hdlg, 0);
            return TRUE;

        case IDCANCEL:
            EndDialog(hdlg, 1);
            return TRUE;

        }
        break;

    }

    }

    return FALSE;

}

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

    switch (message) {

    case WM_PAINT:
        {
            const char *text = "Hello World!";
            PAINTSTRUCT ps;
            HDC hdc;
            hdc = BeginPaint(hwnd, &ps);
            TextOut(hdc, 0, 0, text, lstrlen(text));
            EndPaint(hwnd, &ps);
        }
        return 0;

    }

    return DefScreenSaverProc(hwnd, message, wParam, lParam);

}

========== end of module.cpp ==========

今回作ったダイアログは単純そのものなので、
特別なウィンドウクラスは必要ない。
そのため、RegisterDialogClasses は TRUE を返すだけ。

UNREFERENCED_PARAMETER は、未使用の引数に関する、
コンパイラの警告を抑制するためだ。
本当はコンパイラの設定で制御するのが良いのだろうが、
SDK プログラミングでは慣例となっている。

ScreenSaverConfigureDialog はダイアログプロシージャ。
2 つのボタンが押された処理を行うために、
WM_COMMAND メッセージを処理する。

ダイアログを閉じる際は、EndDialog 関数を呼び出す。
今回は、IDOK が押された場合、戻り値 0 で閉じ、
IDCANCEL が押された場合、戻り値 1 で閉じるとする。
なお、この戻り値はそのままプログラムの戻り値となる。

ダイアログプロシージャの場合、
TRUE を返すとメッセージを処理したことになるが、
FLASE を返すと、メッセージを処理しなかったことになり、
ダイアログボックスとしての既定の処理が行われる。

ScreenSaverProc はウィンドウプロシージャ。
今回は、WM_PAINT メッセージを捕まえて、
画面上に自由に描画を行うことができる。
ここではお決まりの「Hello World!」を描画することにした。

WM_PAINT では、まず BeginPaint を呼び、
適当に描画した上で、EndPaint を呼んで止める。
今回は、TextOut 関数でテキストを描画してみた。

さて、ウィンドウプロシージャの場合、
戻り値を自分で返すとメッセージを処理したことになり、
DefWindowsProc 関数を同じ引数で呼び出すと、
ウィンドウとしての既定の処理が行われる。

scrnsave.lib には、DefScreenSaverProc 関数があり、
これは、スクリーンセーバーとしての既定の処理が行われる。
DefScreenSaverProc は DefWindowsProc と異なり、
マウスやキーボードが動いた時の自動終了などを、
自動的に行ってくれるので楽だ。

どうだろう、結構コードは短くて済んだようだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.