こんにちは!現場でバリバリ自動化ツールを作っていると、「同じスクリプトが何度もクリックされて、裏で何重にもプロセスが走っちゃった……」「ユーザーが何度もアプリを立ち上げてパニックになっている」なんていうトラブルに直面したことはありませんか?
業務自動化を進めるうえで、「二重起動の防止」と「すでに動いている画面をユーザーの目の前にパッと呼び出す(フォーカス制御)」は、プロっぽさと実用性をグッと上げるための必須テクニックです。
今回は、VBScriptとWSH(Windows Script Host)の標準機能だけで、このスマートな制御を完璧に実現する方法を伝授します。ここをクリアすれば、あなたの作る自動化スクリプトは一段と洗練されますよ。さあ、一緒に見ていきましょう!
—
なぜ「二重起動の制御」が必要なのか?
エクセルマクロからの脱却や、業務の自動化(RPA的なアプローチ)を目指すとき、VBScriptは非常に手軽で強力な武器になります。しかし、手軽ゆえに、ユーザーが何度もアイコンをダブルクリックしてしまうという「ヒューマンエラー」を防ぐ仕組みがデフォルトではありません。
もし二重起動を放置するとどうなるでしょうか?
- 同じ処理が並行して走り、ファイルの競合(ロック)が起きる。
- メモリやCPUが無駄に消費され、PCの動作が重くなる。
- 画面上に同じウィンドウがいくつも現れ、ユーザーがどれを操作していいか分からなくなる。
これを防ぐために、「起動する前に、すでに自分が(あるいは対象のアプリが)いないかチェックし、もし居たら新規起動を諦めて、既存のウィンドウを最前面に呼び出す」という優しさを持ったコードを書きましょう。
—
魔法のコマンド `AppActivate` の正体
今回の主役は、WScriptシェルが持つ `AppActivate`(アップ・アクティブイト) というメソッドです。
このメソッドは、指定した「ウィンドウのタイトル(の一部)」をWindowsの背後から探し出し、見つかればそのウィンドウをアクティブ(最前面・操作可能状態)にしてくれます。さらに、その成否を `True` / `False` のブール値で返してくれるという、二重起動検知にはうってつけの性質を持っています。
ざっくりした仕組みのイメージ
[スクリプト実行]
↓
「私のウィンドウタイトル、すでに開いてる?」 (AppActivate)
├── [YES / すでに開いている] ──> 既存のウィンドウを最前面へ! (新規起動はしない)
└── [NO / まだ開いていない] ──> 新しく処理をスタート!
—
【実践】コピペで使える!二重起動防止&フォーカス制御スクリプト
それでは、実際の現場でそのまま使えるコードをご紹介します。
メモ帳(Notepad)などを例にしても良いのですが、今回は「このVBScript自体が二重起動しないように制御する」テンプレートコードを見てみましょう。
デスクトップなどに `counter_app.vbs` という名前で保存して試してみてください。
‘ ==============================================================================
‘ スクリプト名: 二重起動防止&フォーカス制御サンプル
‘ 概要: 自身のタイトルを検知し、二重起動の場合は既存ウィンドウを最前面にする
‘ ==============================================================================
Option Explicit
Dim wshShell, scriptTitle
scriptTitle = “【業務自動化ツール】専用ダッシュボード”
‘ WScript.Shell オブジェクトの生成
Set wshShell = WScript.CreateObject(“WScript.Shell”)
‘ ——————————————————————————
‘ 1. すでに同じタイトルのウィンドウ(プロセス)が起動しているかチェック
‘ ——————————————————————————
‘ AppActivateは、指定したタイトルを持つウィンドウをアクティブにしようと試みます。
‘ 成功すれば True、見つからなければ False を返します。
If wshShell.AppActivate(scriptTitle) Then
‘ — 【すでに起動していた場合の処理】 —
MsgBox “このツールは既に起動しています。” & vbCrLf & _
“既存のウィンドウを最前面に呼び出しました。”, _
vbInformation + vbSystemModal, “二重起動検知”
‘ オブジェクトの解放
Set wshShell = Nothing
WScript.Quit(0) ‘ 処理をここで美しく終了
End If
‘ ——————————————————————————
‘ 2. 新規起動時のメイン処理
‘ ——————————————————————————
‘ ここから下が、本来実行したかったメインの処理になります。
‘ わかりやすいように、ウィンドウタイトルを設定してメッセージを出します。
‘ ※注意: VBScript自体にはウィンドウタイトルを直接変更する命令がないため、
‘ 実際に自分のタイトルを持たせるには、htaファイルにするか、別アプリを操作するのが一般的です。
‘ 今回は「新規起動したよ」というサインとしてメッセージを出します。
MsgBox “メイン処理を開始します!” & vbCrLf & _
“(このウィンドウが開いている間にもう一度スクリプトを実行してみてください)”, _
vbInformation, scriptTitle
‘ メイン処理のシミュレーション(実際にはここに重い処理やIE/Edge操作などを書きます)
WScript.Sleep 2000
MsgBox “すべての処理が完了しました。”, vbInformation, scriptTitle
‘ 後始末
Set wshShell = Nothing
—
コードのここがポイント!エンジニアの知見
ただ動くだけのコードから脱却するために、知っておくべきポイントを解説します。
1. `Option Explicit` はプロの証
冒頭にある `Option Explicit` は、「変数の宣言を強制する」お呪いです。これを書くことで、うっかりミスによるタイポ(スペルミス)で予期せぬバグを生むのを防げます。大規模なVBScriptを書くときは絶対に入り口に置きましょう。
2. `AppActivate` の検索は「部分一致」
`AppActivate` の引数に渡す文字列は、ウィンドウタイトルの「前方一致・部分一致」でヒットします。そのため、タイトルが一意(ユニーク)になるような工夫が必要です。ありふれたタイトル(例:「設定」や「エラー」など)を指定すると、関係ない別のアプリを最前面にしてしまう誤爆が起きるので注意してください。
3. オブジェクトのライフサイクルを意識する
`Set wshShell = Nothing` をスクリプトの最後に記述しています。VBScriptは終了時にメモリが解放されますが、COMコンポーネント(WScript.Shellなど)は明示的に `Nothing` を代入してメモリをキレイに掃除する習慣をつけておくと、メモリリークやプロセス残留を防げます。こういう細かな気配りが「できるエンジニア」の分かれ道です。
—
陥りやすい罠とエラー対策
実際に現場でこの仕組みを導入するときによくある落とし穴をいくつか紹介します。
- Q. ウィンドウタイトルを変えるアプリじゃないと使えないの?
- A. その通りです。`AppActivate` は「ウィンドウのタイトルバーに見えている文字列」を探します。もしVBScript単体ではなく、特定のExcelブックやブラウザ、自作のEXEを対象にする場合は、そのアプリの正確なウィンドウタイトルを正確に指定してあげてください。
- Q. ターミナルやコマンドプロンプト経由だとタイトルが変わる?
- A. `cscript.exe` や `wscript.exe` で実行する場合、実行中のコマンドプロンプトのタイトルがスクリプト名に完全に一致しないことがあります。確実を期すならば、VBScriptからhta(HTML Application)を呼び出すか、ウィンドウタイトルをコントロールできる環境と組み合わせるのがベストプラクティスです。
—
おわりに:ここをクリアすれば基本はバッチリ!
お疲れ様でした!今回は `AppActivate` を用いた二重起動の検知とフォーカス制御について解説しました。
ただコードを上から下に流すだけでなく、「すでに動いているユーザーの環境に寄り添う」という視点を入れるだけで、あなたが作る自動化ツールのクオリティはプロのレベルへと跳ね上がります。
ここをクリアできれば、VBScriptやWSHの基本的なオブジェクト操作、そしてWindowsのウィンドウ制御の勘所はもうバッチリです。ぜひ明日の開発現場で試してみてくださいね。あなたの業務自動化ライフがより快適になることを応援しています!
