Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2010年06月08日] [更新 2017年10月20日] Delphi サンプルプログラム集
950_Delphi で VBScript を操作
動作確認等 Windows XP(SP3) + Delphi 2010(UP5) Pro + vbscript.dll 5.7.0.16535
Windows 7 U64 + Delphi 2010(UP5) Pro + vbscript.dll 5.8.7600.16546
950_VBScript.zip [3,662 KB] 2017年10月20日版 (EXE 同梱)



  • 2011年04月15日
  • サンプル [03] に数式処理関係のリンクを追加




Delphi で VBScript を操作 - タイプライブラリの取り込み


VBScript (Microsoft Visual Basic Scripting Edition:VBS) は,マイクロソフトが提供しているスクリプト言語です.VB (Visual Basic) のサブセット版の言語仕様となっています.
言語仕様の詳細については,マイクロソフトの VBScript ユーザーズ ガイドで確認してださい.

ネット上にはマイクロソフトのスクリプトセンターをはじめ、VBScript で書かれたサンプルコードが多くあります.これらのコードを Delphi で利用したり自分で VBScritp のコードを作成する場合の参考となるかも知れないサンプルです.[VBScript 関数リファレンス] というサイトが見やすい様です (記事の掲載日等は,多くのサイトの記事がそうであるように不明です).

このページのサンプルでは,[タイプライブラリの取り込み] で作成した MSScriptControl_TLB.pas を使用しています.タイプライブラリの取り込みでは,コンポーネントラッパーを作成して,コンポーネントとして登録します.

サンプルプログラム集のサンプルを書くときはいつも,サンプルの内容に迷うのですが,このページのサンプルもあまりいい例でないかも知れません.このページのサンプルは Fusa さんのサイトの記事を参考にしています.



[備考]
VBScript と後述の JScript は,WSH (Windows Script Host) という Windows のスクリプト実行環境で使用可能なスクリプト言語です.WSH 自身にはシェルの機能は実装されていません.
Windows 7 で標準実装された PowerShell というスクリプト実行環境は,独自のスクリプト言語を実装し,コマンドプロンプトの強化版としてのシェルの機能を実装しています.

  • 図1
  • [タイプライブラリの取り込み] で MSScriptControl_TLB.pas ファイルを作成




01_VBScript の簡単な例


VBScript のコードはテキストファイルです.コードを書いたテキストファイルを,拡張子 vbsで 保存すると,それが VBScript のファイルとなります.これをダブルクリック等で実行します.
下図は添付のサンプルの簡単な実行例です.


図2
添付の VBS ファイル
  • ダブルクリックまたは [Enter] で実行
図3
下のコードの実行結果

リスト1
SimpleTest.vbs のコード
msgbox("こんにちは.お元気ですか.") 


次の図は FileProperties1.vbs の実行結果です.コード内の str 変数の内容を表示しています.


図4
下のコードの実行結果
  • str に格納されている値が表示される

リスト2
FileProperties1.vbs のコード
' ファイルのプロパティをダイアログで表示する

Set FS = CreateObject("Scripting.FileSystemObject")
Set F  = FS.GetFile("BW_Delphi.jpg")

str = ""
str = str & "ファイル名: "   & F.Name & vbCrLf
str = str & "最終アクセス: " & F.DateLastAccessed & vbCrLf
str = str & "最終変更: "     & F.DateLastModified & vbCrLf
str = str & "サイズ: "       & F.Size
MsgBox str


次の図は FileProperties2.vbs の実行結果です.コードの 1 行を実行するたびにその内容を表示するようになっているので,[OK] ボタンをクリックすると次の値を表示します.


図5
下のコードの実行結果
  • [OK] をクリックすると次の値を順番に表示

リスト3
FileProperties2.vbs のコード
' ファイルのプロパティを順番にダイアログで表示する

Set FS = CreateObject("Scripting.FileSystemObject")
Set F  = FS.GetFile("BW_Delphi.jpg")

