April 2, 2014

Excel VBAからVBScript(WSH)へ変換するときに注意すること

似ているので簡単…?

VBAとVBScriptは文法が似ているので、VBAに慣れている人ならば、簡単にVBScriptが書ける、という記事をよく見かけます。ところが、自分でVBAを初めてVBScriptに移し替えると意外とつまづくポイントが沢山あったので、メモします。
なお、以下ではExcel VBAからVBScriptの場合について書いていますので、Word VBA、PowerPoint VBA等を使われている場合は、適宜読み替えてください。
found, known and done / VBと類似したプログラミング環境についてhttp://foundknownanddone.blogspot.jp/2014/04/vb.html 

まず、何をするのか。

色々なサイトでよく以下のように書いてあります。
  • 新規テキストファイルを作成します。
  • VBAのコードをコピーして、そのファイルにペーストします。
  • 拡張子を.vbsにして保存します。
  • .vbsファイルをダブルクリックして実行します。
    (必要に応じて、vbsをWindows Scripting Hostに関連付けます。)
この手順は確かに正しいのです。しかし、これだけではダブルクリックでスクリプトがスムースに動くことはなく、大抵の場合はエラーが出ます。
では、どうするのか、をこの記事で解説します。


仕様の違いへの対応

VBAとVBScriptでは相互に仕様が違います。そのため、VBAの世界では当然だと思って書いていたコードをVBScriptの世界にもってくると突然エラーを吐くようになります。例えば、VBAの世界で真面目に型宣言してAs節を書いていると「ステートメントの末尾が不正です。」と言われてしまいます。

 仕様の違いの例を示します。
  • ファイルの入出力機能
    VBScriptそのものには含まれていません。必要に応じて FileSystemObjectとかExcel.Application Objectを操作してファイルを開きます。
  • 型宣言
    VBScriptでは型を伴って変数を宣言することが出来ません。そのため、As節やIs演算子が使えません。
    実際には型は動的に決定されます。簡単にいうと、代入するときに代入するものに合わせて変数の型が自動的に決まるということ。
  • エラー処理
    On ~ Go Toがサポートされないので、エラー処理はOn Error Go Toとはできません。
Microsoft / VBA の機能で VBScript に含まれていない機能
http://msdn.microsoft.com/ja-jp/library/cc392401.aspx#feedback

VBScriptでのNGコードと対応するOKコードを以下に示します。

'NG
Dim data As String

Function convertData(ByRef complexData As Variant) As String
    convertData = "Simple is best, sometimes."
End Function

'OK
Dim data 

Function convertData(complexData)
    convertData = "Simple is best, sometimes."
End Function

そこで、仕様の違いに合わせて、上のサンプルのようにコードを修正します。
それでもエラーが残る場合は次のポイントに注目します。

 VBAでは省略できた記載がVBScriptでは必要

例えば、Excel VBAではRangeと書いたときに、実際にはApplicationオブジェクトが省略されています。VBScriptの世界では、Applicationオブジェクトを省略できないので、明示的に親オブジェクトを指定します。そうしないと、「実行時エラー:型が一致しません」といわれてしまいます。

コードの例を示します。
'NG
Range("A1").Value = "Hello world!!"

'OK
Dim xl
Set xl = CreateObject(,"Excel.Application") 'エクセルを起動
xl.Range("A1").Value = "Hello world!!"
Range以外にも、同じようにApplicationオブジェクトを省略できてしまうメソッドやプロパティの場合、Applicationオブジェクトを指定したコードに書き換える必要があります。

例を以下に示します。
  • セル範囲関係(Range, Cells, Columns, Rows)
  • 選択範囲(Selection)
  • シート、ブック関係(Sheets,Worksheets, Workbooks )
  • アクティブな対象(ActiveCell, ActiveSheet, ActiveWindow )
  • ワークシート関数(WorksheetFunction)
  • マクロの制御に使われるメソッド(Wait, Run, SendKeys)
Microsoft / Excel Application オブジェクト
http://msdn.microsoft.com/ja-jp/library/aa288621(v=vs.71).aspx 

これでコードは動くようになったと思います。
でも、これまでに色々とVBScriptのWebページを検索された方は次のようなことを思っているのでは…。

既に起動中のアプリケーションを操作したいんだ!

VBScriptのサンプルコードでは、上記のようにCreateObjectで新しくアプリケーションを起動するものが多いですが、VBAからの移行では起動中のアプリケーションを操作したいのではないでしょうか。この場合はGetObjectを使います。
一方、新しくアプリケーションを起動したい場合は既に書いていますが、CreateObjectを使います。なお、デフォルトでは起動したアプリケーションのウィンドウが表示されませんので、Visible=Trueとして表示してやります。

コードの例を示します。
'既に起動したExcelの選択範囲に値を書き込む
Dim xl
Set xl = GetObject(,"Excel.Application")
xl.Selection.Value="I know you selected these cells!"


'新しくExcelを立ち上げてシートを作って値を書き込む
Dim xl

Set xl = CreateObject("Excel.Application")
xl.Workbooks.Add
xl.ActiveSheet.Range("A1").Value="New workbook created by VBScript."
xl.Visible = True '立ち上げたExcelを表示する

近いようで遠い世界

以上でVBAをVBScriptに移植できたのではないでしょうか。
ファイルの入出力のコードがある場合など、なかなか面倒になると思いますが、少しでも有用なツールが増えてほしいので、へこたれずにがんばりましょう。
似ているようで違う、VBAとVBScriptの世界の橋渡しをする、ちょっとした解説でした。

更新履歴

2014/4/2 初版

No comments :

Post a Comment