次のページ 前のページ 目次へ

16. 必須のリジューム処理

今まで避けて通ってきましたが、 ザウルスのmoreソフトにおいて、 現在の状態の保存と復帰は大切な処理です。 これが無いと他機能にちょっと切り替えてまたmoreソフトに戻ってくるという ザウルス的な使い方ができなくなります。 本章では、この保存と復帰の実現方法について説明します。

16.1 リジューム処理の必要性

PCでは1度ソフトを起動したら他のソフトを起動しようと何しようと、 (トラブルでもない限り)どちらも終了せずに動き続けます。 でもザウルスはメモリが少なく、 複数のソフトを1度に起動しておくのは現実的ではありません。 そこで本講座の最初の方でも書いたように、 EXEC状態からOUT状態へ移るとか、 EXIST状態にまで戻りソフトを終了することで メモリ使用量を減らすようにしているのです。

しかしOUT状態に戻るというのはEXEC状態の各情報を失うことですし、 EXIST状態に戻るというのはmoreソフトを完全に終了する事に他なりません。 つまり四川省ですとプレイ中にアドレス帳を参照して戻ってきたら、 また初めからやり直し!となってしまうわけです。

他機能に切り替えた後でも、 たとえ電源が切れた後でも正しく続きをプレイするためには、 終了前に現在の状態をファイルに保存し、 再び起動した後に復元する処理が必要です ・・・これがリジューム処理です。

moreソフトにリジューム処理が必須だという事、 お判りいただけましたでしょうか。

16.2 保存するべき情報

情報を保存しなければいけない事はわかりましたが、 それでは一体何を保存したらいいのでしょうか? ちょっと悩んでしまいそうですが、 moreソフト実行中に変化する内容で且つファイルに書き出してないものとなると、 大体下記のようになります。

う〜ん、結構色々あるものですね。

でもご心配は不要です。 四川省ではEXECワークに保存すべき情報をまとめていますので、 単に EXECワークの内容をファイルに保存するだけで済むんです。 さほど複雑でないソフトであれば、大体これで足りるでしょう。

複雑なデータ構造を持つソフトでは、 動的に確保したデータの保持なども必要になると思いますが、 それはソフトに応じて処理を追加してあげれば良いのです :-) 。

16.3 保存・復帰を行うタイミング

moreソフト終了時の流れは FormEnd() → PIMExecEnd() となります。 ですので画面関連の情報は FormEnd() の中で EXECワークに保持しておき、 ファイルへの保存は PIMExecEnd() で行うと良いでしょう。 OUT状態を持つソフトの場合、 PIMAplEnd()を有効にするか、 PIMExecEnd()の中でソフト終了イベントかを見て判断・保存できます。

こうしてファイルに保存した情報の復帰は、 moreソフトの起動の流れに沿って PIMExecSetupPIMAplSetup で読み込めば良いですね。

以上、まとめるとこんな感じです。

PIMAplSetup() OUT状態保存ファイルの有無をチェックし、必要に応じて読み込む。
PIMExecSetup() EXEC状態保存ファイルの有無をチェックし、必要に応じて読み込む。 前回表示していたフォームIDが残っていれば、 そのフォームを表示するように設定。
FormSetup() 画面情報があれば、それに基づいてフォーム上の各コントロールを設定。
FormEnd() 正常な終了ならば フォームID をクリア。 中途な終了ならば フォームID を保存し、 現在のフォームを復元できるよう各画面情報をEXECワークに保持。
PIMExecEnd() 正常な終了ならば EXEC状態保存ファイル を消去。 中途な終了ならば EXEC状態保存ファイルに EXECワーク内容を保存。
PIMAplEnd() 正常な終了ならば OUT状態保存ファイル を消去。 中途な終了ならば OUT状態保存ファイル に OUTワーク内容を保存。

実際には、OUT状態を持たない物の方が多いでしょうから、 上記の PIMAplSetup() と PIMAplEnd() は不要になります。 更に、四川省の場合はフォームが1枚だけで、 且つ常に状態を保持させますので、 PIMExecSetup() と PIMExecEnd() に処理を加えるだけです。

16.4 保存・復帰処理のコード

それでは四川省の実際のコードを見てみましょう。 保存処理の方は単純にEXECワーク内容をファイルに保存しているだけです。 復帰処理の方は安全を考えてファイルサイズの確認、 バージョン番号の確認などを行い、 この状態保存ファイルが本当にこのソフト用のものかチェックしています。

完全に正しい状態保存ファイルであった場合は、 cont_flg = true にして継続させ、 そうでなかった場合は全くの新規から始まったものとして EXECワークを初期化して cont_flg = false で開始するようにしています。

