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