こんにちは!今日も一緒にプログラミングの深遠で楽しい世界を覗いていきましょう。
普段、VBScriptで自動化ツールを書いていると「処理が終わるまで `Do While` でループして監視する」というコードを書きがちではありませんか?
実は、Windows Script Host(WSH)の機能を正しく使うと、「処理が終わったらCOMオブジェクト側から通知を受け取る(イベント受信)」という、洗練された非同期イベント駆動プログラミングを実現できるのです。
今回は、脱初心者を目指すあなたへ、`WScript.CreateObject` の隠された真価である「第2引数(イベントプレフィックス)」を用いた非同期イベント受信の仕組みと実装法を、基礎からわかりやすく解説します。
ここをクリアすれば、VBScriptの基本とイベント駆動の概念はバッチリマスターできますよ!
—
1. なぜ「非同期イベント受信」が必要なのか?
まずは、なぜこのテクニックが重要なのかを整理しましょう。
一般的なスクリプトは「同期処理(上から順番に実行し、終わるまで待つ)」で動きます。
【同期処理のイメージ】
スクリプト: 「Webページを開け!」
スクリプト: 「…まだかな…まだかな…(ひたすら待機中/CPUリソース消費)」
スクリプト: 「あ、終わった? じゃあ次の処理へ」
これに対し、「非同期イベント受信」を使うとスクリプトの動きが変わります。
【非同期処理のイメージ】
スクリプト: 「Webページを開いておいてね。終わったら『通知』をちょうだい!」
スクリプト: 「通知が来るまで、私は別の作業をするか静かに眠っています」
外部オブジェクト: 「読み込み完了しました!(イベント発火)」
スクリプト: 「了解! イベント専用の関数(ハンドラー)を動かします」
ひたすら状態を監視(ポーリング)する無駄なループを排除し、「何か起きた時だけ動く」エレガントなコードが書けるようになるのが最大のメリットです。
—
2. 魔法の鍵:`WScript.CreateObject` の第2引数
VBScriptには、オブジェクトを生成する命令が2種類あります。ここが一番陥りやすい罠です!
1. `CreateObject(“…”)`
→ VBScript言語自身の標準関数。イベント受信はできません。
2. `WScript.CreateObject(“…”, “プレフィックス_”)`
→ WSH(実行環境)が提供する上位関数。第2引数を指定することでイベント受信が可能になります!
イベントが届く仕組み(イメージ図)
+———————————————————+
| WSH (Windows Script Host) 実行環境 |
| |
| [COMオブジェクト] |
| │ (イベント “DocumentComplete” が発生!) |
| ▼ |
| WSHが横取り ──> 「プレフィックス_」+「イベント名」を検索 |
| │ |
| ▼ |
| [VBScript内の Sub 割り出し] |
| Sub IE_DocumentComplete(ByVal pDisp, ByVal URL) |
+———————————————————+
第2引数に `”IE_”` という文字列(プレフィックス)を指定しておくと、外部オブジェクトでイベントが発生した際、WSHが自動的に `IE_イベント名` という名前の `Sub` プロシージャを探して実行してくれるのです。
—
3. 実践コード:Internet Explorerのイベントを非同期で監視する
それでは、実際のコードを見てみましょう。
今回は「Webブラウザを起動し、ページの読み込み完了(`DocumentComplete`)や、ユーザーがブラウザを閉じた(`OnQuit`)タイミングを非同期でキャッチする」スクリプトを作成します。
【コピペで試せる完全コード】
‘ ==============================================================================
‘ 【機能】WScript.CreateObject の第2引数を用いた非同期イベント監視サンプル
‘ ==============================================================================
Option Explicit
‘ 処理完了を判定するためのフラグ
Dim isFinished
isFinished = False
WScript.Echo “1. スクリプトを開始します。”
‘ ——————————————————————————
‘ ポイント: 第2引数に “IEEvent_” というプレフィックスを指定してオブジェクト生成
‘ ——————————————————————————
Dim ie
Set ie = WScript.CreateObject(“InternetExplorer.Application”, “IEEvent_”)
‘ ブラウザの設定
ie.Visible = True
ie.Navigate “https://www.google.com”
WScript.Echo “2. ナビゲーションを開始しました。イベント発生を待機します…”
‘ ——————————————————————————
‘ メインスレッドの保持ループ
‘ ※VBScriptはイベントを待つ間、メインスクリプトが終了しないように維持する必要があります
‘ ——————————————————————————
Do While Not isFinished
‘ CPU使用率が高騰しないよう、100ミリ秒ごとにスリープ
WScript.Sleep 100
Loop
WScript.Echo “5. メインスクリプトを終了します。”
‘ オブジェクトの破棄
Set ie = Nothing
WScript.Quit
‘ ==============================================================================
‘ イベントハンドラー定義エリア
‘ 命名ルール: [第2引数で指定した文字列] + [COMオブジェクトのイベント名]
‘ ==============================================================================
‘ ■イベント1: ページの読み込みが完了した時に呼ばれる
Sub IEEvent_DocumentComplete(ByVal pDisp, ByVal URL)
WScript.Echo “3. 【イベント受信】ページの読み込みが完了しました!”
WScript.Echo ” アクセス先 URL: ” & URL
‘ ここで目的の処理を実行後、ブラウザを閉じることも可能です
End Sub
‘ ■イベント2: ユーザーによってブラウザが閉じられた時に呼ばれる
Sub IEEvent_OnQuit()
WScript.Echo “4. 【イベント受信】ブラウザが閉じられました。”
‘ 待機ループを抜けるためのフラグを立てる
isFinished = True
End Sub
—
4. コードの深掘り解説と重要なポイント
上記コードには、プロのエンジニアが必ず押さえている重要なノウハウが詰まっています。
ポイント①:メインスレッドを終了させない「待機ループ」
VBScriptは上から下に実行されて終わる直線的な言語です。
イベントハンドラー(`Sub IEEvent_…`)を用意しても、メイン処理が最後まで走り抜けてスクリプト自体が終了してしまうと、イベントを受け取ることができません。
そのため、`Do While Not isFinished` のように「フラグが立つまで待つループ」を作り、その中で `WScript.Sleep 100` を呼び出します。`Sleep` を挟むことで、CPUリソースを無駄に消費せずにイベントの到来を優雅に待つことができます。
ポイント②:イベントプロシージャの引数ルール
イベントハンドラー側の `Sub` の引数(例: `ByVal pDisp, ByVal URL`)は、COMオブジェクト側が定義している仕様とぴったり一致している必要があります。
引数の数が違ったりすると、イベントが発生しても関数が正しく呼び出されず、無視されてしまうので注意してください。
—
5. 初学者がハマりやすい「3大落とし穴」と対処法
開発現場で「動かない!」と頭を抱える人の9割が以下のどれかに該当しています。チェックリストとしてご活用ください。
罠1:`CreateObject` を使ってしまう
- NG: `Set obj = CreateObject(“ProgID”, “Prefix_”)`
- OK: `Set obj = WScript.CreateObject(“ProgID”, “Prefix_”)`
- 解説: VBScript組み込みの `CreateObject` は引数を1つ(またはリモートサーバー名を含む2つですが意味が異なります)しか取りません。必ず頭に `WScript.` を付けてください。
罠2:イベント名・プレフィックスのスペルミス
- 原因: 1文字でもタイポがあると、WSHは「該当する割り込み関数なし」と判断し、エラーも出さずにスルーします。
- 対策: プレフィックスの末尾にアンダースコア `_` を付与し、`IEEvent_DocumentComplete` のように明瞭な命名にするのがベストプラクティスです。
罠3:`cscript.exe` / `wscript.exe` の実行環境
イベント受信機能は、Windowsの標準ホスト(CScriptまたはWScript)上でしか動作しません。一部の特殊な埋め込みVBScript環境ではサポートされていない場合があるため、コマンドプロンプトや標準のスクリプト実行環境で動かすことを前提としましょう。
—
6. 先輩エンジニアからのアドバイス:この技術の本質
今回学んだ「イベントを受信する」という考え方は、VBScriptだけに留まらないプログラミングの本質的な思考パターン(イベント駆動アーキテクチャ)です。
将来、VBAから VB.NET, C#, JavaScript (Node.js), Python などへステップアップする際も、「非同期処理」「コールバック関数」「イベントハンドラー」という概念が必ず登場します。
「自分から見に行かず、相手からの通知を待つ」
この思考にシフトできれば、あなたの書く自動化プログラムは一気に洗練され、無駄のないスマートなシステムへと進化します。
—
まとめ
1. `WScript.CreateObject` の第2引数に文字列を指定するとイベント監視モードになる
2. イベントハンドラーは `[指定した文字列][イベント名]` という名前の `Sub` で作成する
3. イベントを待つ間は `WScript.Sleep` を含めた待機ループでメイン処理を維持する
4. `CreateObject`(標準)と `WScript.CreateObject`(WSH固有)の違いに注意する!
ここまでの仕組みを理解できれば、VBScriptの基礎およびWSHの環境特性の理解はバッチリです!
ぜひお手元の環境でコードを動かしてみて、イベントが「ひょっこり」呼び出される快感を味わってみてくださいね。
これからもあなたの自動化プログラミング学習を応援しています!質問があればいつでも聞いてください。