なお、ここで cont_flg は、 継続で起動したのか新規で起動したのか区別するために用意したグローバル変数で、 四川省では GameFormRedisp() で初回描画時にタイマーカウントを 継続させるか 0 から開始させるかの判断に用いています (第13章 『クリア時間を計測させよう』 を参照)。
void PIMExecEnd(PIMEXECWORK *PIMExecWork,MESSAGE *Message)
{
	FILEHDERROR		fhdl;
	ULONG			writelen;
	BOOLEAN			NGflg;

	NGflg = true;

	do {
		if ( (fhdl = FileCreate( INFOSAVE_FILE, USUAL_FILE )) < 0 )
			break;

			/* ゲーム情報を保存する */
		writelen = sizeof(ExecWk);
		FileBlockWrite( fhdl, (void *)g_ewk, &writelen );

		if ( writelen != sizeof(ExecWk) )
			break;

		NGflg = false;
	} while( 0 );

		/* ファイルクローズは忘れずに! */
	if ( fhdl >= 0 ) {
		FileClose( fhdl );
	}

		/* 失敗なら、情報ファイルの破棄(成否問わず) */
	if ( NGflg ) {
		FileDelete( INFOSAVE_FILE );
	}

		/* 確保済みの EXECWK を解放する */
	if ( g_ewk ) {
		DisposeHeapPtr( g_ewk );
		g_ewk = NULL;
	}

	// アウト状態に移行するときにプロセス終了する処理
	Message->CommonMsg.MessageID = AppliProcEndReqID;
	Message->AppliProcEndReq.AplFilter = AF_THIS_APPLI;
}


BOOLEAN PIMExecSetup(PIMEXECWORK *PIMExecWork,MESSAGE *Message)
{
	FILEHDERROR		fhdl;
	FINFOBUF		finfo;
	ULONG			readlen;
	BOOLEAN			NGflg;

		/* 乱数系列の初期化 */
	RANDOMIZE();

	NGflg = true;
	do {

			/* 情報保存ファイルの有無 */
		if ( (fhdl = FileOpen( INFOSAVE_FILE, RW_OPEN )) < 0 )
			break;
			/* ファイルサイズ確認の為、情報を読み込む */
		if ( FileInfoRead( fhdl, FC_INFO_FCB, &finfo ) < 0 )
			break;
			/* ファイルサイズの確認 */
		if ( finfo.iFCB.Size != sizeof(ExecWk) )
			break;
			/* 読み込み */
		readlen = sizeof(ExecWk);
		if ( FileBlockRead( fhdl, FC_FILE_END_PH, (void *)g_ewk, &readlen ) < 0 )
			break;
			/* 読んでもサイズが違う場合 */
		if ( readlen != sizeof(ExecWk) )
			break;
			/* このファイルのバージョン番号の確認 */
		if ( g_ewk->version != SHISEN_VERSION )
			break;
		NGflg = false;

	} while( 0 );

		/* ファイルクローズは忘れずに! */
	if ( fhdl >= 0 ) {
		FileClose( fhdl );
	}

	if ( NGflg ) {
		/* 失敗なら g_ewk の初期化処理を行う */

			/* MyGlbVal型の変数領域をヌルクリア */
		memset( g_ewk, 0, sizeof(ExecWk) );

		g_ewk->version = SHISEN_VERSION;

		HINIT();	/* 牌消去ワーク初期化 */
		CINIT();
		SHUFFLE();

		g_ewk->SCH	= 0;
		g_ewk->MD	= 0;
		g_ewk->Z	= 144;
		g_ewk->P1	= N;
		g_ewk->HF	= 0;

		CGSET();

		cont_flg = false;
	}else{
		cont_flg = true;
	}

	return true;
}
ちなみに、構造体の内容をそのままファイルに保存するのはあまり推奨されないことですが、 物がリジューム用の情報であること、 そして他の機種にそのまま持っていくことはないことから、 このように単なるバイトストリームとして保存しています。

話がそれますが、 これが他機種に持っていく可能性のある設定ファイル等であれば、 構造体そのままではなく、 汎用性を持たせた形式(テキスト等)で保存するのが望ましいでしょう。

16.5 その他

リジューム処理の基本は以上になりますが、 上で割愛したところを少々・・・。

1つは複数の画面を持ったソフト。 この場合、PIMExecSetup()で初期表示フォームIDの値を変更する必要があります。 具体的には、EXECワーク内に DefScreenID というメンバがあるので、 これにフォームIDを設定してあげてください。
	[例] PIMExecWork->DefScreenID = GameFormScnID;

次に、入力項目を持つフォーム。 テキストエディタのようなソフトの場合、 入力されている内容を保存しておかなくてはアプリの切り替えで消えてしまいます。 FormEnd()で内容をメモリに取り出し、 次回の FormSetup()でコントロールに設定する処理を作る必要があります。

それから時間を計測しているソフト。 リジュームするという事は、 前回動いていた時から不連続に時間が過ぎているという事です。 連続して動いているものと決め付けていると問題が起きるでしょうから、 これも注意しましょう。


次のページ 前のページ 目次へ