UWSCのスレッド間で同じScriptControlを使う、とPUBLICでない文字列をスレッド間で共有する(相互更新可能)
UWSCでオブジェクトというと、ScriptControl経由でのJScriptオブジェクトが使いやすい。
しかし、こやつはスレッドを超えられない。
これをどうにかしたい。
結果:ieに依存してよければ超えられる
なお、PUBLICでない文字列をスレッド間で共有するだけなら、ieはいらない。
スクリプト
threadCOM.uws
OPTION EXPLICIT, OPTFINALLY IFB GET_UWSC_NAME = "threadCOM.uws" THEN DIM sc = CREATEOLEOBJ("ScriptControl") sc.Language = "JScript" DIM o = sc.Eval("({'val':'success!!!'})") MSGBOX("一部のCOMオブジェクトは、スレッドをまたげない") THREAD threadCOMTest(o) TRY MSGBOX("しかし、このモジュールを使えば!") threadCOM.Put(o) THREAD threadCOMTest() // 省略はスレッド内でモジュール経由で取得 SLEEP(2) o.val = "update!" MSGBOX("Disposeを忘れずに") FINALLY threadCOM.Dispose() ENDTRY ENDIF PROCEDURE threadCOMTest(obj=NULL) IF obj = NULL THEN obj = threadCOM.Get() DIM count = 0 TRY WHILE count < 5 BALLOON("成功! " + obj.val) SLEEP(1) count = count + 1 WEND EXCEPT BALLOON("失敗 " + VARTYPE(obj)) SLEEP(3) ENDTRY FEND MODULE threadCOM CONST _title = "ie for threadCOM" FUNCTION _GetIe(bCreate=FALSE) DIM ie COM_ERR_IGN ie = GETACTIVEOLEOBJ("InternetExplorer.Application", _title) COM_ERR_RET IFB COM_ERR_FLG THEN ie = NULL IFB bCreate THEN ie = CREATEOLEOBJ("InternetExplorer.Application") ie.Navigate("about:blank") ie.Document.Title = _title ENDIF ENDIF RESULT = ie FEND PROCEDURE Put(obj, name=_title) DIM ie = _GetIe(TRUE) ie.PutProperty(name, obj) FEND FUNCTION Get(name=_title) DIM ie = _GetIe() RESULT = NULL IF ie <> NULL THEN RESULT = ie.GetProperty(name) FEND PROCEDURE Dispose() DIM ie = _GetIe() IF ie <> NULL THEN ie.Quit() FEND ENDMODULE
解説
ScriptControlで作ったオブジェクトを別スレッドから参照しようとすると、エラーになります。
これをなんとかしようとした場合、グローバル変数にJSONを入れたりとか、そもそもScriptControlを管理する専用スレッドを立てたりとか、涙ぐましいことをする必要があります。
しかし、いろいろと不満が残ります。
そこでこのモジュールです。
ieオブジェクトには、GetProperty/PutPropertyというVariantに名前をつけて登録するメソッドがあります。
ieはGetActiveOleObjでスレッドをまたいでアクセスできるので、できるかなー、と思ったら案の定です。
Putの第二引数・Getの第一引数が名前の指定です。
省略していると、一つのオブジェクトしかもてませんが、指定すれば複数可能です。
ieに依存し、Dispose関数を呼び忘れるとゾンビができるのは、かなりイマイチですが、.参照するには現在この方法しか思いついてません。
ま、ゾンビも再利用されるので、いいっちゃいい気もしますが。
また、サンプルを動かすとわかりますが、別スレッドの変更をそのまま受けられるのもポイントが高いです。
PUBLICでないスレッドをまたげる変数になります。
でも、オブジェクトでなく文字列を共有したいだけなら、VBScript.RegExpはスレッドをまたげるようなので、VBScript.RegExpのPatternでも使ったらよいと思う。
DIM regexp = CREATEOLEOBJ("VBScript.RegExp") regexp.Pattern = "start" THREAD Func(regexp) SLEEP(1) regexp.Pattern = "up" SLEEP(5) PROCEDURE Func(regexp) DIM i = 0 WHILE i < 9 BALLOON(regexp.Pattern) SLEEP(0.5) i = i + 1 WEND FEND