読者です 読者をやめる 読者になる 読者になる

プログラマとプロマネのあいだ

プログラマもやるし、プロマネもやるし、たまに似非アーキとか営業っぽいこともやる

JScriptの配列とVBScriptの配列(SafeArray)を相互変換する方法(1次元編)

メモ魔 @ ウィキ - SAFEARRAY構造体によると、VBScriptの配列とSafeArrayは別っぽいんですが、以下では同じものとして扱います。
用途としては主に、JScriptからCOM(例えばExcelの関数とか)を呼びだそうとしたときに、引数としてSafeArrayを要求されるときに、JScriptの配列をSafeArrayに変換した上で、引数に設定するという使い方です。


具体的には、
Workbooks.OpenText メソッド (Microsoft.Office.Interop.Excel)
の、FieldInfoパラメータには、2次元のSafeArrayを渡す必要があり、調査しました。
この記事ではまず、JScriptの配列から、1次元のSafeArrayを作り出す方法を紹介します。

JScriptVBScript両方使う方法

<?xml version="1.0" encoding="Shift_JIS" ?>
<package>
  <job>
    <script language="VBScript"><![CDATA[
      ' 1次元のJScript配列を、1次元のSafeArrayに変換する関数
      Function convertToSafeArray(jsArray)
        Dim length, result(), elem, i
        length = jsArray.length
        ReDim result(length-1)

        For i=1 to length
          elem = jsArray.shift()
          result(i-1) = elem
        Next

        convertToSafeArray = result
      End Function
    ]]></script>
    <script language="JScript"><![CDATA[
      // 1次元のJScript配列
      var arr = [1,3,6];

      // SafeArrayに変換
      var safeArray = convertToSafeArray(arr);
      printVBArray(new VBArray(safeArray));

      // デバッグ用:VBArrayを表示
      function printVBArray(vbArray) {
        for(var i=0; i<=vbArray.ubound(1); i++) {
          WScript.Echo("vbArray[" + i + "] = " + vbArray.getItem(i));
        }
      }
    ]]></script>
  </job>
</package>

VBScriptの関数(convertToSafeArray)にJScriptの配列を渡すと、"JScriptTypeInfo"という型になるんですが、JScriptで定義されているlengthプロパティやshiftメソッドがそのまま使えるので、それらを駆使してVBScriptの配列に変換し、関数の戻り値として返します。
一方、VBScriptの配列を戻り値として受け取ったJScript側では、VBArrayというラッパオブジェクトが用意されているので、これを利用して読み込みを行います。

JScriptのみ使う方法

<?xml version="1.0" encoding="Shift_JIS" ?>
<package>
  <job>
    <script language="JScript"><![CDATA[
      // 1次元のJScript配列を、1次元のSafeArrayに変換する関数
      // http://www.imasy.or.jp/~hir/hir/tech/js_tips.html#safearray
      function JSArray2SafeArray(ar) {
        var dic = new ActiveXObject("Scripting.Dictionary");
        for (var i = 0; i < ar.length; i++){
          dic.add(i, ar[i]);
        }
        return dic.items();
      }

      // 1次元のJScript配列
      var arr = [1,3,6];

      // SafeArrayに変換
      var safeArray = JSArray2SafeArray(arr);
      printVBArray(new VBArray(safeArray));

      // デバッグ用:VBArrayを表示
      function printVBArray(vbArray) {
        for(var i=0; i<=vbArray.ubound(1); i++) {
          WScript.Echo("vbArray[" + i + "] = " + vbArray.getItem(i));
        }
      }
    ]]></script>
  </job>
</package>

これは、fooling around with JScriptというサイトに載っていた方法です。"Scripting.Dictionary"オブジェクトを介してVBScriptの配列を作り出しています。