サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

PHP を使って VBScript コードを作る(な、何を言っているのか...

背景

先ごろ VBS を使って2000行を超えるスクリプトを二つ作りました。しかしこの二つのスクリプトソースコードのうち 2/3 は同じです。

Visual Studio 2015 でデバッグとプロジェクト管理をしています。便利です。後ほどリンクをご紹介します。

開発環境には別の仕事の関係で PHP もインストールしてあります。

ソースコードの分割

VBS には include という概念がないため、一つのファイルに全ての処理を書かなければいけません。手軽に実行がモットースクリプトですから、これは制限というよりむしろ美徳です。しかし開発時はファイルが別々になっててくれた方がうれしい場合があるのも事実。二重管理しなくてすむし、再利用もしやすくなるしね。

include には下記の別の方法もあるにはありますが、やっぱり最終的な実行ファイルは一つにしたいです。

vbScriptでinclude文を使う - tekkの日記 C#,VB.NET

ユーザーに配るとき「これをダブルクリックしてね」と言うだけで済みますからね。せっかく Visual Studio を使っているので、「ビルド」として複数のスクリプトファイルを一つにまとめる処理を作ってみましょう。

手順1:プロジェクトの作成

メモ: Visual Studio を使って VBScript の開発を行う - 高東ソフトウェアサービス

まずはこれでプロジェクトを作ります。私の場合は 2008 と 2015 で同じことをしました。VBS 開発もこれで IDE の恩恵を受けることができます。

手順2:メインファイルの作成

手順1のリンク先にある手順の通りにプロジェクトを作ったものとして、プロジェクトのルートに VBSTest.vbs があるものと想定します。中身は空でかまいません。これをビルドのたびに書き換えるイメージです。

次に VBSTest.php を作成します。タイプミスではありません。PHP です。 何を言っているのかわからねーと思 いますが、つまり PHP を VBS のプリプロセッサとして使用するのです。

PHP で VBS のプリプロセッサ

PHPプログラマーが知らないPHPの用法 | 株式会社きじねこ

PHP は Hypertext Preprocesser の略です。HTML のプリプロセッサという出自を持ちます。しかし PHP さんにとって PHP の外側の世界が本当に HTML なのかどうかは知ったこっちゃありません。つまり VBS でもなんでもいいのです。

VBSTest.php の中身は以下の通りです。

<?php
require_once 'classes/ApplicationEntry.vbs';
// require_once 'tests/HelloWorldTest.vbs';
require_once 'classes/HelloWorld.vbs';

見ての通り、ファイル内容を結合しているだけです。コメントアウト部分は後ほど説明します。

手順3:サブフォルダの作成

次に include する対象のクラスファイルを格納する「classes」フォルダを作成します。

そしてこれに対応するフォルダ「みたいなもの」をプロジェクトに作ります。ソリューションエクスプローラー上で右クリックして「追加>フィルター」を選択します。Visual Studio 上でフォルダ「みたいに」使えるのでこれでいいです。

手順4:クラスファイルの作成

次にこの「classes」フォルダの中に二つのクラスファイルを作ります。

以下のファイルは「集中例外ハンドラ」です。深い階層から Err.Raise したいときに便利で必ず作るので、この記事には関係ありませんが、備忘録としてここに書かせていただきます。

try~catchを実装するには - 城陽人の本棚

classes/ApplicationEntry.vbs です。

Option Explicit

Dim app
Set app = New ApplicationEntry

app.Start
WScript.Quit(0)

Class ApplicationEntry
    Sub Start()
        On Error Resume Next
        Call Me_Main() ' この後に何も行を書かないことで上の On Error Resume Next を集中例外ハンドラにできる。
    End Sub

    Private Sub Me_Main()
        On Error Goto 0 ' この行は Me_Main() 内部でのみ有効。

        Dim h
        Set h = New HelloWorld
        h.Greeting "Hello"
    End Sub

    Private Sub Class_Terminate()
        If Err.Number <> 0 Then
            WScript.Echo Err.Number & ":" & Err.Description & "@" & Err.Source
            WScript.Quit(Err.Number)
        End If
    End Sub
End Class

PHP はファイル末尾の改行を無視するので、最後は二つの改行で終らせるのがいいかもしれません。

次に HelloWorld クラスを記述します。classes/HelloWorld.vbs です。

Class HelloWorld
    Public Sub Greeting(ByVal msg)
        WScript.Echo msg & "World!"
    End Sub
End Class

手順5:ビルドバッチの作成

プロジェクトのプロパティで「構成プロパティ>ビルドイベント」を選択します。

コマンドライン」の欄に「Build.bat」を設定します。

次にその Build.bat をプロジェクトフォルダ直下に作成します。中身は以下の通りです。

@echo off
php -c C:\php\php-cli.ini VBSTest.php >VBSTest.vbs
type VBSTest.vbs
echo 0

type しているのは PHP の部分でエラーが発生した場合に、それをビルドエラーとして Visual Studio で検知できるようにするためです。後ほど実際にやってみます。

手順6:作成したファイルをプロジェクトに追加

作成したファイルを全て Visual Studio からプロジェクトに追加します。ソリューションエクスプローラー上で右クリックし「追加>既存の項目」を選択してスクリプトを追加します。

「classes/ApplicationEntry.vbs」「classes/HelloWorld.vbs」はもちろんフィルタ「classes」の下に、VBSTest.php と Build.bat はプロジェクト直下に追加します。

ビルド

これでプロジェクトの「ビルド」をすると VBSTest.vbs の中身が PHP によって作られるようになります。

手順7:デバッグ

その後は「デバッグなしで実行」するとデバッグもできます。何を言っているのかわからねーと思いますが、いや 先ほど紹介したリンク にもちゃんとそう書かれています。VBS をデバッグするためにはなぜか「デバッグなし」の方を選ばなければなりません。Visual Studioツールバーをカスタマイズして、こちらも直ぐにクリックできるようにしておきます。

さて、PHP ファイルのコメントアウト部分を以下のように変更してリビルドしてみてください。

<?php
// require_once 'classes/ApplicationEntry.vbs';
require_once 'tests/HelloWorldTest.vbs';
require_once 'classes/HelloWorld.vbs';

「tests/HelloWorldTest.vbs」というファイルはまだ作っていないですからエラーが出てほしいです。Visual Studio の「エラー一覧」ペインを見ると、ちゃんとエラーが表示されていることが確認できると思います。PHP の出力するエラーを「ビルドエラー」のように見ることができます。

「tests/HelloWorldTest.vbs」を実際に実装すれば、クラスの単体テストを行うことができます。あるいは ApplicationEntry.vbs の中で WScript.Quit(0) しているので classes/HelloWorld.vbs の中に直接テストコードを埋め込んでしまってもいいでしょう(実行されないため)。個々のクラスファイルを指定すると単体テスト、ビルドして結合テスト、などができるようになります。

これでソースコードの管理や再利用が簡単になるだけでなく、 プリプロセッサの恩恵 にあずかることもできます。

集中例外ハンドラのファイル(classes/ApplicationEntry.vbs)にハードコーディングしている「HelloWorld」を PHP の変数にしてしまえば(例えば「<?=$className ?>」のように)再利用できます。

開発時にはトレースを出して、本番リリースのスクリプトでは__それをフラグ一つで無効化するのではなく__処理自体を削除するというようなこともできるようになります(単体テストしづらくなりますが)。

聞いただけでゲンナリする VBS の開発も、これでだいぶ楽になると思います。

参考文献