WScript.echo "ファイル名: "   & F.Name
WScript.echo "最終アクセス: " & F.DateLastAccessed & vbCrLf
WScript.echo "最終変更: "     & F.DateLastModified & vbCrLf
WScript.echo "サイズ: "       & F.Size


当然ですが,ダブルクリックで実行するということは,以下のように,ShellExecute 関数等を使用して実行することと同じです.引数付きで実行する VBS のコードは,ShellExecute 関数の 4 番目に引数の値を指定することになります.


procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle,'open','SimpleTest.vbs', nil, nil, SW_HIDE);
end;


上の VBScript 程度のコードであれば,uses に ComObj を追加して,下に示すように,Delphi のコードに移植して実行ということも考えられます.しかし,VBScript 独自の命令を使用していると簡単に移植できない場合もあります.そのような場合,VBScript のコードを Delphi から実行できると便利です.


procedure TForm1.Button1Click(Sender: TObject);
var
  FS   : OleVariant;
  F    : OleVariant;
  AStr : String;
begin
  FS := CreateOleObject('Scripting.FileSystemObject');
  F  := FS.GetFile('BW_Delphi.jpg');

  AStr :=   'ファイル名:  '   + VarToStr(F.Name) + sLineBreak
          + '最終アクセス:  ' + VarToStr(F.DateLastAccessed) + sLineBreak
          + '最終更新:  '     + VarToStr(F.DateLastModified) + sLineBreak
          + 'サイズ:  '       + VarToStr(F.Size);

   ShowMessage(AStr);
end;


[備考]
Delphi の場合は,COM オブジェクトの生成に CreateOleObject を使用します.VB や VBS で使用している CreateObject という関数は,Delphi にはありません.また,VB, VBS の GetObject は Delphi では GetActiveOleObject に相当します.VB, VBS の GetObject はオブジェクトの参照,Windows API の GetObject はオブジェクトの情報取得用の関数です.
Delphi で使用する GetObject 関数は,クラススコープがあれば,そのクラスあるいはコンポーネントのオブジェクトを取得し,単に GetObject とした場合は Windows API の関数を意味し,明確に区別することができます.
VB や VBS の vbCrLf (改行文字) は,Delphi では sLineBreak です.




02_VBScript のコードを Delphi で実行


前の VBScript のコードを Delphi で実行します.もちろん ShellExecuteEx や CreateComObject でVBS ファイルを指定して実行することもできますが,スクリプトの操作が困難になります.ここでは[タイプライブラリの取り込み] で作成した MSScriptControl_TLB を uses して使用します.

Button1Click では,VBS のコードを実行時に作成して,TScriptControl の ExecuteStatement メソッドを実行します.
Button2Click では,VBScript のテキストを読込んでから実行します.Button3Click ではそのコードを 1行 づつ実行する場合です.結果は Button2Click と同じとなります.


図6
設計時画面
図7
Button1 クリック
図8
Button2 クリック

リスト4
Delphi で VBScript のコードを実行
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MSScriptControl_TLB, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  VBScriptのコードをDelphiのコードで作成して実行する例
//  VBScriptのExecuteStatementメソッドを使用する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  VBSpt : TScriptControl;
begin
  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create(Self );
  VBSpt.Language := 'VBScript';

  try

    VBSpt.ExecuteStatement('msgbox("こんにちは.お元気ですか.") ');
  finally
    FreeAndNil(VBSpt);
  end;
end;

//=============================================================================
//  VBScriptのコードをDelphiで読込んで実行する例
//  VBScriptのExecuteStatementメソッドを使用する
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  VBSpt : TScriptControl;
  SL    : TStringList;
begin
  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create(Self);
  VBSpt.Language := 'VBScript';

  //コードを格納するTStringList生成
  SL := TStringList.Create;
  try
    //コードを読込んで実行
    SL.LoadFromFile('FilePropeties1.vbs');
    VBSpt.ExecuteStatement(SL.Text);
  finally
    FreeAndNil(SL);
    FreeAndNil(VBSpt);
  end;
