X作成講座 on FB[02] (1)テンプレートの書き換え
さて実際に XCMD を作ってみましょう。一番単純なXの例として、2つの値を渡すとその合計を返す XFCN "tasu" を作ります。
作業は大きく分けて HyperXcmd.MAIN(テンプレート) の書き換え、ソース入力、STR#リソースの準備、の3つに分けられます。「また HyperXcmd.MAIN を書き換えるの?」と思われたかも知れませんが、このファイルはあくまでテンプレートであり、XCMD を作るたびにその XCMD 用に書き換えて使うように出来ているのです。
−・−・−
まず XCMD テンプレート フォルダをコピーします。分かり易いように "tasu.x folder" とでも名前を変えて下さい。この中の HyperXcmd.MAIN をダブルクリックしてFBII を立ち上げます。
説明しやすいように、ソースに行番号を付けて下さい。「編集」メニューの「プレファランス...」で右側にある「行番号を表示」にチェックを入れます。
では、テンプレートを解説しながら説明します。
書き換えの必要なところは "#" を付けてあります。
00006 GLOBALS "HyperXcmd.GLBL" 'get our globals file first 00007 END GLOBALS ここでグローバル変数を定義したファイルを読んでいます。 HyperXcmd.GLBL には XCMD 作成に必要なグローバル変数が定義されています。 00009 RESOURCES "", "STAKWILD", "XCMD", 6011, "<xcmd name>",_resPurgeable% コードリソースとしてコンパイルするための設定をしています。 各パラメータの意味はリファレンスマニュアルを参照して下さい。 # XFCN を作る場合は "XCMD" を "XFCN" に書き換えます。 # 6011 を希望するリソースIDに書き換えます。 # <xcmd name> に XCMD の名前 "tasu" を入れます。 00011 OUTPUT FILE "<stack name>" 'add xcmd to target stack # <stack name> に XCMD をインストールするスタック名を入れます。 00013 INCLUDE "HyperXcmd Events.INCL" 'load your own xcmd routines XCMD で必要になるイベント処理ファイルを読んでいます。 外部ウィンドウを作る場合にのみ必要です。 不要ならコメントアウトしてしまって構いませんが、その場合は イベントに関連するものを全てコメントアウトして下さい。 00015 ENTERPROC% (xCmdPtr&) 'use % because we are making a code rsrc ここからプログラムがスタートします。 xCmdPtr& には HyperTalk と値をやりとりするためのメモリブロックの アドレスを受け取っています。 00016 DIM rect;8 00017 DIM 63 title$ 必要ならここに DIM文を入れます。このテンプレートでは rect と title$ を 定義していますが、多分外部ウィンドウを作成するために入れたあとで、 削除するのを忘れたのでしょう。 今回は不要なのでコメントアウトしてしまって構いません。 00019 LONG IF xcmdID% = 0 00020 xcmdHndl& = FN RECOVERHANDLE (REGISTER(a4))'get handle to xcmd 00021 LONG IF xcmdHndl& 'we got a handle? 00022 CALL GETRESINFO (xcmdHndl&, xcmdID%, type&, tmp$)'get rsrc ID of xcmd 00023 END IF 00024 % REGISTER(A4) + _drvrMenu, xcmdID% 'set xcmd to read STR# ID 00025 END IF ここでは XCMD 自身の ID を xcmdID% に入れ、それを A4 レジスタに入れています。 これは XCMD と同じ ID の STR# リソースを読むための準備です。 00026 CALL GETPORT(hcPort&) 'save original port オリジナルのグラフポートを保存しています。 外部ウィンドウを使わないのであれば不要ですが、もしこの行をコメントアウト するなら、hcPort& を使っている全ての行をコメントアウトする必要があります。 00027 xCmdPtr&.passFlag% = _false 'keep HC from passing msg on パスフラグを false にしています。 ここを true にすると HyperTalk の pass xxx と同じ動作をします。 00029 prmCount% = xCmdPtr&.paramCount% 'get parameter count XCMD に渡された引数の数を prmCount% に入れています。 通常、HyperTalk から XCMD が呼ばれた時は、引数の数がここに入ります。 ところが外部ウィンドウを作成する XCMD では、HyperTalk から呼ばれる以外に HyperCard から「イベントが起きたよ」と呼び出される場合があります。 イベントによって XCMD が呼ばれた時は、prmCount% に -1 が入ります。 以下の IF 文ではこれを利用してイベント処理を分けています。 00030 LONG IF prmCount% => 0 'just passing some parameters 通常の XCMD 呼び出しならば・・・ 00031 LONG IF prmCount% <= _maxParams 'is paramcount count correct? 引数の数が設定範囲内ならば・・・ # この _maxParams は HyperXcmd.GLBL ファイル内で設定されています。 # ソースをどう分けて管理するかにもよりますが、この値は XCMD ごとに # 異なるので、私はここに直接値を書き込んでしまうのが良いと思います。 # 例えば引数を2つまで許すなら LONG IF prmCount% <= 2 とします。 00033 LONG IF prmCount% <> 0 00034 FOR j = 0 TO prmCount% - 1 'cycle thru parameters 00035 FN ZeroToPas (xCmdPtr&, [[xCmdPtr& + _params + j * 4]], str255$(j)) 00036 NEXT 'C string to P string 00037 END IF 各引数文字列(C文字列)を str255$() という文字列配列に格納しています。 当然 256バイト以降の文字は切り捨てられます。 00038 CALL INITCURSOR 'reset our cursor カーソルをアローカーソルに設定しています。 外部ウィンドウを扱う場合に必要です。 # 外部ウィンドウを扱わないのならコメントアウトした方が良いでしょう。 00040 SELECT UCASE$(str255$(0)) 'check first parameter value 第1引数の値によって分岐します。 00041 CASE "!" 'if '!' then return version info in msg 00042 FN ReplyToQuery (xCmdPtr&, _versionInfo)'send info 00043 00044 CASE "?" 'if '?' then return usage info in msg 00045 FN ReplyToQuery (xCmdPtr&, _usageInfo)'send info もし "!" が渡されたら、バージョン情報を返します。 もし "?" が渡されたら、書式情報を返します。 この2つは XCMD の標準的なインターフェースです。 バージョンと書式情報の返し方は後述しますが、FBではリソースを 利用するようになっています。 00047 CASE ELSE 00048 'handle normal xcmd parameters "!" でも "?" でもなかったら自前のルーチンを実行します。 # ここ(00048)に XCMD/XFCN のプログラム本体を書きます。 # 長くなりそうなら呼び出し部分だけをここに書いて、 # 本体を書いた別ファイルをインクルードするようにすると良いでしょう。 00051 XELSE 00052 FN ErrorHandler (xCmdPtr&, _wrongParams)'if paramcount incorrect 00053 END IF 'paramCount > 0 引数の数が規定値より大きかった場合のエラー処理です。 XELSE は 00031 からの分岐です。 00055 XELSE 00056 ' 00057 FN HandleHCEvent (xCmdPtr&) 'handle all windoid events here prmCount% が -1 だった場合、つまりウィンドウを持つ XCMD で イベントによる呼び出しを受けた場合の処理です。 XELSE は 00030 からの分岐です。 外部ウィンドウを扱わないXでは、ここが実行されることがありません。 00060 CALL SETPORT(hcPort&) 'restore original port 外部ウィンドウを使う場合は XCMD 中でカレントポートを移動するので、 ここで元に戻しています。 外部ウィンドウを使わないのであればコメントアウトして構いません。