Ko-Window プログラマーズマニュアル 「Console プログラミング」 ● Console とは もともと Ko-Window は、WSRV.RC で指定するウィンドウとしての利用エリアを、実 画面サイズより狭めると、残りの領域がウィンドウ管轄外になりました。ここは黒地 に白という Human68k としてのコンソール領域となり、ここに printf() 等の通常の 標準出力が行われてデバッグで利用できました。これは最初の頃の Ko-Window マニュ アルを見るとわかります。 ところが、サーバーがマルチプロセス対応になり、さまざまな文字出力ルーチンを フックした結果、そのような使い方は不可能となります。 そこで、新たにデバッグ等で使えるよう、文字の表示出力を簡略化する目的で考え 出したのがこの Console です。これは corlib.a で追加したもので、その実現はサー バーに影響を与えず、ライブラリレベルでのみ行われています。 ●動作概念 画面上に1つ、代表して文字表示を行うウィンドウを出しておきます。これが Console ウィンドウです。他のウィンドウアプリケーションは、自分でいちいち文 字表示のコードをもたなくても、デバッグやエラー情報などを、その Console ウィ ンドウに表示させることができます。 というのも、ウィンドウ上でテキスト文字を表示させるのは意外にコストがかかる からです。 もちろん、このとき Console ウィンドウと、アプリケーションウィンドウは別の プロセス (この場合のプロセスとはKo-Window管理上のもの) ですから、何等かの形 でそれぞれのコネクションを開かなければなりません。その仕組みを以下に説明しま す。 ●仕組み まず Console ウィンドウは、起動したら自分のウィンドウ内の1文字表示ルーチ ンのエントリアドレスを、コモン領域に格納します。 これで、他のプロセスからも "Console" という名前で参照すれば、そのエントリ アドレスを得ることができます。 次にアプリケーション側では、Console ウィンドウへの文字出力が必要になったら corlib 内の関数を通じて、以下のように表示を行います。 1) 予め、ConsoleOpen() で画面上に Console ウィンドウが開いているかどう か問い合わせる。もし開いているなら、そのエントリアドレスを受け取って 記憶しておく。 2) 実際に表示が必要になったら ConsolePrint(), ConsolePrintf(), ConsoleChar() で表示を行う。これらのルーチンは、内部で記憶した Console エントリを直接呼び出すように実装されている。 このような2段階の構造になっているのは、毎回コモン領域を参照して Console エ ントリを問い合わせるのは無視できない手間となり、効率がよくないからです。予め ConsoleOpen() でアドレスを受け取っておくことで、実際の文字表示は extern 扱 いの putchar() 等の出力関数を呼ぶのとコスト的にほぼ同一になります。 もし画面上に Console ウィンドウがなければどうなるでしょう。ConsoleOpen() は 失敗として NULL を返します。ですが、通常アプリケーションはこの値を読み出して チェックする必要はありません。個々の ConsolePrint() 等出力関数が、失敗時には 何もしないようにできているからです。 このように ConsoleOpen() の成功か否かをユーザーアプリケーションではなく出力 関数に組み込んでしまったのが、前述の文章でコスト的にほぼ同一であると表現した ことの理由です。そのぶんユーザープログラム側の手間が軽減するので、その方がメ リットは大きいでしょう。 ●2段階構造の問題 このように、2段階に実行する方法になっていますが、それによる問題も生じます。 それは、ウィンドウプロセスがイベントドリブンによるマルチプロセスとして実行が 行われていることが原因です。 もし、ConsoleOpen() でエントリアドレスを受け取ったあと、ConsolePrint() が呼 び出される前にユーザーの操作で Console ウィンドウをクローズされてしまったら、 どうなるでしょう。画面上に Console ウィンドウは無いのにもかかわらず ConsoleOpen() は成功しているため ConsolePrint() はでたらめなアドレスを呼び出 すことになってしまいます。暴走の原因です。 そこで、これらの Console 関数には、ConsoleOpen() のあと ConsolePrint() 等の 出力との間にイベントの解放が挟まってはいけません。 幸いにして Ko-Window のイベントは、イベント関数からの return をもって初めて 他のプロセスに解放されるため、イベント関数の最初で ConsoleOpen() が行われる限 りにおいてはこのようなトラブルは起こりにくくなっています。 早い話、システムからアプリケーションのルーチンが呼び出されたあとに1度だけ ConsoleOpen() を実行しておけば、あとはシステムに return するまでの間は、いく らでも ConsolePrint() 等を実行して構わないということです。 だから、EventOpen で ConsoleOpen() を一度だけやっておけば、あとは EventMouseSwitch 等で自由に ConsolePrint() が使えるというのは大間違いです!! EventExec() なら EventExec() が呼び出されるたびに ConsolePrint() の前に ConsoleOpen() が実行されていなければなりません。 この辺りを間違えないでください。 わからない時は、とにかく ConsolePrint() 等の Console 出力を行う直前に常に ConsoleOpen() を呼び出しておけば間違いありません。 ●表示バッファリングと改行コード 通常の Ko-Window プログラムでは、文字列表示は効率化するためバッファリング を行っています。このバッファリングはプログラミングにおける重要な役割をもって いて、どんなプログラムでもこの考えが必要になってくるでしょう。 ただし、この Console 出力ではユーザーアプリケーション側からは、相手の Console ウィンドウがどういう仕組みで表示を行っているのか全くわかりません。 ですが内部的に1文字出力を基本としてインプリメントされているためまず行バッ ファリングは行われていると思って構いません。この行バッファリングとは、1行分 の表示の表示をバッファにためこみ、改行コードが現れてはじめて表示を行うという ものです。 だから、デバッグなどで ConsolePrint( "ここ" ); 等とプログラムに書いておい ても、実際にはそのタイミングで Console ウィンドウには表示されません。バッファ リングされるだけです。必ず表示の最後に ConsolePrint( "ここまで\r\n" ); のよ うに改行コードを記述しておくよう心掛けましょう。でないと思わぬところでデバッ グに苦労するかもしれません。(これは Ko-Window に限らず、UNIX 等のプログラミ ングでも同じ事です) また、Console ウィンドウが改行コードをどう扱うかは相手の都合によりますので 未定義となっています。これは、将来 ESC シーケンスで画面制御を行なえるような Console ウィンドウが作られないとも限らないからです。その場合は CR も LF もそ のままもともとの意味通りの働きをさせなければなりません。だから絶対間違いない のは、上記の例のように CR,CF である \r\n と書いておくことです。 1993/4/20 小笠原博之 oga@dgw.yz.yamagata-u.ac.jp DenDenNET: DEN0006 COR.