end;

//=============================================================================
//  VBScriptのコードをDelphiで読込んで1行づつ実行する例
//  VBScriptのExecuteStatementメソッドを使用する
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  VBSpt : TScriptControl;
  SL    : TStringList;
  i     : Integer;
begin
  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create(Self);
  VBSpt.Language := 'VBScript';

  //コードを格納するTStringList生成
  SL := TStringList.Create;
  try
    //コードを読込んで1行づつ実行
    SL.LoadFromFile('FilePropeties1.vbs');
    for i := 0 to SL.Count - 1 do begin
      VBSpt.ExecuteStatement(SL[i]);
    end;
  finally
    FreeAndNil(SL);
    FreeAndNil(VBSpt);
  end;
end;

end.




03_Eval メソッドを使用した数式処理


TScriptControl には Eval というメソッドがあります.これは後述のように,VBScript の実行結果を取得する時に使用しますが,式の評価にも使用できます.その例です.文字列で与えた計算式を実行でき,関数電卓に似たようなことができます.

Delphi で数式処理を行うには,以下のリンクも参考になるでしょう.
[Cindy components のインストール手順] で紹介している Cindy components 群にも TcyMathParser というコンポーネントがあります.


以上は,いわゆる数式処理や関数電卓のようなものですが,Microsoft Word (ワード) の数式エディタや pTex (Publishing TeX),LaTeX (ラテフ) のような数式エディタを実装するためのコンポーネントのようなものもネット上で見た記憶があります.


図9
設計時画面
図10
Button1 クリック
  • コード内に書いた数式の計算結果
図11
Button2 クリック
  • Edit1.Text の式を計算して表示

リスト5
Eval メソッドを使用した数式計算
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, MSScriptControl_TLB, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  Edit1にテスト用の数式をセット
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
  Edit1.Text := '(10 + 20) / 5';
end;

//=============================================================================
//  VBScriptのEval関数(文字列で与えられた数式を計算)の簡単な使用例
//  文字列で与えられた計算式の計算結果を表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  VBSpt : TScriptControl;
begin
  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create( Self );
  VBSpt.Language := 'VBScript';

  try
    //計算結果を表示
    Label2.Caption := VarToStr(VBSpt.Eval('sin(90) + log(10)')) ;
  finally
    FreeAndNil(VBSpt);
  end;
end;

//=============================================================================
//  VBScriptのEval関数(文字列で与えられた数式を計算)の簡単な使用例
//  Edit1のTextプロパティの文字列式を計算する
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  VBSpt : TScriptControl;
begin
  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create( Self );
  VBSpt.Language := 'VBScript';

  try
    //計算結果を表示
    Label2.Caption := VarToStr(VBSpt.Eval(Edit1.Text)) ;
  finally
    FreeAndNil(VBSpt);
  end;
end;

end.




04_VBScript の実行結果を取得


上のサンプルでは,VBScript を実行して,その結果も VBScript のダイアログで表示していました.この結果を Delphi 側で表示するために,TScriptControl の Evalメソッドの引数に VBScript 内の変数名を指定して,その値を取得します.
そのために,元の VBScript コードの表示部分を削除しておきます.サンプルではそのコードを TMemo に表示するようにしてみました.


図12
設計時画面
図13
Button1 クリック
  • 最初の 2 行が VBScript のコード

リスト6
VBScript 内の変数の値を取得
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, MSScriptControl_TLB, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Panel1: TPanel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  ファイルからVBScriptのコードを読込んで実行
//  実行するのは表示コード部分のないVBSコード.表示はDelphiで実行
//
//  このコードではTStringListに読込んで実行しているが,Memo1.Textを実行しても
//  同じ.結果の表示を他のコントロールに表示することを考えてTStringListを使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  VBSpt       : TScriptControl;
  SL          : TStringList;
  AFileName   : String;
  AType       : String;
  ModifiyDate : TDateTime;
  AccessDate  : TDateTime;
  ASize       : Int64;
