ホーム 主筆 その他ソフト その他情報 Syuhitu.org English

Windows関連

スクリーンセーバー作成法

半透明ウインドウの性能

bootfont.bin

キャビネット形式

ウインドウスタイルをいじる

Java製ソフトをServiceに登録する

イベントログにメッセージを出力する

コントロールパネルにアイコンを追加する

スクリプトによる拡張1

スクリプトによる拡張2

ガジェットの作成

大容量メモリ

メモリ搭載量の下限に挑む

スパースファイルにする

表示されるアイコンの種類を調べてみた

メモリマップIOとエラー処理

ファイルを作る順番と速度の関係

Cryptography API: Next Generationを使う

Windows 10のアクセントカラー

iSCSIディスクにバックアップを取る

サーバプロセスを分離して実装する

サーバプロセスを分離して実装する - F#

レジストリに大量に書き込む

Solaris関連

OpenGL

Solaris設定

ディレクトリの読み込み

主筆プラグイン開発

マルチスレッドでの開発

door

音を出す

Blade100の正しい虐め方

パッケージの作成

画像入出力

BMPファイル

ICOファイル

ANIファイル

JPEGファイル

減色アルゴリズム

減色アルゴリズムの並列化

その他アルゴリズムなど

自由軸回転

Base64

文字列操作

CPU利用率の取得

正規表現ライブラリ

メタボールを作る

メタボールを作る2

正規表現とNFA・DFA

C言語の構文解析

液晶ディスプレイを解体してみた

iSCSIの理論と実装

単一フォルダにファイルを沢山作る

USB-HUBのカスケード接続

SafeIntの性能

VHDファイルのフォーマット

USBメモリに書き込み続けてみた

スクリーンセーバー作成

はじめに

Windows上で動作するスクリーンセーバーを開発することを考えてみる。

なお、今となっては随分年代物となってしまったが、俺が使っている環境はWindows 2000とVisual C++ 6.0である。しかし、バージョンが上がったとしても、基本的な部分は変わらないはずである。

ヘッダファイル・ライブラリ

まず、スクリーンセーバー開発固有のヘッダファイルとして「scrnsave.h」というヘッダファイルが必要になる。

同様に、「SCRNSAVE.LIB」もしくは「SCRNSAVW.LIB」をリンクする必要がある。「SCRNSAVW.LIB」はワイドバイト文字列を取り扱うバージョンである。文字コードとしてUnicodeを使うようにするのなら(すなわち、コンパイル時の引数に_UNICODEを指定するのなら)こちらを使用する必要がある。そうでなければ「SCRNSAVE.LIB」を使う。

なお、これらのファイルはVisual Sudioについてくるから、HDD内を探せばきっとどこかに入っているはずである。

プログラムの構造

スクリーンセーバーとして動作するプログラムは、下記三つの関数を実装する必要がある。

ScreenSaverConfigureDialog

BOOL WINAPI ScreenSaverConfigureDialog(
  HWND hDlg,
  UINT message,
  DWORD wParam,
  LONG lParam
);

スクリーンセーバーの「設定ダイアログ」が表示されるときに呼ばれる。ここでダイアログを表示し、スクリーンセーバーの動きを変更できるようにする。

RegisterDialogClasses

BOOL WINAPI RegisterDialogClasses(
  HANDLE hInst
);

スクリーンセーバーで使用する拡張のウインドウクラスを登録する。不要なら何もする必要はない。

ScreenSaverProc

LONG WINAPI ScreenSaverProc(
  HWND hwnd,
  UINT message,
  DWORD wParam,
  LONG lParam
);

実際のスクリーンセーバーが描画されているときの手続きを記述する。すなわち、引数hwndに渡されたウインドウハンドルに描画する処理を記述する。

以下に、これら関数について解説する。

ScreenSaverProcですること

この関数ではスクリーンセーバーの本来の処理を行います。つまり、画面上にユーザの興味をそそる魅力的なコンテンツを描き出さなければならない。

この関数には下記四つの引数が渡される。

HWND hWnd

描画対象となるウインドウのウインドウハンドルが指定される。

UINT message

ウインドウメッセージが指定される。本関数ではmessageに指定されたウインドウメッセージに応じた処理を行わなければならない。

DWORD wParam

LONG lParam

messageに指定されたウインドウメッセージを処理する為に必要となる情報が渡される。wParamとlParamの値については下記を参照のこと。

下記に、messageに指定されるウインドウメッセージと、wParam・lParamの値を示す。
messageの値 意味 wParamの値 lParamの値 戻り値
WM_CREATE ウインドウが構築された 使われない CREATESTRUCT構造体へのポインタ 正常に処理したら0を返す。失敗した場合は-1を返す。
WM_ERASEBKGND 背景の消去 デバイスコンテキストのハンドル 使われない アプリケーションで背景を消去した場合は0を返す。
WM_TIMER タイマイベント タイマ識別子 タイマコールバック関数の関数ポインタ 正常に処理したら0を返す。
WM_SIZE ウインドウのサイズが変更された サイズ変更フラグ ウインドウのサイズ 正常に処理したら0を返す。
WM_DESTROY ウインドウが破棄された 使われない 使われない 正常に処理したら0を返す。
 

なお、送出されるウインドウメッセージは上記以外にも存在する。詳細はMSDNに記述されている。

上記のメッセージを処理するScreenSaverProc関数は下記のような構造となる。

 

