【特定COMオブジェクトの生存チェック】CreateObject失敗時のレジストリ自動確認とCOMコンポーネント再登録バッチ
レガシーシステムの呪縛、あるいはWindowsインフラストラクチャの深部において、VBScript(Visual Basic Scripting Edition)とWSH(Windows Script Host)のコンビネーションがいまだに現役の生命線として稼働している現場は少なくない。
夜間バッチの静寂を破る「エラー 428: オブジェクトは現在のコンポーネントには作成できません」あるいは「エラー 429: コンポーネントはオブジェクトを作成できません」。この冷徹な文字列に直面したとき、多くのエンジニアはリモートデスクトップを叩き起こし、手動で `regsvr32` を実行する泥臭い作業に追われる。
プロフェッショナルな自動化エンジニアであれば、この「COMコンポーネントの不在・破損・レジストリの乖離」というエントロピーの増大に対し、スクリプト自身が自己治癒(セルフヒーリング)能力を持つ仕組みを構築すべきだ。
今回は、`CreateObject` の深層メカニズムを紐解きながら、レジストリの動的走査と `regsvr32` のプログラム的アプローチを統合した、極限の自動メンテナンス・アーキテクチャを提示する。
—
1. COMオブジェクト生存チェックの設計思想
VBScriptにおける `CreateObject(ProgID)` は、背後でCOM(Component Object Model)のランタイムを呼び出し、レジストリハイブ(主に `HKEY_CLASSES_ROOT`)から `CLSID` を引き、最終的にインプロセス(DLL)またはアウトプロセス(EXE)のサーバーをロードする。
このライフサイクルにおいて障害が発生する要因は主に以下の3点に集約される。
1. DLL/OCXファイルの物理的な欠損(誤削除やアンチウイルスによる隔離)
2. レジストリのエントリの破損または未登録(OSのアップデートや不完全なアンインストール)
3. アーキテクチャの不整合(64bit環境での32bit COM呼び出しにおけるリダイ렉션問題)
単純に `On Error Resume Next` でエラーを握りつぶすだけのコードは、システム管理における悪手である。我々は、エラーを「正確に検知」し、「原因を特定」し、「自動修復」するトランザクションを構築しなければならない。
—
2. 実装コード:自己治癒型COMローダー
以下のスクリプトは、指定したProgIDの生存を確認し、失敗した場合にはレジストリから実体(InprocServer32など)のパスを逆引き、ファイルが存在すれば再登録、存在しなければアラートを返す完全自動化されたモジュールである。
Option Explicit
‘ ==============================================================================
‘ 致命的例外自動修復型 COMオブジェクト・ローダー
‘ Archtecture : WSH / VBScript 5.8
‘ ==============================================================================
Dim objTarget
Dim targetProgId
targetProgId = “Scripting.Dictionary” ‘ テスト用に標準コンポーネントを指定(適宜変更)
WScript.Echo “=== COMオブジェクト生存チェック開始: ” & targetProgId & ” ===”
Set objTarget = GetOrCreateObjectWithAutoRepair(targetProgId)
If Not objTarget Is Nothing Then
WScript.Echo “[SUCCESS] オブジェクトの取得に成功しました。”
‘ ここに実際のビジネスロジックを記述
objTarget.Add “TestKey”, “TestValue”
WScript.Echo “[INFO] テスト値の格納に成功: ” & objTarget(“TestKey”)
‘ 明示的メモリ解放 (ライフサイクル管理の鉄則)
Set objTarget = Nothing
Else
WScript.Echo “[FATAL] オブジェクトの回復および生成に完全に失敗しました。”
WScript.Quit 1
End If
WScript.Echo “=== 処理終了 ===”
WScript.Quit 0
‘ ==============================================================================
‘ 関数: GetOrCreateObjectWithAutoRepair
‘ 概要: オブジェクト生成を試み、失敗時はレジストリ確認とregsvr32による修復を試行
‘ ==============================================================================
Function GetOrCreateObjectWithAutoRepair(ByVal progId)
Dim instance
‘ 1次試行:通常生成
Set instance = SafeCreateObject(progId)
If Not instance Is Nothing Then
Set GetOrCreateObjectWithAutoRepair = instance
Exit Function
End If
WScript.Echo “[WARNING] CreateObject失敗。レジストリおよびモジュールの検証を開始します…”
‘ 2次試行:自動修復プロセスの発動
If RepairComComponent(progId) Then
‘ 修復成功後、再試行
Set instance = SafeCreateObject(progId)
If Not instance Is Nothing Then
WScript.Echo “[INFO] 修復後のオブジェクト生成に成功しました。”
Set GetOrCreateObjectWithAutoRepair = instance
Exit Function
End If
End If
Set GetOrCreateObjectWithAutoRepair = Nothing
End Function
‘ ==============================================================================
‘ 関数: SafeCreateObject
‘ 概要: 例外を安全に捕捉するラッパー
‘ ==============================================================================
Function SafeCreateObject(ByVal progId)
On Error Resume Next
Dim obj
Set obj = CreateObject(progId)
If Err.Number <> 0 Then
‘ エラーログの記録が必要な場合はここに記述
Err.Clear
Set SafeCreateObject = Nothing
Else
Set SafeCreateObject = obj
End If
On Error GoTo 0
End Function
‘ ==============================================================================
‘ 関数: RepairComComponent
‘ 概要: レジストリからDLLパスを特定し、regsvr32を実行する
‘ ==============================================================================
Function RepairComComponent(ByVal progId)
RepairComComponent = False
Dim shell, fso, clsId, dllPath
Set shell = CreateObject(“WScript.Shell”)
Set fso = CreateObject(“Scripting.FileSystemObject”)
On Error Resume Next
‘ Step A: ProgIDからCLSIDを取得 (HKEY_CLASSES_ROOT\
Dim clsIdRegPath
clsIdRegPath = “HKCR\” & progId & “\CLSID\”
clsId = shell.RegRead(clsIdRegPath)
If Err.Number <> 0 Then
WScript.Echo “[ERROR] レジストリにProgIDが見つかりません: ” & progId
Err.Clear
Exit Function
End If
‘ Step B: CLSIDからインプロセスサーバーのDLLパスを取得 (HKEY_CLASSES_ROOT\CLSID\
Dim serverRegPath
serverRegPath = “HKCR\CLSID\” & clsId & “\InprocServer32\”
dllPath = shell.RegRead(serverRegPath)
If Err.Number <> 0 Then
WScript.Echo “[ERROR] 該当するInprocServer32エントリが見つかりません (Out-of-procの可能性あり).”
Err.Clear
Exit Function
End If
‘ 規定値(Default)以外に余計な文字列が入っている場合や環境変数を含む場合の簡易的なクリーニング
dllPath = Trim(dllPath)
WScript.Echo “[INFO] 検出されたコンポーネントパス: ” & dllPath
‘ Step C: 物理ファイルの存在確認
If Not fso.FileExists(dllPath) Then
WScript.Echo “[FATAL] 実体ファイルが存在しません。再インストールが必要です: ” & dllPath
Exit Function
End If
‘ Step D: regsvr32によるサイレント再登録実行
WScript.Echo “[INFO] regsvr32を実行してコンポーネントを再登録します…”
Dim cmd
‘ /s = サイレントモード(ダイアログを出さない)
cmd = “regsvr32.exe /s “”” & dllPath & “”””
Dim exitCode
exitCode = shell.Run(cmd, 0, True) ‘ 0=非表示, True=同期実行
If exitCode = 0 Then
WScript.Echo “[SUCCESS] COMコンポーネントの再登録に成功しました。”
RepairComComponent = True
Else
WScript.Echo “[ERROR] regsvr32が非ゼロの終了コードを返しました: ” & exitCode
RepairComComponent = False
End If
On Error GoTo 0
End Function
—
3. チーフアーキテクトが解説するコードの急所と技術的ポイント
オブジェクトの明示的解放(`Set … = Nothing`)
VBScriptのガベージコレクション(参照カウント方式)はスコープを抜ければ基本的には解放されるが、長期稼働するWSHプロセスや、エラーハンドリングを挟む複雑な制御フローにおいては、メモリリークやCOM参照のゾンビ化を招く。
特に `CreateObject` と再登録プロセスを同一セッションで行う場合、確実に `Set objTarget = Nothing` を明示し、COMコンポーネントの解放フェーズ(`IUnknown::Release`)を明示的にトリガーさせることが、ファイルロック(Sharing Violation)を防ぐ絶対条件となる。
WSHの `Shell.RegRead` によるレジストリ走査
`WScript.Shell` の `RegRead` メソッドは、`HKCR`(HKEY_CLASSES_ROOT)のハイブを直接引くことができる。
通常の `ProgID` から `CLSID`、そして `InprocServer32`(または `LocalServer32`)に至るパスを動的に辿ることで、インストーラーがどこにDLLを配置したかをハードコーディングなしで完全自動追跡できる。これにより、環境依存性を極限まで排除したポータブルなメンテナンススクリプトが完成する。
`regsvr32.exe` のサイレント実行と同期制御
`shell.Run(cmd, 0, True)` の第3引数 `True`(WaitOnReturn)は極めて重要である。
非同期(`False`)にしてしまうと、`regsvr32` がレジストリ書き込みを完了する前に次の `CreateObject` が走ってしまい、競合エラー(Race Condition)を引き起こす。OSの非同期処理をVBScript側で確実に調停するため、同期実行は必須の設計パターンである。
—
4. エンジニアリングの現場へ向けて
レガシーシステムは「動いているから触らない」という免罪符のもとに放置されがちだが、OSのセキュリティパッチや環境変化によって、ある日突然COMのリンクが切断されるリスクを常に孕んでいる。
ここに提示した自動修復スクリプトをタスクスケジューラや、基幹バッチのイニシャライザ(前処理)として組み込んでおくことで、深夜の緊急呼び出しを未然に防ぐことができる。
VBScriptは過去の遺物ではない。APIとレジストリ、そしてOSの挙動を熟知したエンジニアの手にかかれば、現代のCI/CDパイプラインにも匹敵する堅牢な自己修復エージェントへと昇華させることができるのだ。
