ヘプタモンド・スクリーンセーバに戻る 

スクリーンセーバーの作り方

 通常のWindowソフトを作る場合、メインルーチンWinMain()関数や応答ルーチンWndProc()を記述します。
 スクリーンセーバーでは主関数等はシステムに用意されており、プログラマは以下の3ルーチンを準備することになります。詳しくはコンパイラのドキュメントを参照していただくとして、ここではスクリーンセーバーのプログラミングの概略を説明したいと思います。

BOOL WINAPI ScreenSaverConfigureDialog(
  HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {}
BOOL WINAPI RegisterDialogClasses(HANDLE hInst) {}
LRESULT WINAPI ScreenSaverProc(
  HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {}

 この中で、スクリーンセーバーの「設定」で現れるダイアログの応答ルーチンがScreenSaverConfigureDialog()で、スクリーンセーバーの動作を記述するのがScreenSaverProc()です。RegisterDialogClasses()は設定ダイアログに細工をする場合に必要なようですが、通常は単にTRUEを返すだけで良いようです。

 インクルードファイルとしてscrnsave.hを指定します。リンク時にはscrnsave.libを加えます。これらのヘッダファイルやライブラリがないコンパイラでは、もちろんコンパイルできません。

● ScreenSaverConfigureDialog()

 設定ダイアログウィンドウの応答ルーチンです。スクリーンセーバーといっても、ここは通常のダイアログ応答ルーチンと同様に書けばOKです。設定した値は、ファイルやレジストリに記録しておく必要があります。なぜかレジストリの人気は低いので、どこかにabcde.iniなどのiniファイルを設けておくとよいでしょう。iniファイルの内容は、通常、テキストファイルにします。

 設定ダイアログボックスのID番号は2003番に決まっています。scrnsave.hの中に、
  #define DLG_SCRNSAVECONFIGURE 2003
 という行があるので、これは変更できません。ダイアログを作ったら、そのIDをDLG_SCRNSAVECONFIGUREにします。

● ScreenSaverProc()

 実際にスクリーンセーバーが起動したら呼ばれる応答ルーチンです。スクリーンセーバーがどのように動作するかを記述します。
 通常のウィンドウの応答ルーチンとの違いは、メッセージに応答しない場合は、DefScreenSaverProc()というルーチンを呼ぶことです。その他の場合は、0を返せばよいでしょう。
 いったん何か書いたら他は何もしないのなら別ですが、普通はスクリーンセーバーは絵を動かしたりしますから、WM_CREATEメッセージ処理でシステムのタイマーを起動することになります。
 本スクリーンセーバーでは表示とパズル解きを分離したかったので、パズルを解く部分を別スレッドで起動しています。

 WM_ERASEBKGNDメッセージはタイマーメッセージよりも前に来るので、画面全体の下準備(消すなど)をします。
 あとはWM_TIMERメッセージが到着するごとに、画面を書き換えればよいのです。
 マウスを動かすなど、スクリーンセーバー終了時にはWM_DESTROYメッセージが来るので、タイマーを抹消したりします。

 マニュアルには、上記2ルーチンをモジュール定義ファイルというのでエクスポートせよ、と書いてあるのですが、何もしないでも動作するようです。

 私の買ったコンパイラの解説にはなぜか載っていなかったのですが、
  WM_POWERBROADCAST
 というメッセージをデフォルト処理するとまずいようです。本スクリーンセーバーではBROADCAST_QUERY_DENYという値を返しています。

● 本スクリーンセーバーのプログラムで注意する点

 メッセージ応答とは別のスレッドでパズルを解いているため、表示より先にパズル解きが進んでしまわないよう、イベントセマフォというスレッド間通信の仕組みを使っています。パズルが解けたことを知らせるのには、通常のウィンドウメッセージ(WM_APP)を使用しています。
 残りの領域が分割されていないかを確かめる部分は、探索(パックトラック)なので再帰ルーチンを使用しているため、少々制御が追いにくいかもしれません。ここの部分(aki())は、制御的にではなく、宣言的(問題記述的)に解釈すると理解しやすいと思います。

2002年7月12日 岡田好一