LRESULT WINAPI ScreenSaverProc (
    HWND hWnd,
    UINT message,
    DWORD wParam,
    LONG lParam)
{
  switch( message ){
  case WM_CREATE:	// 構築する
    構築時に処理すべき処理を記述
    return 0;

  case WM_DESTROY:	// 破棄する
    破棄時に処理すべき処理を記述
    break;

  case WM_ERASEBKGND:
    真を返すとWindwosによる背景消去が行われなくなる。
    スクリーンセーバーであれば真を返すべきである。
    return TRUE;

  case WM_TIMER:	// タイマ通知
    一般的にはここで描画処理を行う
    return 0;

  case WM_SIZE:  	// サイズ変更通知
    サイズが変わったときにしなくてはいけない処理を行う。
    return 0;
  }
  return DefScreenSaverProc(hWnd, message, wParam, lParam);
}

上記のプログラム中の「DefScreenSaverProc」は、アプリケーションでは明示的に処理を行わないメッセージを処理するために呼び出す。自分で処理を実装した場合は呼ぶ必要はない。

「WM_ERASEBKGND」は、自前で背景消去処理を記述した場合には真を返す。そうすることで、Windowsが勝手に背景を白で消去処理を行わなくなる。これにより、画面が著しくチラチラする現象を防止することが可能となる。

「WM_TIMER」はタイマのイベントである。しかし、当然だがタイマーは勝手には設定されず、無論、タイマーイベントのメッセージが自動的に送出されてくることはない。すなわち、自分でタイマーの設定を行う必要がある。

タイマーの設定には下記のAPI関数を用いる。

UINT_PTR SetTimer(
  HWND hWnd,              // ウインドウハンドル
  UINT_PTR nIDEvent,      // タイマ識別子
  UINT uElapse,           // タイマアウト値(ミリ秒単位)
  TIMERPROC lpTimerFunc   // タイマプロシージャの関数ポインタ
);
hWndはウインドウメッセージを受け取るウインドウのウインドウハンドルを指定する。すなわち、ScreenSaverProc関数のhWndを指定しておけばよい。

タイマ識別子は1以上の好きな値を指定しておけばいい。タイマーを複数個設定して、複雑なイベント処理を実装しようというのであれば、タイマー識別子の値も慎重に設計する必要がある。しかし、タイマーを1つしか設定しないのであれば、全く気にする必要はない。

タイマーイベントはuElapseに指定した間隔に発生する。1秒間に24コマ描画しようと言うのであれば42程度の値を指定しておけばいい。なお、タイマーイベントの時間解像度はそれ程高くないため、余り細かいことを気にしても意味はない。

lpTimerFuncには、タイマーイベントを処理する関数の関数ポインタを指定する。なお、この引数に関数ポインタを指定した場合は、WM_TIMERのタイマーイベントは送出されなくなる。関数ポインタを指定して関数を呼び出させるか、WM_TIMERのウインドウメッセージを受け取るかの選択は、アプリケーションを作る人の個人的趣味に依存する問題である。

不要になったタイマーを破棄するには下記のAPI関数を用いる。

BOOL KillTimer(
  HWND hWnd,          // ウインドウハンドル
  UINT_PTR uIDEvent   // タイマ識別子
);

描画処理の大半はタイマーイベントの処理中で行う。すなわち、タイマーイベントが一回発生したら、1コマだけ描画を行うようにする。

まかり間違っても、無限ループを作ってその中で描画しようなどと考えてはいけない。

なお、画像は、渡されたウインドウハンドルからデバイスコンテキストを取得し、幾つかのWindowsAPIをもってして描画を行う。あるいは、OpenGLやDirectXを使用する。

ScreenSaverConfigureDialogですること

ここではスクリーンセーバーの動きをカスタマイズできるように、「設定」ダイアログを表示する手続きを記述する。

ScreenSaverProc関数と同様、ウインドウメッセージが送出されてくるので、それらを処理するような形でダイアログボックスを表示する処理を実装する必要がある。

なお、本関数からはDefScreenSaverProc関数を呼び出してはいけない。

その他すべきこと

ほかにもするべきことがいくつか存在する。

DLG_SCRNSAVECONFIGURE識別子でダイアログを定義する

スクリーンセーバーの「設定」ダイアログの識別子はDLG_SCRNSAVECONFIGUREという名前を使用することが規定されている。また、この識別子として定義される値は2003であることも規定されている。

その為、VisualC++のリソースエディタでダイアログを作る場合は、以下の手順を踏むこととなる。

  1. 通常通りダイアログを作成する

  2. 「ダイアログプロパティ」のIDを「DLG_SCRNSAVECONFIGURE」に変更する

  3. 「resource.h」ヘッダファイルで定義されているDLG_SCRNSAVECONFIGUREの値を2003に変更する



スクリーンセーバーの名前を定義する

「画面のプロパティ」の「スクリーンセーバ」タブを選択すると、コンボボックス中にスクリーンセーバーの日本語名称が表示される。

この名前は、Windwos98ではファイル名が使用されるようだが、Windwos2000以降ではプログラム中にリソースとして定義した文字列が使用される。

このとき使用される文字列は1番のものと決められている。よって、スクリーンセーバーの名称は下記の手順により設定を行うこととなる。

  1. リソースエディタのストリングテーブルに任意のIDで名前を定義する

  2. 「resource.h」を開き、上記で設定したIDに対応する値を「1」にする

コンパイルする

「SCRNSAVE.LIB」をリンクすること以外は、特に注意するべき事項はない。

なお、スクリーンセーバーの拡張子は「.scr」と決められている。そのため、生成されたプログラムの拡張子を「.exe」から「.scr」に変更する必要がある。

インストール

インストール方法は特に規定されていない。

基本的にはシステムフォルダに格納されている「*.scr」ファイルをスクリーンセーバーとして認識する。よって、生成した「.scr」ファイルをシステムフォルダに格納すればいい。

また、「.scr」ファイルを右クリックして「インストール」を選択しても問題はない。

 


連絡先 - サイトマップ - 更新履歴
Copyright (C)  2000 - 2016 nabiki_t All Rights Reserved.