戻る
EXM形式プログラミング入門 津守 正樹 (Brahma) 95/02/14 改訂 02/22 0 はじめに HP100/200LX(以下HP100LXと表記)の内蔵PIMは極めて優秀であり、広範 な分野をカバーします。しかし、内蔵PIMでもカバーできない業務が発生し た場合、どうすればよいのでしょうか。 幸いにして、HP100LXはIBM-PC/XT互換機であり、MS-DOS Ver5 を内蔵して います。そのため、DOSアプリケーションを作成することにより、任意の業 務を行うことが可能です。ただし、通常のDOSアプリケーションでは、内蔵 PIMの様にメモリの許す限り起動し自由に切り替える、ということができま せん。 そこで本稿では、内蔵PIMの形式であるEXM形式のプログラムの作り方につ いて解説します。本稿で基礎知識を得て、本稿で挙げている開発資料を読め ば内蔵PIMと同様の特徴を持ったプログラムを作成することが可能です。 但し、本稿発表時点ではHP95LX用の開発キットしか一般公開されていない 為、その範囲内での開発について解説します。 本稿は、C言語の知識を持ち、ある程度のプログラムを組むことができる 人を対象とします。また、一般的なHP100LXに関する知識(用語、操作)に ついても持っていることを前提とします。 1 EXM形式とは EXM形式とはHP95/100/200LXの System Manager において動作するアプリ ケーションの形式です。ただし、EXM形式とは正式名称ではなく、正式には System Manager-Compliant Application と呼ばれます。本稿では、MS-DOS の一般的なプログラムの形式であるEXE形式と対比する為、及び表記の短さ と親しみやすさからEXM形式と表現します。 EXM形式の便利な点は、System Manager のタスクスイッチング機能を使用 できること、機能の共通化により実行形式のファイルサイズと実行時のメモ リの占有量が小さいこと、System Manager が提供するサービスを使用できる こと、などです。 逆に不便な点は、作成する上で守らなければいけない約束事がある、一般 的なC言語の関数で使用できないものがある、EXE形式からEXM形式への変換が 必要、メモリモデルは tiny か small モデルしか使えない、などです。 2 EXM形式作成上の留意点 一般的なDOSのプログラムを作成することに比べ、EXM形式のプログラムを 作成する場合は、以下の点に注意する必要があります。 ・メモリ管理 System Manager は独自のメモリ管理を行っていますので、従う必要が あります。具体的には動的なメモリの確保は全て System Manager 提供 の関数を使用します。そのため、一般的なC関数で使えなくなるものが あります。stdio.h関係がその例で、代替の関数が用意されています。 ・スタートアップコード 通常のC言語のスタートアップコードは使用できません。System Manager用のスタートアップコードを使用します(95開発キットに含ま れている)。このため、起動時の引数、環境変数は使えません。 ・初期化、終了処理 EXM形式プログラムの起動時と終了時には、m_init関数とm_fini関数を コールする必要があります。exit関数等は使用できません。 ・イベントループ 他のEXM形式プログラムと協調動作を行うために、プログラム内部で m_event関数やm_nevent関数を使ってイベント待ちを行う必要があり ます。キーボード入力はイベントループに含めなければなりません。 3 EXM形式作成に必要なもの 以下のものを用意して下さい。 ・HP95LXソフト開発キット FYHPPC LIB15 #22に登録されています。 特に、\tools\crt0.obj、\tools\csvc.obj、\headers\*.h は、コンパ イル時に必要となりますので、適切なディレクトリに収納しておいて 下さい。 ・HP100LX開発資料 NORIさんが配布して下さっています。 EXE形式からEXM形式に変換するツールの e2m.exe の新版が含まれてお り、新版はtlink対応になっています(但し古いバージョンのtlinkには 対応していません)。旧版は95開発キットに含まれています。 ・Cコンパイラ TC++/BC++をCコンパイラとして使用した場合に対応していることは確認 済みです。95開発キットがそのまま使用できます。また、推奨コンパイ ラは MS-C Ver.5.1以降です。それ以外のコンパイラについてはFYHPPC 8番会議室でお尋ね下さい。 筆者は TC++ Ver1.0 2ndEdition(98版)と MS-C Ver.6.00A(PS/55版)を HP100LX上で使用しています。 コンパイラによっては、ヘッダーファイルやスタートアップコードの 修正が必要になります。 ・ホストマシン 必要ではありませんが、開発効率を上げるために高速なマシンで開発す ることは有効です。PC98かIBM PC互換機を使用する人が多いようです。 コンパイラにも言えることですが、HP100LXがXT互換機だからといって PC互換機にこだわる必要はありません。機種依存の関数(グラフィック、 BIOS、サウンド等)とスタートアップコードを除けば、PC98用のコンパ イラでも使用可能なものが多いです。 ・HP95LXシステムマネージャドキュメント FYHPPC LIB15 #46に登録されている、HP95LXの System Manager に関す る資料です。 特に Chapter 7 と Chapter 8 は必読であり、Chapter 8 に関しては有 志の方々により和訳され、NORIさんが配布して下さっています (上記のHP100LX開発資料に含まれています)。 ・HP95LXプログラミングガイド FYHPPC LIB15 #47に登録されている、HP95LXのプログラミングに関する 資料です。 System Manager の内部処理について述べられており、EXM形式プログラ ミングの参考になります。 注:HP95LXソフト開発キットとHP95LXシステムマネージャドキュメントは HP/YHP社の好意により公開されているものでHP/YHP/Lotus社によるサ ポートは行われていません。 NORIさんが配布して下さっている資料は、プログラム開発の意図 を持った方の為にボランティアで配布して下さっているものです。開 発の意図がない方はご遠慮下さい。 4 プログラムの実際 論より証拠ということで、実際にプログラムを走らせてみます。 見慣れない関数や構造体がありますが、なにも言わず、コンパイル及び 実行をしてみて下さい。 以下のプログラムはHP95LXソフト開発キットに含まれている SMHELLO を さらに簡単にした、SMHELLOT(SMHELLO Tiny)です。 ========================================================= SMHELLOT.C #include "interfac.h" #include "event.h" #include <string.h> void app_display( void ); void main( void ) { EVENT appevent; int done = 1; m_init(); /* System Manager への初期化宣言 */ app_display(); /* 画面表示 */ do { /* イベントループ */ m_event( &appevent ); /* イベントの取得 */ switch ( appevent.kind ) { /* イベント種類の判定 */ case E_KEY: /* キー入力発生 */ done = 0; break; } } while( done ); m_fini(); /* System Manager への終了宣言(戻らない) */ } void app_display( void ) { m_setmode( 1 ); /* テキストモードにセット */ m_disp( 3, 5, "hello, world", strlen( "hello, world" ), 0, 0 ); /* 文字の表示 */ } ==================================================================== =========================================================== MAKEFILE smhellot.exm : smhellot.exe e2m smhellot smhellot.exe : smhellot.obj tlink /m smhellot+a:\tc\lib\csvc+a:\tc\lib\crt0,,,a:\tc\lib\cs.lib smhellot.obj : smhellot.c a:\tc\bin\tcc -ms -c -Ia:\tc\headers smhellot.c ==================================================================== 上記の二つのファイル(SMHELLOT.C,MAKEFILE)を任意のディレクトリに 入れ、MAKEFILEを自分のディレクトリ構成に合わせ修正します。あとは、 MAKEするだけで、SMHELLOT.OBJ,SMHELLOT.EXE,SMHELLOT.MAP, SMHELLOT.EXMが作成されます。但し、上記のMAKEFILEはTurboC用ですので、 開発環境に応じて変更して下さい。 SMHELLOT.EXMを登録して実行してみて下さい。キー入力により終了します。 5 プログラムの解説 各部分の解説をします。上記のソースには切り出しやすいように行番号 を付けませんでしたが、解説では行番号を使用します。 ・SMHELLOT.C 1行目 System Managerとのインターフェース用のインクルードファ イル 2行目 イベントサービス用のインクルードファイル 9行目 EVENT構造体の確保 これにより発生したイベントの情報を 得る 12行目 System Managerへの初期化宣言 (*) 13行目 画面表示の為app_disp関数をコール 15行目 ここから22行でイベントループを形成 16行目 イベントの取得を行う (*) 17行目 EVENT構造体に含まれたイベントの種類により分岐 18行目 イベントがキー入力ならイベントループから抜ける(〜20行) 24行目 System Managerへの終了宣言 (*) 30行目 画面をテキストモードに設定 (*) 32行目 "hello, world"という文字列を出力 (*) *の付いている行の関数は全て System Manager 提供の機能(System Manager Service)を実現する関数です。 ・m_init関数 EXMプログラムの最初(mainエントリポイント)で必ず呼び出す必要 があります。 ・m_event関数 キー入力やプログラム終了などのイベントを取得します。イベント が発生するか、タイムアウト(約0.5秒間)するまで、プログラムに 制御は戻りません。 ・m_fini関数 EXMプログラムの終了時には必ず呼び出す必要があります。この関数 呼び出し後は制御はプログラムに戻りません。exit関数やreturn関 数でEXMプログラムを終了することは禁止されています。 ・m_setmode関数 画面モードの設定を行います。ただし、設定できるのはHP95LX互換 モードのテキストモードとグラフィックモードだけです。 ・m_disp関数 文字列を画面に表示します。ただし、HP95LX互換モードでのみ動作 します。 このプログラムのように、入力待ちをするような場合は、全てイベント ループに含めます。これにより、効率的(ユーザーにとって無理のない) なタスクスイッチングを実現します。 当然のことではありますが、イベント待ち以外に待ちを作るべきでは ありません。HP100LXがそのプログラムに独占されてしまうからです。 m_event(m_nevent)関数によるイベント待ちを実行しないと、他のプログ ラムの起動はできませんし(hot key を認識しないため)、アラームも 機能しません。 またイベント待ちから次のイベント待ちに戻る時間が短い方が良いこと は言うまでもありません。 ・MAKEFILE MAPファイルを作成する必要がありますので、tlinkに /m オプションを 付けます(5行目)。crt0.obj は System Manager用スタートアップコー ド、csvc.obj は System Manager インターフェースモジュールです。 e2m.exe は、EXEファイルとMAPファイルからEXM形式ファイルを作成 します(2行目)。 6 System Manager Service System Manager Service は機能別に以下の19に分けられます。 ・イベントサービス (Event Services) ・メニューサービス (Menu Services) ・ファイルメニューサービス (File Menu Services) ・スクリーンサービス (Screen Services) ・編集サービス (Editing Services) ・ファイルサービス (File Services) ・プロセス管理サービス (Process Management Services) ・クリップボードサービス (Clipboard Services) ・サウンドサービス (Sound Services) ・メモリ管理サービス (Memory Management Services) ・日付/時間サービス (Date/Time Services) ・印刷サービス (Printer Services) ・設定サービス (Configuration Services) ・通信サービス (Communications Services) ・その他サービス (Miscellaneous Services) ・リソースサービス (Resource Services) (*) ・ヘルプサービス (Help Services) (*) ・比較サービス (Collating Services) ・123ブリッジサービス (1-2-3 Bridge Services) SMHELLOT に使用した、m_init関数,m_fini関数はプロセス管理サービス m_event関数はイベントサービス、m_setmode関数,m_disp関数はスクリーン サービスに所属します。 各サービスの詳細は HP95LXシステムマネージャドキュメント Chapter 8 を参照して下さい。*の付いているサービスは内蔵PIM用であり、自作プロ グラムには使用できません。 7 イベント SMHELLOT はEXM形式のプログラムですが、System Managerのプログラ ムらしくありません。実行してみると分かりますが、起動中に別のプロ グラムを起動して戻った場合、画面が表示されないからです。 System Manager はイベントとタスク、メモリの管理を行っていますが 個々のプログラムの画面表示の管理まではしてくれません。 別のプログラムが起動した後、プログラムが再びアクティブになった 際にはイベントが発生します。すなわち、 System Manager がEVENT構造 体によりイベントとして連絡してくれますので、アクティブになったプロ グラム自身が画面の再表示を行う必要があります。 この際、画面のイメージを保存しておくと高速に再表示することが可能 ですが、メモリを余計に消費しますのでそのようなことはしないことが推 奨されています。 では、SMHELLOT に再表示の機能をつけ加えます。17行目の下に以下の プログラムをつけ加えて下さい。 case E_ACTIV: app_display(); break; プログラムが再度アクティブになった際には appevent.kind に E_ACTIV が代入されています。それを判定して再度画面の表示を行うわけ です。 イベントには以下の12種類が存在します。 ・E_ACTIV プログラムがアクティブになった際に発生 ・E_ALARM_DAY プログラムがアラームをセットする為のイベント ・E_ALARM_EXP 設定したアラーム時刻になった際に発生 ・E_BREAK Ctrl+Breakキーを押した際に発生 ・E_BRIDGE ブリッジサービス要求時の123専用のイベント ・E_DEACT 他のプログラムの起動により非アクティブ状態になる 際に発生 ・E_GROW 123への拡張要求 ・E_KEY キー入力が発生した際に発生 ・E_NONE イベント無し ・E_SHRINK 123への縮小要求 ・E_TERM プログラムが終了させられた際に発生 ・E_TIMECHANGE システムの日時が変更された際に発生 これらのイベントに応じた対応をプログラミングすることにより、効率的 に System Manager の機能を利用し、高機能かつ使いやすいプログラムを 実現します。 タスクスイッチングを行う上で重要なことは、E_DEACT,E_TERM の各イベ ントが発生した場合、次にイベント待ち(m_event(m_nevent)関数のコール) になってはじめて、非アクティブ化やプログラムの終了が行われる、という 点です。つまり、非アクティブ化やプログラムの終了が発生しても、一度は 制御がプログラムに戻されるということです。そのため、E_DEACT,E_TERM イベントの検出により、クリップボードの更新やファイルのクローズ等の 必要な処理を行うことができます。 8 イベントループを持たないEXM形式プログラム 一般的にはEXM形式プログラムはイベントループを持ちますが、待ちが 発生しないプログラム、あるいは他のアプリケーションを起動したくない プログラムなら持たないことも可能です。ただし、そのプログラムの実行中 はタスクスイッチングを行うことができません。 その例としてプログラムを一つ示します。クリップボードの読み書きと ファイルアクセス、DOSプログラムの起動を行っていますので、そちらも 参考にして下さい。 =========================================================== DOSCOM.C #define TFNAME "a:\\sys\\doscom.tmp" #define REDIRCT " > "TFNAME"\r" #include "interfac.h" #include "fileio.h" #include <string.h> void app_main(void); void main( void ) { m_init(); app_main(); m_fini(); } void app_main( void ) { char com_buf[128], rbuf[1024]; int index, len; FILE fd; com_buf[0] = '\0'; m_setmode( 1 ); if( m_open_cb() != 0 ) /* クリップボードのオープン */ return; if( m_rep_index((char far *)"TEXT", (int far *)&index, (unsigned *)&len) != 0 ) { /* TEXT形式のインデックスの取得 */ m_close_cb(); /* クリップボードのクローズ */ return; } m_cb_read( index, 0, rbuf, len ); /* クリップボードから読み出し */ m_close_cb(); rbuf[ len ] = '\0'; strncat( com_buf, rbuf, sizeof( com_buf )); strncat( com_buf, REDIRCT, sizeof( com_buf )); if( m_spawn( com_buf, strlen( com_buf ), 2, "Wait a minute." ) != 0 ) /* 文字列をCOMMAND.COMに渡す */ return; if( m_open( &fd, TFNAME, strlen( TFNAME ), 0, 0 ) != 0 ) /* ファイルのオープン */ return; if( m_open_cb() != 0 ) { m_close( &fd ); /* ファイルのクローズ */ return; } if( m_reset_cb( "DOSCOM" ) != 0 ) { /* クリップボードの内容のクリア */ m_close_cb(); m_close( &fd ); return; } m_new_rep( "TEXT" ); /* TEXT形式でデータを受け取るようクリップボードをセット */ m_read( &fd, rbuf, sizeof( rbuf ), &len ); /* ファイルから読み出し */ m_cb_write( rbuf, len ); /* クリップボードに書き込み */ m_fini_rep(); /* 現在の形式のデータの終了をクリップボードに通知 */ m_close_cb(); m_close( &fd ); } ==================================================================== 特に説明は加えませんが、クリップボードの文字列をそのままコマンド として実行し、結果をファイル経由でクリップボードに収納しているプロ グラムです。System Manager上からDOSコマンドを実行する為のプログラム です。 ただし、データが日本語か否かの判定を行っていませんので、ペースト 時に文字化けを起こすことがあります。これは、クリップボードから取り 出したデータの最後が2バイトコード(日本語)の1バイト目になっている かをチェックすることにより回避可能です。 実行しDOSコマンドが終了すると必ずキー入力を求めますが、これは m_spawn関数の特性です。起動するプログラムがキー入力を受け付けない 性質のものなら、キーバッファに任意のキー入力をストアしておくことに より回避可能です(INT 16H)。 クリップボード使用上の注意点ですが、オープンしたままプログラムを 終了すると他のプログラムがクリップボードをオープンできなくなる為、 クリップボードが使えなくなります。また、ファイルをオープンしたまま プログラムを終了した場合は、他のEXM形式プログラムの動作に悪影響を 及ぼすことがあります。但し、ファイルのオープンとクローズは一対一で 対応するようにして下さい(クローズが多くても悪影響を及ぼします)。 9 開発キットの問題点 HP100LXでEXM形式プログラミングを行うにあたり、現在公開されている 開発キットにはいくつか問題があります。 これは、公開されているのがHP95LX用であるということに起因します。 ・画面モード m_setmode関数はHP95LX用の画面モードにしか対応していません。 そのため、別の手段でCGAモードに変更しますが、その際いくつか の関数が使用できなくなります。m_disp関数等です。 ・メニューサービス HP95LXとHP100LXではメニューが変わっていますが、公開されているの はHP95LX用ですので、HP95LX風のメニューしか使えません。 ・イベントサービス m_event関数では特に不具合は確認されていませんが、m_nevent関数を 使用するとシステムマクロが正常に動作しなくなります。 この他にも、m_spawn関数がLotus123と併用できない等、いくつかの不具 合が存在します。 デベロッパー登録を行うとHP100LX向け開発資料とライブラリ類が手に入 りますが、現在は登録が中止されているとのことです。一般公開できるよう にNORIさんがHP/YHP社に働きかけて下さっています。 10 より知識を得るために HP100LXでEXM形式プログラミングを行うにあたり、DOS Function Call や BIOS Call が使用できます(一部に制限がかかる場合があります)。 その為、一般に流通しているDOS/V関係の書籍も資料として有効です。 また、FYHPPCのLIBに登録されているプログラムの一部にはソースコード が添付されています。他人の書いたソースコードを読むことは大変参考に なりますので、お勧めします。 11 おわりに 本稿は筆者がHP100LXでプログラミングを始めて一ヶ月の時点で中本さん の要請に応じて書いた文章(FYHP MES16にアップ)を補足修正したものです。 当時、ここまでの知識が得られたのは、苦労してHP95/100LXの環境を整備 してこられた先輩方のおかげであり、感謝の念に絶えません。この場をお借 りして、深くお礼申し上げます。 あれから半年しか経っていないのですが、EXM形式のプログラミング技術 を取得された方も増え、数多くの魅力的なソフトウェアが公開されました。 隔世の感もありますが、本稿の原版が少しは貢献できたのではと自負して おります。 本稿がHP100LXでのプログラミングを始める方の手助けとなることを祈り 結びとさせていただきます。 12 付記 ・本稿はフリーソフトウェアと同等の扱いとします。 ・本稿から得た知識に対して対価を支払う必要はありませんが、その成果 をNIFTY-Serve FYHPPCで公開することを希望します(強制ではありませ ん)。 ・本稿の著作権は筆者(津守正樹,Brahma)にあります。 ・個人レベルでの再配布は許可しますが、不特定多数への配布や転載に 関しては筆者に許可を得て下さい。また、再配布を行う場合は被配布者 に最新のバージョンを提供するよう心がけて下さい。 ・本稿は各種資料から得た知識、独自に解析した結果、どなたかから教え て頂いた情報等を元に、筆者なりに理解している内容を記述したもの です。内容の正確さ、不正確なことにより被る不利益に関しては、一切 保証しません。 ・本稿に関する質問、意見等はFYHPPC 8番会議室において受け付けます。 メイルによる質問も受け付けますが、的を得た質問の場合はFYHPPC 8番 会議室で引用させていただくことがありますので予めご了承下さい。 付録 HP100LX用開発キットを用いたプログラミング 本稿発表時点では一般公開されていませんが、HP100LX用開発キット (Developer's GuideとISVディスケット)を用いると、HP100/200LX搭載の System Managerに対応したEXM形式プログラムを作成することが可能です (但しHelpコンパイラが添付されていないためHelp機能は使えません)。 そして、中本さんが独自の開発キット(以下NKITと表記)を開発し公開 して下さったため、デベロッパー登録をしなくてもHP100/200LX用のAPIを 使用したプログラムの作成が可能になりました。 以下に、HP95LX用からの変更点とサンプルプログラムを付記します。 付1 HP95LX用からの変更点 プログラマから見て、以下の点が変更されました。 ・APIの変更 System Manager Service (System Manager API)がいくつか新設及び 廃止、変更されました。詳しくは後述します。 ・LHAPIの導入 メニュー、ファイルメニュー、スクリーン、編集の各サービスが廃止 され、LHAPI(Lotus Handheld Application Programming Interface)が 導入されました。LHAPIとはHP100LXに内蔵されたGUIルーチン群です。 LHAPIにより、容易にCUAに沿ったインターフェースを利用することが できます。 LHAPIに関する詳細は、8番会議室で不定期連載中(本稿発表時点)の LHAPI入門を参照して下さい。 ・アプリケーションDataブロックの移動 System ManagerはEXM形式プログラムのDataブロックを勝手に移動させ てしまう為、farポインタのセグメントの扱いに注意する必要がありま す。 実際にはHP95LX用開発キットでも同じ問題は存在していたのですが、 関数の引数の殆どがnearでしたので意識する必要があまりありません でした。しかし、HP100LX用の関数はfarポインタを要求するものが多く 特にLHAPIでは必ず使用します。その為、対策が不可避となってきます。 その他にも、イベント管理等が変更されています。 HP純正の開発キットでは推奨コンパイラであるMS-C(Ver.6以降)に特有の 機能を使用していますので、他のコンパイラを使用するのが困難になって います。NKITでは、TurboCやLSI Cによる開発が可能です。 付2 関数の新設及び廃止 以下の関数が新設及び廃止されました。また、名称が同じでも機能や引数 が変更されたものもあります。 各新設関数の一行説明については、おおはたさん、中本さんの解析を参考 にさせていただいています。 ・イベントサービス → イベント管理サービス 廃止 ・m_event ・m_nevent 新設 ・m_action イベント要求(イベント取得等)を与えて実行する ・メニューサービス LHAPIに移行 ・ファイルメニューサービス LHAPIに移行 ・スクリーンサービス LHAPIに移行 ・編集サービス LHAPIに移行 ・ファイルサービス → ファイルI/Oサービス 新設 ・m_card_changes カード差替回数を取得する ・m_flush 不明 ・m_get_drive_list 有効なドライブリストを取得する ・プロセス管理サービス 廃止 ・m_init ・(m_spawnarg) 新設 ・(m_appcount) ロードされているアプリケーション数を取得する ・m_get_TCB TCB(Task Control Block)配列へのポインタを取得する ・m_get_TCB_size TCBへの登録最大数を取得する ・m_init_app システムマネージャーレベルの初期化処理を行う ・m_keylock ホットキーによるタスクスイッチを禁止する ・m_keyunlock ホットキーによるタスクスイッチを許可する ・クリップボードサービス 廃止 ・m_rep_name 新設 ・m_get_cb_info クリップボードの情報を取得する ・サウンドサービス 新設 ・m_play 7オクターブの音楽を演奏する ・メモリ管理サービス 新設 ・m_current_task 現在のタスク番号を返す ・m_enable_app_key ロックされたブルーキーを利用可能にする ・m_free_static_block 確保したstatic領域を開放する ・m_free_SVC_entry S_SERVICEエントリーを開放する ・m_get_active_DOS_size 不明(動作中のDOSアプリが使用しているメモリ量の取得?) ・m_get_avail_123_mem 123メモリ確保関数で確保可能なサイズを取得する ・m_get_avail_init_mem アプリケーションスタート時の利用可能領域のサイズを取得する ・m_get_avail_mem 拡張可能なnear領域のサイズを取得する ・m_get_avail_static_mem 確保可能な最大のstatic領域のサイズを取得する ・m_get_DOS_hot_key 不明(DOS起動キーを取得?) ・m_get_DOS_part_size 不明(Setupで設定したDOSサイズを取得?) ・m_get_far_block System Managerが使用するfar領域を割り当てる ・m_get_far_handle farポインタへのnearハンドルを取得する ・m_get_far_user_handle ユーザー用のfarポインタへのnearハンドルを得る ・m_get_static_block staticブロックを確保する ・m_get_static_size 不明(Setupで取得したstaticサイズを取得?) ・m_get_static_used 不明(使用中のstatic領域のサイズを取得?) ・m_get_SVC_entry S_SERVICEへのエントリポイントを取得する? ・m_load_client リダイレクタをロードする ・m_load_TSR 特別なTSRをstatic領域にロードする ・m_locate_SVC 特定のS_SERVICEエントリへのポインタを取得する ・m_lock_out_app_key ブルーキーをロックしTCBを更新する ・m_modify_hot_key 実行中のタスクのホットキーを変更する ・m_QuickKeyCheck イベントループ前に山越でキーを取得する ・m_reg_far 間接farテーブルを登録する ・m_set_DOS_hot_key DOS起動キーを設定する ・m_set_DOS_part_size 次に起動するDOSアプリのサイズを設定する ・m_set_far_block 間接farブロックの領域を拡張、縮小、開放する ・m_set_static_size static領域のサイズを設定する ・m_task_info TCB情報を取得する ・m_unload_client リダイレクタを開放する ・日付/時間サービス 廃止 ・m_alarm ・(m_posttime) 新設 ・m_keybez 内蔵インターナショナルキーボードサポートをチェックする ・m_nalarm アラームを待ち行列に加えペンディング情報を取得する ・m_nfalarm 条件に一致するアラームを検索する ・印刷サービス 新設 ・m_write_printer_atb プリンタへアトリビュートを送信する ・m_trans_printer_atb バッファへアトリビュートを収納する ・設定サービス 日付/時間サービスに併合 ・通信サービス 廃止 ・ComAnswer ・ComCommand ・ComConfigure ・ComDial ・ComGet ・ComGetModem ・ComHangUp ・ComSet ・ComSetDtr ・ComStatus 新設 ・ComAcqReceiveBytes ポートの獲得と受信を行う ・ComAcqSendBytes ポートの獲得と送信を行う ・ComAcquire ポートの使用権を排他的に獲得する ・ComGetParameters 回線設定を取得する ・ComMdmClr モデムラインをクリアする ・ComMdmSet モデムラインをセットする ・ComMdmStatus UARTのMCRとMSRを取得する ・ComPower 通信ポートの電源オンオフ操作をアプリケーションに許可する ・ComRelease ポートの使用権を解放する ・ComSetParameters 回線設定を設定する ・その他サービス 廃止 ・drawbox ・m_errmsg ・message ・message3 ・msg_off ・showname 新設 ・m_disable_macros マクロの実行・記録を禁止する ・m_enable_macros マクロの実行・記録を可能にする ・m_get_sysver System version IDを得る ・m_playback_macro マクロを再生する ・m_ram_iv_info RAMイメージベクタのアドレスとアクティブな数を取得する ・m_start_record 動作中のマクロを停止し、マクロの記録を開始する ・m_stop_record 現在記録中のマクロの記録を終了する ・m_sys_rsrc_addr システムリソースアドレスを含む文字列を取得する ・m_update_apname_list 全ドライブのAPNAME.LSTを更新する ・リソースサービス 新設 ・m_GetKeyLabel スキャンコードから覚えやすい文字列を取得する ・m_GetScanCode 覚えやすい文字列からスキャンコードを取得する ・m_InitKeyLabels キーラベルとスキャンコードのテーブルを初期化する ・ヘルプサービス 廃止 ・m_help_display ・m_help_init ・m_help_key ・m_help_term 新設 ・m_help2_display ヘルプスクリーンデータを表示する ・m_help2_getmetrics ヘルプスクリーン座標を取得する ・m_help2_init ヘルプシステムを初期化する ・m_help2_key ヘルプシステムにキー入力を渡す ・m_help2_term ヘルプシステムを終了する ・比較サービス 新設 ・m_colLicsChar LICS文字をソートオーダーで比較する ・m_colLicsStr LICS文字列をソートオーダーで比較する ・123ブリッジサービス 不明 ・API管理サービス(新設) ・m_clear_api_error 直前のクラス/関数のエラーをクリアする ・m_disable_fnct_tbl 関数テーブルで最初の無効にされていない関数を無効にする ・m_enable_fnct_tbl 最後に無効にした関数を有効にする ・m_get_api_error 直前にエラーを起こした関数IDを取得する ・m_get_class_tbl 関数テーブルのアドレスを取得する ・m_get_free_api_class クラスグループを指定し登録可能なクラスIDを取得する ・m_insert_fnct_tbl ディスパッチ行列に関数テーブルを追加する ・m_remove_fnct_tbl ディスパッチ行列から関数テーブルを削除する ・m_search_api_class 指定されたグループから検索文字列と一致するクラスを探す ・m_valid_api_fnct クラス/関数の状態を取得する ・LHAPIサービス(新設) ・ClearError LHAPIBLOCK構造体のエラー番号とハンドラをクリアする ・ClearRect 画面の一部を白く消去 ・DeactivateLHAPI LHAPIに非アクティブになる旨を通知する ・DrawChar 1文字を表示する ・DrawFKeys ファンクションキーを表示する ・DrawNChars 最大数を指定してテキストを表示する ・DrawText テキストを表示する ・GetCurrentFont カレントに定義されたシステムフォントを取得する ・GetDefaultFont デフォルトフォントを取得する ・GetError エラー番号を取得する ・GetErrorHandler エラーハンドラーを取得する ・GetFocus フォーカスされたウィンドウへのポインタを取得する ・GetLHAPIBlockPtr LHAPIBLOCK構造体へのオフセットアドレスを取得する ・GetLocalClipping ローカルクリッピング領域を取得する ・InitializeLHAPI LHAPIBLOCK構造体の初期化を行う ・IntersectLocalClipping 特定の矩形領域と交差するローカルクリッピング領域を定義する ・Line 線を描画する ・Outline 矩形を黒線で被う ・Panel パネルを表示する ・ReactivateLHAPI LHAPIBLOCK構造体の再構築する ・Rectangle 色とフラグを指定して矩形を表示する ・RegisterFont 定義された内から使用するフォントを設定する ・ResetAlt ALTキーリリース時のMENUキー入力メッセージ発生の防止する ・ResetRepRule 低位の画素置換ルールをLHAPI定義のデフォルトにリセットする ・ResetVideo 内部LHAPIビデオ状態変数をリセットする ・SendAllMsg メッセージを全ウィンドウに送る ・SendFocusMsg フォーカスされたウィンドウにメッセージを送る ・SendMsg 特定のウィンドウにメッセージを送る ・SetCurrentFont カレントのシステムフォントを設定する ・SetDefaultFont デフォルトフォントを設定する ・SetError LHAPIBLOCK構造体のエラー番号を設定する ・SetErrorHandler エラーハンドラーを設定する ・SetGlobalClipping グローバルクリッピング領域を設定する ・SetHelpFkey アプリケーション内共通のヘルプキーを設定する ・SetLocalClipping ローカルクリッピング領域を設定する ・SetMenuFont メニューに使用するシステムフォントを設定する ・SetRepRule 低位の画素置換ルールを設定する ・ShadowBox 影付きのパネルを表示する ・ShowSymbol 特殊シンボルを表示する ・SubclassMsg 自分以外のクラスハンドラにメッセージを送る ・UninitializeLHAPI LHAPIに終了を通知する 付3 サンプルプログラム 4章で例示した SMHELLOT を改造したサンプルプログラムを以下に示し ます。LHAPIを使用しており、その定義の為に少々長くなっています。 ========================================================= LHHELLOT.C #if defined(NKIT) #include "lxapi.h" /* NKIT専用ヘッダ */ #else #include "cap2.h" /* LHAPI定義 */ #include "interfac.h" /* System Manager API定義 */ #include "event.h" /* EVENT構造体定義 */ #include "sysdefs.h" /* システム定数定義 */ #endif char far *msgNull = ""; /* ダミー */ char far *msgAppName = "Hello"; /* タイトル */ char far *msgHello = "hello, World"; /* 表示文字列 */ char far **StringTable[] = { &msgNull, &msgAppName, &msgHello, }; int far MainHandler( PLHWINDOW, WORD, WORD, WORD,...); BOOL Done; /* イベントループ脱出用フラグ */ LHAPIBLOCK LHAPIData; /* LHAPI管理領域 */ EVENT_NORM app_event; /* イベント管理用構造体 */ LHWINDOW MainView = { /* アプリケーション本体オブジェクト */ (PLHCLASS)MainHandler, 0, 0, 640, 200, &msgNull, 0, 0, 0, NULL, NO_FKEYS, NO_MENU, NO_HELP }; LHWINDOW MainTitle = { /* タイトルバー */ TitleBar, 0, 0, 0, 0, (PLHRES)&msgAppName, 0, 0, TITLE_NODATETIME|STYLE_NOFOCUS, NULL, NO_FKEYS, NO_MENU, NO_HELP }; #if defined(TURBOC) #define GetDataSeg() _DS #endif #if defined(LSIC) int _asm_(char *); #define GetDataSeg() _asm_(" mov ax,ds\n") #endif void FixupFarPtrs( void ) /* Dataブロック移動対策(注) */ { int i, dataseg; #if defined(MSC) _asm { mov ax,ds mov dataseg,ax } #else dataseg = GetDataSeg(); #endif for ( i = 0; i < countof( StringTable ); i++ ) *((( int *)( StringTable[i] )) + 1 ) = dataseg; } int far MainHandler( PLHWINDOW Wnd, WORD Message, WORD Data, WORD Extra,...) /* アプリケーション本体オブジェクトのハンドラ */ { if(( Message == DRAW ) && ( Data & DRAW_FRAME )) { /* 表示メッセージ */ /* CREATE,E_ACTIVE,E_REFRESH時に送られる */ ClearRect(Wnd->x,Wnd->y,Wnd->w,Wnd->h); /* 画面のクリア */ DrawText( 200, 80, msgHello, DRAW_NORMAL, FONT_DEFAULT ); /* 文字列の表示 */ } return SubclassMsg(Object, Wnd, Message, Data, Extra); /* 親クラスにメッセージを転送(親クラスの機能を継承) */ } void main( void ) { m_init_app( SYSTEM_MANAGER_VERSION ); /* System Managerへの初期化宣言 */ InitializeLHAPI( &LHAPIData ); /* LHAPIブロックの初期化 */ SetDefaultFont(FONT_LARGE); /* デフォルトフォントの設定 */ m_reg_app_name( msgAppName ); /* アプリケーション名の登録 */ SendMsg( &MainView, CREATE, CREATE_FOCUS, 0 ); /* アプリケーション本体オブジェクトの生成 */ SendMsg( &MainTitle, CREATE, CREATE_NORMAL, 0 ); /* タイトルの生成 */ Done = FALSE; /* DoneがTRUEでイベントループから脱出 */ while( !Done ) { /* イベント(ディスパッチ)ループ */ app_event.do_event = DO_EVENT; /* イベント取得を設定 */ m_action( &app_event ); /* イベント処理 */ switch( app_event.kind ) { /* イベントの種類で分岐 */ case E_ACTIV: /* 再アクティブ化要求 */ case E_REFRESH: /* 画面再描画要求 */ FixupFarPtrs(); /* Farポインタの修正 */ ReactivateLHAPI( &LHAPIData ); /* LHAPIにACTIVE化を通知 */ break; case E_DEACT: /* 非アクティブ化要求 */ DeactivateLHAPI(); /* LHAPIにDEACTIVE化を通知 */ break; case E_TERM: /* 強制終了要求 */ case E_BREAK: /* CTRL+BREAKを検出 */ case E_KEY: /* キー入力を検出(ブルーキーを除く) */ FixupFarPtrs(); /* Farポインタの修正 */ Done = TRUE; /* イベントループ脱出 */ break; } } m_fini(); /* System Managerへの終了宣言(戻らない) */ } ==================================================================== (注) Dataブロックの移動は、再アクティブ化のときだけ発生するわけでは ありません。動的なメモリの確保(アプリケーション自身、System Managerによるものを問わず)の際には移動することが考えられます。 その為、上記のFarポインタの修正方法では問題が起きうるのですが 今回は単機能のサンプルプログラムということで考慮していません。 また、LHAPI入門のサンプルプログラム1でも同様になっています。 =========================================================== MAKE.MSC DSTNAME = lhhellot MSCDIR = a:\c700 OKITDIR = a:\dev\100exm LIBDIR = $(OKITDIR)\libs INCDIR = $(OKITDIR)\headers STACK_SIZE = 0x1000 COPTS = /DMSC CFLAGS = /AS /Ze /Oswl /Gs /G1 /DNDEBUG /DAPI2 /DOFFICIAL $(COPTS) LFLAGS = /CP:0xffff /NOI /NOE /NOD /MAP /SE:0x80 /ST:$(STACK_SIZE) SYS_LIBS = $(LIBDIR)\bb.lib $(LIBDIR)\mlhstub.lib $(LIBDIR)\caprea.lib $(DSTNAME).exm: $(DSTNAME).exe e2m $(DSTNAME) $(DSTNAME).exe: $(DSTNAME).obj $(SYS_LIBS) \(MSCDIR)\bin\link $(LFLAGS) @<< $(DSTNAME).obj,$(DSTNAME).exe,,$(SYS_LIBS); <<NOKEEP .c.obj: \(MSCDIR)\bin\cl /c /I$(INCDIR) $(CFLAGS) $*.c ==================================================================== =========================================================== MAKE.TCC DSTNAME = lhhellot TCDIR = a:\tc NKITDIR = a:\dev\nkit COPT = -1 -G -DNKIT -DTURBOC $(DSTNAME).exm : $(DSTNAME).exe e2m $(DSTNAME) $(DSTNAME).exe : $(DSTNAME).obj $(TCDIR)\bin\tlink /m $(NKITDIR)\tccstart+$(DSTNAME)\ +$(NKITDIR)\tcclib,$(DSTNAME),, $(DSTNAME).obj : $(DSTNAME).c $(TCDIR)\bin\tcc $(COPT) -ms -c -I$(NKITDIR) $(DSTNAME).c ==================================================================== =========================================================== MAKE.LSI DSTNAME = lhhellot LSICDIR = a:\lsic NKITDIR = a:\dev\nkit COPTS = -DNKIT -DLSIC $(DSTNAME).exm : $(DSTNAME).exe e2m $(DSTNAME) $(DSTNAME).exe : $(DSTNAME).obj $(LSICDIR)\bin\lld -M -o $(DSTNAME).exe $(NKITDIR)\lsistart.obj $(DSTNAME).obj $(NKITDIR)\lsilib.obj $(DSTNAME).obj : $(DSTNAME).c $(LSICDIR)\bin\lcc -c $(COPTS) -I$(NKITDIR) $(DSTNAME).c ==================================================================== LHHELLOT.Cは純正開発キットとNKITに対応しています。MAKE.MSCはMS-C用 (純正)、MAKE.TCCはTurboC用(NKIT)、MAKE.LSIはLSI C用(NKIT)です。 動作確認はそれぞれ、MS-C Ver6.00A(PS/55版)、TurboC++ Ver1.0 2ndEdition(98版)、LSI C-86 Ver3.30c 試食版、で行いました。 LHAPI固有の部分を除けば、関数が変わっただけの部分が多いため解説は 省きます。LHAPI固有の部分に関してはLHAPI入門を参照して下さい。 95LX用の開発と比べ、プログラムの流れで変わったのはイベント処理です。 従来のm_event(m_nevent)関数はSystem managerに制御を渡し、イベント の発生を待つタイプの関数でした。しかし、m_action関数はSystem Manager に制御を渡した後の動作を指定できます。 動作の指定はEVENT_NORM構造体のdo_eventメンバで行い、以下の種類が存 在します。 ・DO_EVENT イベント待ちを行う ・DO_YIELD アプリケーションをasleep状態にする ・DO_FINI アプリケーションを終了させる ・DO_NO_EVENT イベント待ちをせずイベントを取得する ・DO_NO_FINI アプリケーションの終了を阻止する ・DO_BRIDGE 123とのブリッジサービスを行う ・DO_IC_INIT タスク間通信(IC)を開始する ・DO_IC_CLOSE タスク間通信を終了する ・DO_SWAP ICセッションにある他のアプリケーションにスワップする ・DO_LAUNCH EXM形式プログラムを起動する ・DO_EXEC DOSプログラムを起動する ・DO_DOS_CLOSE 起動中のDOSプログラムを強制終了する ・DO_REFRESH フォアグラウンドのアプリケーションにE_REFRESHイベントを送る ・DO_SERVICE_COMPLETE 特別TSRの処理を終了する ・DO_REQUEST_FOREGROUND 自タスクをフォアグラウンドにする ・DO_CLOSE_APP EXM形式プログラムを終了させる ・DO_EXEC_FULL DOSプログラムを完全コントロール下で起動する ・DO_EXIT_SYSMGR System Managerと総てのアプリケーションを終了させる ・DO_MOVE_TO_END 自タスクを待ちキューの最後におく これらの指定により、高度なマルチタスクプログラミングを実現します。 サンプルプログラムでは、do_eventメンバにDO_EVENTを代入してm_action 関数を実行しており、これは従来のm_event関数に該当します。
All contents and programs Copyright 1996,97,98 (C) by Masaki " Brahma " Tsumori all rights reserved.