begin
  Memo1.Lines.BeginUpdate;

  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create(Self);
  VBSpt.Language := 'VBScript';

  //コードを格納するTStringList生成
  SL := TStringList.Create;
  try
    //コードを読込んで実行
    SL.LoadFromFile('FilePropeties.txt');
    VBSpt.ExecuteStatement(SL.Text);

    Memo1.Text := SL.Text;
    Memo1.Lines.Add('');
    Memo1.Lines.Add('  ---------- 結果 ----------');
    Memo1.Lines.Add('');

    //実行結果から値を取得
    AFileName   := VarToStr(VBSpt.Eval('F.Name'));
    AType       := VarToStr(VBSpt.Eval('F.Type'));
    AccessDate  := VarToDateTime(VBSpt.Eval('F.DateLastAccessed'));
    ModifiyDate := VarToDateTime(VBSpt.Eval('F.DateLastModified'));
    ASize       := VBSpt.Eval('F.Size');

    //形式を整えて表示
    Memo1.Lines.Add(' ファイル名    : ' + AFileName);
    Memo1.Lines.Add(' 種類          : ' + AType);
    Memo1.Lines.Add(' 最終アクセス  : ' +
                    FormatDateTime('yyyy年mm月dd日 hh時nn分', AccessDate));
    Memo1.Lines.Add(' 最終変更      : ' +
                    FormatDateTime('yyyy年mm月dd日 hh時nn分', ModifiyDate));
    Memo1.Lines.Add(' サイズ        : ' + FormatFloat(',###.##0 KB', ASize/1024));
  finally
    FreeAndNil(SL);
    FreeAndNil(VBSpt);
  end;
  Memo1.Lines.EndUpdate;
end;

end.




05_VBScript のコードに値を渡す


VBScript 内のコードの変数に値をセットするテストです.
まず,引数付きの関数を実行する場合の引数の与え方です.少し面倒ですが,VarArrayCreate 関数で配列を作成して SafeArray で渡します.外部のファイル内に値を設定するため,管理者権限 (管理者として実行) が必要となります.

もう 1 つの方法として,Button2Click では,VBScript のコードを読み込んで,そのコードに変数を設定するコードを追加してから実行しています.VBScript のコードは読み出しだけですから,管理者権限での実行は必要ありません.


図14
設計時画面
  • 任意のファイルを選択可能にするため TOpenDialog を使用
図15
Button1 クリック
  • TScriptControl の Run メソッドで実行
図16
Button2 クリック
  • 変数設定用のコードを追加して実行
  • 上 3 行が追加したコード

リスト7
VBScrip 内の変数に値をセット
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, MSScriptControl_TLB, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Panel1: TPanel;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses ActiveX;

{$R *.dfm}

//=============================================================================
//  文字列を"(ダブルコーテーション)で囲んだ文字列を作成する関数
//=============================================================================
function AddQuotedStr(Str: String): String;
begin
  Result := SysUtils.AnsiQuotedStr(Str, '"');
end;

//=============================================================================
//  VBScript内の関数を実行
//  Runメソッドを使用.関数の引数はVarArrayを使用してセット
//
//  PSafeArrayの使用にはusesにActiveXが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  VBSpt   : TScriptControl;
  SL      : TStringList;
  Params  : PSafeArray;
  V       : Variant;
  AType   : String;
