UWSCのpowershell関数をスピードアップする
以前、powershellからUWSCを制御する方法を書いた。
PowershellとUWSCの連携 - じゅんじゅんのきまぐれ
しかし、そうじゃないだろ、という気がしたので、再度考えた。
問題は、powershell関数のイニシャルコストが高いこと。
powershell関数を起動させっぱなしにすればいいじゃない!
スクリプト
psh.uws
OPTION EXPLICIT IFB GET_UWSC_NAME = "psh.uws" THEN STOPFORM(FALSE) psh.Create() DIM code = "" WHILE code <> EMPTY PRINT psh.Run(code) code = INPUT("?") WEND psh.Dispose() STOPFORM(TRUE) ENDIF MODULE psh DIM _ie, _from, _to TEXTBLOCK _psh_code $u2p = New-Object PSObject $u2p | Add-Member NoteProperty "ie" (New-Object -ComObject InternetExplorer.Application) $u2p.ie.Navigate("about:blank") #$u2p.ie.Visible = $true $u2p | Add-Member NoteProperty "to" $u2p.ie.Document.createElement("input") $u2p.to.type = "hidden" $u2p.to.name = "p2u" [VOID]$u2p.ie.Document.body.appendChild($u2p.to) $u2p | Add-Member NoteProperty "from" $u2p.ie.Document.createElement("input") $u2p.from.type = "hidden" $u2p.from.name = "u2p" [VOID]$u2p.ie.Document.body.appendChild($u2p.from) $u2p.ie.Document.title = "Powershell uwsc bridge" try { while($true) { if(($u2p.from.value.length -gt 0) -and ($u2p.to.value.length -lt 1)) { try { $u2p.to.value = iex $u2p.from.value } catch { $u2p.to.value = "Invoke error. " + $u2p.from.value + "`n" + ($Error[0] | Out-String) } $u2p.from.value = "" } else { Start-Sleep -Milliseconds 100 } } } catch { Write-Host "Exit." } ENDTEXTBLOCK PROCEDURE Create(disp=FALSE) DIM code = _psh_code IF disp THEN code = REPLACE(_psh_code, "#", "") POWERSHELL(code, TRUE, disp) _ie = 0 WHILE _ie = 0 COM_ERR_IGN _ie = GETACTIVEOLEOBJ("InternetExplorer.Application", "Powershell uwsc bridge") IF COM_ERR_FLG THEN _ie = 0 COM_ERR_RET WEND IFB GetOleItem(_ie.document.body.children) > 1 THEN _from = ALL_OLE_ITEM[0] _to = ALL_OLE_ITEM[1] _from.value = "" _to.value = "" ENDIF FEND PROCEDURE Dispose() _to.value = "exit" SLEEP(0.5) _ie.Quit() FEND FUNCTION Run(code) RESULT = EMPTY IFB LENGTH(_from.value) THEN PRINT "Unknown message. " + _from.value _from.value = "" ENDIF IF LENGTH(code) = 0 THEN EXIT WHILE LENGTH(_to.value); SLEEP(0.1); WEND _to.value = code WHILE LENGTH(_to.value); SLEEP(0.1); WEND RESULT = _from.value _from.value = "" FEND ENDMODULE
使い方
単体の場合は、実行するとInputボックスが出ます。
powershellスクリプトを入力すると、結果がPRINTされます。
IE経由で、文字列を受け渡しています。
Inputボックスにキャンセルすると、終了します。
「dir」とか入れてオブジェクトが文字列変換されて見難い場合、「dir | out-string」とかが良いです。
実際には、モジュールとしてCALLして使うかと思います。
Scriptの最初でpsh.Createして、最後にpsh.Disposeする。
で、powershell関数を呼んでいたところを、psh.Runにすれば多分OK。
解説
、、、するほどのことは、ないですね。
uwsc <-> ie <-> powershellとなっています。
psh.Createで、powershellを呼び出しieを作る。
psh.Disposeで、powershellを終了させieを閉じる。
psh.Disposeしないで終了してしまうと、ゾンビが残るので要注意。
ゾンビがいると、以降の動作が正常に行くか不明です。
(GetActiveOleObjでゾンビを取得してしまうと、連携できなくなる)
ieのタイトルに時間情報とかを付加するとか、UWSCで取得後タイトルを変えるとかすれば、問題ないかもしれないけど、ま、ゾンビが残ることに変わりはないので放置。
STOPFORMされてしまうと、ゾンビが残るので、STOPFORMは消してます。
雑感
インターネットの片隅で、UWSCで遊ぶ。
「uwsc getlasterror」でGoogle先生に聞くと、上位を制圧しているのが嬉しい。
、、、とはいえ、できないのにDEF_DLLしているモジュールは恥ずかしいかもしれない。
気が向いたら修正しよう。
しかし、2chのUWSCスレッドにURLが貼られているとは、、、意外と見てる人いるのね。
ま、Win32APIをUWSCから呼ぼうとする変態が少ないということか。
UWSCにできないことはない。
妥協が必要なことはあるかもしれないけど。
できないのは、、、己の技術不足。
それを何とかするのが楽しい、というところ。
今回は、powershell連携を改善してみました。
え?文字列になってしまうのをなんとかできないか?
ScriptControlを使うとかすれば、JScriptのオブジェクトが扱えると思うけど、面倒。
ま、それくらいはやりたい人ががんばってみてよ。(私の興味の範疇外)
問題は、powershellはJScriptオブジェクトを上手く扱えないこと。