2011年10月12日水曜日

64ビット版OfficeでURLエンコード処理ができない?に対する返信2

前回は、既存手法をまとめてみました。
今回は、地味にそのひとつを改変してみます。

対象は、こちら。

64ビット版OfficeでURLエンコード処理ができない? - Microsoft Officeのリボンのカスタマイズ情報が満載 - 初心者備忘録

きぬあささん、ネタに乗っかりました。ありがとうございます。

こちらの手法は、記事内にも書かれている通り「VBScript ファイルを作成し、32ビット版の cscript.exe でそのスクリプトを実行」するというものです。
これを URL エンコード処理だけに特化して考えると、次のような感想が出てきます。

  1. encodeURIComponent メソッドは JScript のメソッドだから、素直に考えると VBScript ファイルじゃなく JScript ファイルでいいんじゃないか。
  2. JScript なら、ScriptControl を経由しなくてよい。ScriptControl を使わないなら、64 ビット版の cscript.exe を直接 (既定のまま) 呼んでもいいんじゃないか。
  3. cscript.exe を呼ぶと一瞬 DOS 窓が開くのがイマイチなので、WScript.exe でいいんじゃないか。

もちろん元記事は、32 ビット版の ScriptControl を 64 ビット環境からどう呼び出すか、という観点から書かれていると思うので、VBScript から ScriptControl を介して JScript コード実行という流れ自体に意味があるわけです。URL エンコード処理はその一例に過ぎません。このエントリでは URL エンコード処理目的に前提が変わっていますので、あくまで別観点から見た場合の話をしています。元記事の手法が良いとかダメとか、そういう次元の話ではないので、そこはご了承ください。

さて、まとめると、こういう感じです。

JScript ファイルを作成し、64ビット版の WScript.exe でそのスクリプトを実行

いたってふつうですね…。
なんか当たり前すぎて、わざわざエントリ起こす意味があるのか分からなくなってきましたが、乗りかかった船なので、書きます。泣きながら。

Option Explicit

Public Sub Sample()
  MsgBox EncodeURLx64("東京都千代田区")
End Sub

Public Function EncodeURLx64(ByRef str As String) As String
    Const ForWriting = 2&
    Dim jsCode As String, script As String, commnd As String

    jsCode = "WScript.StdOut.Write(encodeURIComponent(WScript.Arguments.Item(0)));"
    script = VBA.Environ$("TEMP") & "\enc.js"
    commnd = "WScript.exe """ & script & """ """ & str & """"

    Call CreateObject("Scripting.FileSystemObject").OpenTextFile(script, ForWriting, True).Write(jsCode)
    EncodeURLx64 = CreateObject("WScript.Shell").Exec(commnd).StdOut.ReadAll
    Kill script
End Function

なんか見にくいですね…。
さて、問題は検証です。
自分の環境は Win7 x64 なのですが、Office は 2003 なので WOW64 上での動作となります。これでは 32bit アプリなので、検証できません。
仕方が無いので、VBA 用のコードを VBS 用に書き直しました。

MsgBox EncodeURLx64("東京都千代田区")

Function EncodeURLx64(str)
    Const ForWriting = 2, TemporaryFolder = 2
    Dim fso, jsCode, script, commnd

    Set fso = CreateObject("Scripting.FileSystemObject")
    jsCode = "WScript.StdOut.Write(encodeURIComponent(WScript.Arguments.Item(0)));"
    script = fso.GetSpecialFolder(TemporaryFolder).Path & "\enc.js"
    commnd = "WScript.exe """ & script & """ """ & str & """"

    Call fso.OpenTextFile(script, ForWriting, True).Write(jsCode)
    EncodeURLx64 = CreateObject("WScript.Shell").Exec(commnd).StdOut.ReadAll
    fso.DeleteFile script
End Function

VBS はふつうに叩くと 64bit の WScript.exe で実行されるはずなので、64bit の Office VBA と同じ条件のはず。
…なんか JS を吐く VBS っていうのも、ふつうに考えると意味がよく分かりませんが、検証目的だから仕方が無いよね?

はい、実行結果。


できてるみたいです。

なお、コードはあくまで実験用です。エラーハンドリングや、引用符のエスケープなど、プロダクトなら当然必要な処理を割愛しておりますので、ご注意ください。

というわけで、今回は既存手法のアレンジをお送りしました。
次回は、スクリプト経由という手法から当然予想される方向へ、さらに一歩進んでみたいと思います。

2 件のコメント:

  1. ふむふむ(●゚ェ゚)

    返信削除
  2. 文字数制限(※1)を許容できれば、一時ファイルを使わず下記でも OK(ただし、やはり遅い)。

    Dim cmd As String
    cmd = "mshta ""javascript:new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write(encodeURIComponent('エンコードしたい文字列'));close();"""
    Debug.Print "["; CreateObject("WScript.Shell").exec(cmd).StdOut.ReadAll; "]"

    ※1 http://scripting.cocolog-nifty.com/blog/2006/09/mshtaexeurl_40fe.html

    返信削除