begin
  Memo1.Lines.BeginUpdate;

  if OpenDialog1.InitialDir = '' then begin
    OpenDialog1.InitialDir := ExtractFileDir(Application.ExeName);
  end;
  if OpenDialog1.Execute = False then exit;

  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create(Self);
  VBSpt.Language := 'VBScript';

  //VBScriptの関数に渡す値をセット
  V      := VarArrayCreate([0, 1], varVariant);
  V[0]   := ExtractFilePath(OpenDialog1.FileName);
  V[1]   := ExtractFileName(OpenDialog1.FileName);
  Params := PSafeArray(TVarData(V).VArray);

  //コードを格納するTStringList生成
  SL := TStringList.Create;
  try
    //コードを読込む
    SL.LoadFromFile(ExtractFilePath(Application.ExeName) + 'FilePropeties.txt');

    //スクリプトにコードを追加
    VBSpt.AddCode(SL.Text);
    //VBSのコード内のFileTypeという関数を実行
    //引数はParamsで渡す
    AType := VBSpt.Run('FileType', Params);

    Memo1.Text := SL.Text;
    Memo1.Lines.Add('');
    Memo1.Lines.Add('  ---------- 結果 ----------');
    Memo1.Lines.Add('');

    //結果を表示
    Memo1.Lines.Add(' ファイル名 : ' + ExtractFileName(OpenDialog1.FileName));
    Memo1.Lines.Add(' 種類       : ' + AType);
  finally
    FreeAndNil(SL);
    FreeAndNil(VBSpt);
  end;
  Memo1.Lines.EndUpdate;
end;

//=============================================================================
//  VBScript内の関数を実行
//  コードの先頭に関数を呼出すコードと引数の値をセットするコードを追加して実行
//  VBScript内に複数の関数がある場合は面倒
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  VBSpt   : TScriptControl;
  SL      : TStringList;
begin
  Memo1.Lines.BeginUpdate;

  if OpenDialog1.InitialDir = '' then begin
    OpenDialog1.InitialDir := ExtractFileDir(Application.ExeName);
  end;
  if OpenDialog1.Execute = False then exit;

  //VBScriptオブジェクトを生成
  VBSpt := TScriptControl.Create(Self);
  VBSpt.Language := 'VBScript';

  //コードを格納するTStringList生成
  SL := TStringList.Create;
  try
    //コードを読込む
    SL.LoadFromFile(ExtractFilePath(Application.ExeName) + 'FilePropeties.txt');
    //変数に値をセットするためのコードを追加
    SL.Insert(0, 'APath  = ' + AddQuotedStr(ExtractFilePath(OpenDialog1.FileName)));
    SL.Insert(1, 'AName  = ' + AddQuotedStr(ExtractFileName(OpenDialog1.FileName)));
    SL.Insert(2, 'RetStr = FileType(APath, AName)');
    SL.Insert(3, '');

    //スクリプトを実行
    VBSpt.ExecuteStatement(SL.Text);

    Memo1.Text := SL.Text;
    Memo1.Lines.Add('');
    Memo1.Lines.Add('  ---------- 結果 ----------');
    Memo1.Lines.Add('');

    //実行結果から値を取得
    Memo1.Lines.Add(' ファイル名 : ' + ExtractFileName(OpenDialog1.FileName));
    Memo1.Lines.Add(' 種類       : ' + VarToStr(VBSpt.Eval('RetStr')));
  finally
    FreeAndNil(SL);
    FreeAndNil(VBSpt);
  end;
  Memo1.Lines.EndUpdate;
end;

end.




06_VBScript 実行時のエラー処理


TScriptContorl には OnError イベントがあります.その中で Error プロパティでエラー内容の文字列を取得できます.ここままでのサンプルでは,TScriptControl を実行時に生成していますが,このサンプルでは Form に配置してオブジェクト・インスペクタで OnError イベントを作成しています.


図17
設計時画面
  • TScriptControl コンポを配置してOnError イベントを作成
図18
Button1クリック
  • エラー内容が TMemo に表示される

