UWSCでグローバルアトムを使う
前回の実行状態を保持したい場合、INIファイルを使うのが一般的ですね。
でも、POFF(P_UWSC_REEXEC,TRUE)で処理を続行するのにもINIを使うのは、なんかくやしくないですか?
そこで登場するのが、Global Atom!
まあ、制約多くて使いにくいですが
GlobalAtom、もうちょっとなんとかならなかったのか、という残念な仕様です。
使いにくい。
- NULL終端最大255バイト文字列が可能できるだけ
- キーという概念はない!(格納するとその時空いてた番号をくれる)
- 電源切ると消える
ま、電源切ると消えるのは良い点でもありますが、キーがないのは使えない。
ということで、全検索してキーを作りだすことにしました。
Atom.uws
OPTION EXPLICIT IFB GET_UWSC_NAME = "Atom.uws" THEN DIM loop = TRUE, key, buf WHILE loop DIM cmd = SLCTBOX(SLCT_STR, 0, "コマンドを選択してください", "Find", "Update", "Delete", "Dump") IFB cmd = "Dump" THEN Atom.Dump() ELSEIF cmd = -1 THEN loop = FALSE ELSE key = INPUT("キーを入力してください", "テストAtomキー") IFB cmd = "Delete" THEN IFB Atom.Delete(key) = 0 THEN PRINT cmd + " 成功" ELSE PRINT cmd + " 失敗" ENDIF ELSE buf = Atom.Find(key) IFB cmd = "Update" THEN IFB Atom.Update(key, INPUT("更新内容を入力してください", buf)) THEN PRINT cmd + " 成功" ELSE PRINT cmd + " 失敗" ENDIF ELSE PRINT cmd + " : " + buf ENDIF ENDIF ENDIF WEND ENDIF MODULE Atom CONST _BUF_SIZE = 256 CONST _BASE_NAME = "_juneUwscGAtom:" CONST _SEP = ":" CONST _MIN_ATOM_NO = $C001 CONST _MAX_ATOM_NO = $FFFF DIM _top, _baseLen DEF_DLL GlobalFindAtomW(wstring): WORD: kernel32 DEF_DLL GlobalAddAtomW(wstring): WORD: kernel32 DEF_DLL GlobalGetAtomNameW(WORD,var wstring,int): DWORD: kernel32 DEF_DLL GlobalDeleteAtom(WORD): WORD: kernel32 PROCEDURE Atom _baseLen = LENGTH(_BASE_NAME) //DIM buf, ret //FOR _top = _MIN_ATOM_NO TO _MAX_ATOM_NO // buf = FORMAT(CHR(0), _baseLen) // ret = GlobalGetAtomNameW(_top, buf, _baseLen) // IF buf = _BASE_NAME OR ret = 0 THEN BREAK //NEXT _top = _MIN_ATOM_NO _baseLen = _baseLen + 1 FEND FUNCTION Get(no) RESULT = EMPTY DIM len = 0, buf, ret = len WHILE ret > len - 2 len = len + _BUF_SIZE buf = FORMAT(CHR(0), len) ret = GlobalGetAtomNameW(no, buf, len) WEND IF ret > 0 THEN RESULT = buf FEND FUNCTION FindNo(name) RESULT = 0 DIM len = LENGTH(name) + _baseLen, buf, i DIM tar = _BASE_NAME + name + _SEP, ret FOR i = _top TO _MAX_ATOM_NO buf = FORMAT(CHR(0), len) ret = GlobalGetAtomNameW(i, buf, len) IFB buf = tar THEN RESULT = i BREAK ELSEIF ret = 0 THEN BREAK ENDIF NEXT FEND FUNCTION Find(name) DIM no = FindNo(name) IFB no = 0 THEN RESULT = EMPTY ELSE RESULT = COPY(Get(no), LENGTH(name) + _baseLen + 1) ENDIF FEND FUNCTION Update(name, data) DIM no = FindNo(name) IF no > 0 THEN GlobalDeleteAtom(no) RESULT = GlobalAddAtomW(_BASE_NAME + name + _SEP + data) FEND FUNCTION Delete(name) // 0が成功。失敗はAtom RESULT = GlobalDeleteAtom(FindNo(name)) FEND PROCEDURE Dump(t=ERR_VALUE) DIM i, buf IF t = ERR_VALUE THEN t = _top PRINT "Dump start " + t FOR i = t TO _MAX_ATOM_NO buf = Get(i) IFB LENGTH(buf) THEN PRINT i + ":" + buf ELSE BREAK ENDIF NEXT FEND ENDMODULE
使い方
Atom.uwsを実行してもわかるかもしれませんが、再起動絡みですとだいたいこんな想定です。
CALL Atom DIM key = "テストスクリプト用のキー" SELECT Atom.Find(key) CASE "再起動後" Atom.Delete(key) MSGBOX("メモリクリアされてすっきりなUWSC") DEFAULT MSGBOX("実行されました。いろいろ処理してメモリクリアしたくなる") Atom.Update(key, "再起動後") POFF(P_UWSC_REEXEC, TRUE) SELEND
もしくは、こんなスクリプト間連携にも使えます。
両方のスクリプトを実行してください。
こっちを実行すると、FUKIDASIが出ます。
CALL Atom DIM key = "連携キー", val = EMPTY FUKIDASI("連携相手待ち") WHILE val = EMPTY SLEEP(0.1) val = Atom.Find(key) WEND Atom.Delete(key) FUKIDASI() MSGBOX("「"+val+"」って言われた〜")
んで、こっちで入力したメッセージが、上のスクリプトに伝わるしかけ。
CALL Atom DIM key = "連携キー" Atom.Update(key, INPUT("連携相手にメッセージをどうぞ"))
言うまでもないですが、キー名は任意です。
両方のスクリプトで同じであればよいのです。