PowershellとUWSCの連携
UWSCのPowershell関数は遅い。
恐らくアセンブリのロードに時間がかかるのだろう、、、。
二回目以降でも遅い。
なんとか早くしたいので、考えてみた。
そうだPowershellからUWSCを呼び出そう
Powershellを呼び出すのが遅いなら、PowershellからUWSCを呼べば良いじゃない!
ただ、UWSCに直接オブジェクトを注入する方法は思いつかなかったので、
Powershell <-> ie <-> UWSC
とする。
UWSCは特定のIEを監視して、EVALする、ということ。
p2u.uws
OPTION EXPLICIT p2u.Run() MODULE p2u DIM __regexp PROCEDURE p2u __regexp = CREATEOLEOBJ("VBScript.RegExp") FEND PROCEDURE Run() DIM __p2uIe = GETACTIVEOLEOBJ("InternetExplorer.Application", "Powershell uwsc bridge") DIM __p2u = __p2uIe.document.getElementsByTagName("input") DIM __p2uT = __p2u.Item(0), __p2uF = __p2u.Item(1), __i, __res, __fuki = FALSE TRY COM_ERR_IGN WHILE !COM_ERR_FLG IFB LENGTH(__p2uT.value) THEN __res = "" TRY __p2u = GetEvalStrings(__p2uT.value) FOR __i = 0 TO LENGTH(__p2u) - 1 IF LENGTH(__res) THEN __res = __res + "<#CR>" __res = __res + EVAL(__p2u[__i]) NEXT EXCEPT __res = TRY_ERRMSG ENDTRY IF LENGTH(__res) = 0 THEN __res = " " __p2uF.value = __res __p2uT.value = "" ELSEIF G_MOUSE_X = 0 THEN IFB !__fuki THEN FUKIDASI("p2u is running.") __fuki = TRUE ENDIF ELSE IFB __fuki THEN FUKIDASI() __fuki = FALSE ENDIF SLEEP(0.1) ENDIF WEND COM_ERR_RET EXCEPT // nop ENDTRY // 終了処理 TRY __p2uIe.Quit() EXCEPT // nop ENDTRY FEND FUNCTION GetEvalStrings(code) RESULT = SPLIT(code, "<#CR>") DIM i, line, m = LENGTH(RESULT), ms, j FOR i = 0 TO m - 1 // 行結合を考慮する IFB COPY(RESULT[i], LENGTH(RESULT[i])) = "_" AND i + 1 < m THEN RESULT[i] = COPY(RESULT[i], 1, LENGTH(RESULT[i]) - 1) + RESULT[i + 1] RESULT[i + 1] = "" ENDIF // マルチステートメントを考慮する line = TRIM(RESULT[i]) j = 0 ms = SAFEARRAY(0, 0) WHILE LENGTH(line) ms[j] = TOKEN(";", line, TRUE, TRUE) j = j + 1 RESIZE(ms, j) WEND IFB j > 1 THEN RESIZE(ms, j - 1) InsertArray(RESULT, i, ms) ENDIF line = TRIM(RESULT[i]) // OPTION指定は捨てる IF RegExp(line, "^OPTION\s+[a-zA-Z]+", TRUE) THEN RESULT[i] = "" // DIMで始まる行は、DIM捨ててカンマ区切りで=を:=に変更して IF RegExp(line, "^DIM\s+\S+", TRUE) THEN ReconstDim(RESULT, i) NEXT FEND FUNCTION RegExp(s, p, t=FALSE, g=FALSE, i=TRUE, m=FALSE) __regexp.Pattern = p __regexp.Global = g __regexp.IgnoreCase = i __regexp.Multiline = m IFB t THEN RESULT = __regexp.Test(s) ELSE RESULT = __regexp.Execute(s) ENDIF FEND FUNCTION RepExp(s, p, t=EMPTY, g=FALSE, i=TRUE, m=FALSE) __regexp.Pattern = p __regexp.Global = g __regexp.IgnoreCase = i __regexp.Multiline = m RESULT = __regexp.Replace(s, t) FEND PROCEDURE ReconstDim(var codes, index) DIM line = TRIM(codes[index]) IF !RegExp(line, "^DIM\s+\S+", TRUE) THEN EXIT line = TRIM(COPY(line, 4)) DIM ms = SAFEARRAY(0, 0), i = 0, off WHILE LENGTH(line) ms[i] = TOKEN(",", line, TRUE, TRUE) IFB RegExp(ms[i], "=", TRUE) THEN ms[i] = RepExp(ms[i], "=", ":=") i = i + 1 RESIZE(ms, i) ELSE off = RegExp(ms[i], "\[[^\]]+\]", FALSE, TRUE) ms[i] = RepExp(ms[i], "\[.*") IFB off.Count > 0 THEN ms[i] = ms[i] + ":=SAFEARRAY(0, " + COPY(off.Item(0).Value, 2, LENGTH(off.Item(0).Value) - 2) IFB off.Count = 1 THEN ms[i] = ms[i] + ")" ELSE ms[i] = ms[i] + ", 0, " + COPY(off.Item(1).Value, 2, LENGTH(off.Item(1).Value) - 2) + ")" ENDIF ELSE ms[i] = "" ENDIF ENDIF WEND InsertArray(codes, index, ms) FEND PROCEDURE InsertArray(var src, idx, ins) // srcのidx番目にinsを入れる。idx番目は上書きする DIM im = LENGTH(ins) - 1, i IF im < 0 THEN EXIT IFB im >= 0 THEN DIM sm = LENGTH(src) RESIZE(src, sm + im - 1) FOR i = sm - 1 TO idx + 1 STEP -1 src[i + im] = src[i] NEXT ENDIF FOR i = 0 TO im src[i + idx] = ins[i] NEXT FEND ENDMODULE
で、Powershell側はこんな感じ。
$p2u = New-Object PSObject $p2u | Add-Member NoteProperty "ie" (New-Object -ComObject InternetExplorer.Application) $p2u.ie.Navigate("about:blank") $p2u.ie.Document.title = "Powershell uwsc bridge" #$p2u.ie.Visible = $true $p2u | Add-Member NoteProperty "to" $p2u.ie.Document.createElement("input") $p2u.to.type = "hidden" $p2u.to.name = "_powershell2uwsc" [VOID]$p2u.ie.Document.body.appendChild($p2u.to) $p2u | Add-Member NoteProperty "from" $p2u.ie.Document.createElement("input") $p2u.from.type = "hidden" $p2u.from.name = "_uwsc2powershell" [VOID]$p2u.ie.Document.body.appendChild($p2u.from) $p2u | Add-Member ScriptMethod "Run" { $this.from.value = "" if($args.length -gt 0) { $this.to.value = $args[0] $count = 6000 if($args.length -gt 1) { $count = $args[1] } if($count -gt 0) { while(($this.from.value.length -eq $null) -and ($count -gt 0)) { Start-Sleep -Milliseconds 100 $count-- } if($this.from.value.length -gt 0) { "Run: " + $this.from.value $this.from.value = "" } else { "Run timeout!" } } } } .\p2u.uws
使い方
PowershellからRunメソッドにUWSCにEVALさせる文字列を渡すだけ。
上の例なら
$p2u.Run("MSGBOX(""aaa"")")
といったところ。
UWSC側で改行SPLITしてるので、複数行も可能。
$p2u.Run(@" a := "aaa" MSGBOX(a) "@)
x64のPowershell&IEでもOKだとは知らなかった、、、。
UWSC側のスクリプトを読むと判りますが、DIM文を解釈しようとしてたりします(不完全)
拡張していけば、掲示板のスクリプトをPowershellにペーストして実行、なんてこともできそうですね。
終了する場合は、PowershellのIEオブジェクトを閉じる想定。
$p2u.ie.Quit()