リスト8
TScriptControl の OnError イベントを使う
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, MSScriptControl_TLB, StdCtrls, ExtCtrls, OleCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Panel1: TPanel;
    Button1: TButton;
    ScriptControl1: TScriptControl;
    procedure Button1Click(Sender: TObject);
    procedure ScriptControl1Error(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  ファイルからVBScriptのコードを読込んで実行
//  実行するのは表示コード部分のないVBSコード.表示はDelphiで実行
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  SL          : TStringList;
  AFileName   : String;
  AType       : String;
  ModifiyDate : TDateTime;
  AccessDate  : TDateTime;
  ASize       : Int64;
begin
  ScriptControl1.Language := 'VBScript';
  Memo1.Lines.BeginUpdate;

  //コードを格納するTStringList生成
  SL := TStringList.Create;
  try
    //コードを読込んで実行
    SL.LoadFromFile('FilePropeties.txt');
    try
      Memo1.Text := SL.Text;
      Memo1.Lines.Add('');
      Memo1.Lines.Add('  ---------- 結果 ----------');
      Memo1.Lines.Add('');

      //スクリプト実行
      ScriptControl1.ExecuteStatement(SL.Text);

      //実行結果から値を取得
      AFileName   := VarToStr(ScriptControl1.Eval('F.Name'));
      AType       := VarToStr(ScriptControl1.Eval('F.Type'));
      AccessDate  := VarToDateTime(ScriptControl1.Eval('F.DateLastAccessed'));
      ModifiyDate := VarToDateTime(ScriptControl1.Eval('F.DateLastModified'));
      ASize       := ScriptControl1.Eval('F.Size');

      //形式を整えて表示
      Memo1.Lines.Add(' ファイル名    : ' + AFileName);
      Memo1.Lines.Add(' 種類          : ' + AType);
      Memo1.Lines.Add(' 最終アクセス  : ' +
                      FormatDateTime('yyyy年mm月dd日 hh時nn分', AccessDate));
      Memo1.Lines.Add(' 最終変更      : ' +
                      FormatDateTime('yyyy年mm月dd日 hh時nn分', ModifiyDate));
      Memo1.Lines.Add(' サイズ        : ' + FormatFloat(',###.##0 KB', ASize/1024));
    except
    end;
  finally
    FreeAndNil(SL);
  end;
  Memo1.Lines.EndUpdate;
end;

//=============================================================================
//  TScriptControlのOnErrorイベント
//  エラーが発生しなければ何も表示しない
//=============================================================================
procedure TForm1.ScriptControl1Error(Sender: TObject);
begin
  Memo1.Lines.Add(ScriptControl1.Error.Description);
  Memo1.Lines.Add(ScriptControl1.Error.Source);
  Memo1.Lines.Add(ScriptControl1.Error.Text);
end;

end.




07_VBScript のヘルプファイル


マイクロソフトの以下の [Windows Script Version] というページからダウンロードできます.そこにある scd56jp.exe です (URL は 2010年08月20日現在).
このヘルプファイルは 2001年と古く,ADVPACK.DLL もかなり古いバージョンですが,scd56jp.exe をインストールしても上書きはされないようです.不安であればヘルプファイルだけを取り出して利用するという手もあります.


図19
scd56jp.exe の内容
図20
VBScript のヘルプ




08_JScript を使用した WSH のサンプルを Delphi で実行


WSH では JScript というスクリプト言語もよく使用されいます.ネット上にあるそのようなサンプルを Delphi で利用する時の参考です.
例えば次のコードはマイクロソフトが提供している音声合成エンジンを使用して,コンピュータが英語で Hello と発声します.このコードを TestVoice.js という名前で保存します.


リスト9
WSH (JScript) のコードの例
var tts = WScript.CreateObject("SAPI.SpVoice");
tts.Rate = 2;
tts.Speak("Hello!");


保存した拡張子が .js の JScript のコードは次のようにして実行できます.
拡張子 .js のファイルは JavaScript のファイルでもあります.そこで,JavaScript のファイルと区別するために明示的に WScript.exe を指定して実行しています.もし拡張子の関連付けが設定されていなければ ShellExecute 関数の第 3 引数を JScript のファイル名にすることができます.

WScript.exe の代わりに CScript.exe でも実行可能です.CScript.exe は,VBScript, JScript どちらのスクリプトも実行できます.



リスト10
保存した JScript (拡張子は .js) のファイルを実行
uses に ShellAPI が必要
//=============================================================================
//  WSH(JScript)のファイルをDelphiで実行する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(Handle,'', 'WScript.exe', 'TestVoice.js', nil, SW_HIDE);
end;


以下は,JScript のコードを Delphi のコードに変換して実行する例です.


リスト11
WSH (JScript) のコードを Delphi のコードに変換して実行
uses に ComObj が必要
//=============================================================================
//  WSH(JScript)のコードをDelphiのコードに変換して実行
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LSavedCW : Word;
  LSpeach  : OleVariant;
begin
  //浮動小数点演算エラー回避
  LSavedCW := Get8087CW;
  Set8087CW(LSavedCW or $4);

  LSpeach := CreateOleObject('SAPI.SpVoice');
  LSpeach.Rate := 2;
  LSpeach.Speak('Hello');

  Set8087CW(LSavedCW);
end;


Windows の SpVoice (SAPI) オブジェクトのの Speak メソッド はデフォルトでは同期実行です.したがって,Speak メソッドが終了するまで Speak メソッドの次のコードは実行されません.
次のコードを使用すると,非同期に近い動作を実現できます.



リスト12
Windows SpVoice (SAPI) の Speak メソッドを非同期で実行
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    FObjSpeach : OleVariant;
    FStopFlag  : Boolean;
    procedure SAPI_Speach(AText: string);
  end;

var
  Form1: TForm1;

implementation

uses
  ComObj;

{$R *.dfm}

const
  SVSFDefault = 0;
  SVSFlagsAsync = 1;
  SVSFPurgeBeforeSpeak = 2;

//=============================================================================
//  SAPI.SpVoice オブジェクトを生成して音声を出力
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText : string;
begin
  if not VarIsEmpty(FObjSpeach) then Exit;

  Button1.Enabled := False;

  LText := '1. 2. 3. 4. 5. 6. 7. 8. 9. 10';
  SAPI_Speach(LText);
  Button1.Enabled := True;
end;

//=============================================================================
//  音声出力を強制終了させるフラグをセット
//  Stop メソッドの代用機能
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  FStopFlag := True;
end;

//-----------------------------------------------------------------------------
//  SAPI.SpVoice オブジェクトを生成して音声を出力
//  見かけ上非同期で動作させる例
//  Stop 等の強制終了の方法がないのでオ終了まで待つ
//-----------------------------------------------------------------------------
procedure TForm1.SAPI_Speach(AText: string);
var
  LSavedCW : Word;
begin
  //浮動小数点演算エラー回避
  LSavedCW := Get8087CW;
  Set8087CW(LSavedCW or $4);

  FStopFlag := False;
  FObjSpeach := CreateOleObject('SAPI.SpVoice');
  FObjSpeach.Rate := 2;
  FObjSpeach.Speak(AText, SVSFlagsAsync);
  repeat
    Sleep(100);
    if FStopFlag then Break;
    Application.ProcessMessages;
  until  FObjSpeach.WaitUntilDone(10);

  FObjSpeach := Unassigned;

  Set8087CW(LSavedCW);
end;

end.


[備考]
本項のサンプルコードで使用している音声合成エンジンは,Windows 7 では日本語の読み上げはできません.Windows 8.1 / 10 であれば日本語も読み上げてくれます.
Windows 7 の場合は,Microsoft Speech Platform という,同じマイクロソフトが提供している音声合成エンジンを使用すると日本語も読み上げてくれます.
音声合成にはこの他にも多くの製品,ユーティリティ等があります.ジャストシステムの一太郎のプレミアム版以上には「詠太」という読み上げソフトが添付されています.




09_スクリプトエンジンのバージョン


VBScript, JScript のバージョンは CScript コマンドを実行すると確認できます.このバージョンの値は WSH のバージョンと同じです.
下図は筆者の環境での値です.


図21
Windows 7
図22
Windows 10