【実務・中級編】【COMコンポーネント依存性チェック】 CreateObject 実行前のレジストリ (HKCR) 事前確認による安全なエラー未然防止 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【COMコンポーネント依存性チェック】CreateObject地獄からの脱却。レジストリ直叩きによる安全な事前診断ロジック

開発現場でVBScriptを扱うとき、最も恐ろしい瞬間とは何だろうか。
それは、入念に作り込んだスクリプトをクライアント端末で実行した瞬間、突如として画面に叩きつけられる「エラー 429: オブジェクトを作成できません」という冷徹なメッセージではないか。

`ADODB.Stream` による文字コード変換、`MSXML2.DOMDocument` によるXML解析、あるいは特定の業務システム用COMコンポーネント。これらはWindows標準機能やインストール済みソフトに依存しているため、「開発環境では動いたが、配布先の端末では環境差異により爆発する」というトラブルが後を絶たない。

今回は、このCOMコンポーネント依存性問題を根本から解決し、`CreateObject` を実行する前にレジストリ(`HKEY_CLASSES_ROOT`)を直接叩いて存在確認を行う、極限まで堅牢な事前診断ロジックを伝授する。

なぜ従来の `On Error Resume Next` は悪手なのか?

多くのプログラマブルなVBScript初学者(あるいは中途半端な経験者)は、依存性チェックのために以下のようなコードを書く。

‘ 【アンチパターン】エラートラップ頼みの甘い設計
On Error Resume Next
Set objStream = CreateObject(“ADODB.Stream”)
If Err.Number <> 0 Then
‘ エラー処理
MsgBox “COMがありません”
End If
On Error GoTo 0

このアプローチは一見して動くように見えるが、プロダクション環境のアーキテクチャとしては最悪である。

1. 例外処理の乱用とバグの隠蔽
`On Error Resume Next` は、対象の行以外の予期せぬエラー(構文上のミスやメモリ不足など)までも握り潰す。これにより、デバッグが極めて困難な「幽霊バグ」を生み出す温床となる。
2. COMの初期化コストとリソースリーク
たとえ失敗する事が分かっているコンポーネントであっても、OSは一度インスタンス生成を試みる。不要なプロセスの生成や、レジストリ・メモリへの負荷は、数百台の端末で一斉実行される業務自動化ツールにおいて無視できないパフォーマンス低下を招く。

真にプロフェッショナルなエンジニアであれば、「エラーが発生してから対処する」のではなく、「実行前に環境を診断し、安全なパスのみを通す」べきだ。

レジストリ(HKCR)によるProgID事前検証のメカニズム

WindowsのCOMコンポーネントは、すべてレジストリの `HKEY_CLASSES_ROOT (HKCR)` にその身分証明書(ProgIDやCLSID)を登録している。
つまり、`CreateObject(“ProgID”)` を呼ぶということは、OSが裏でこのレジストリツリーを検索しているに過ぎない。

であれば、スクリプト側から WMI(`StdRegProv`)を用いて直接レジストリを覗きに行けばよい。インスタンスを生成する前の「純粋なメタデータチェック」であるため、オーバーヘッドはほぼゼロであり、予期せぬ例外を発生させることもない。

【プロダクションコード】堅牢なCOM依存性チェッカー

以下のコードは、実務の現場でそのまま組み込める、依存性チェック機能付きのラッパー関数を含むスクリプトだ。
文字コード変換(`ADODB.Stream`)やXML操作(`MSXML2.DOMDocument.6.0`)など、環境によって有無が分かれるコンポーネントを安全に呼び出すための設計となっている。

Option Explicit

‘ ==============================================================================
‘ スクリプト名: ComDependencyChecker.vbs
‘ 概要 : COMコンポーネントの存在をレジストリから事前診断し、安全にインスタンスを生成する
‘ 著者 : 業務自動化アーキテクチャチーム
‘ ==============================================================================

Dim objStream
‘ 安全に ADODB.Stream のインスタンスを取得(存在しない場合は Nothing が返る)
Set objStream = SafeCreateObject(“ADODB.Stream”)

If objStream Is Nothing Then
MsgBox “必要なCOMコンポーネント (ADODB.Stream) がこの環境に登録されていません。”, vbCritical, “致命的な環境エラー”
WScript.Quit 1
End If

‘ — 以下、通常処理 —
Wscript.Echo “COMコンポーネントの生存を確認しました。処理を継続します。”
‘ objStream.Open …

‘ ——————————————————————————
‘ 関数名 : SafeCreateObject
‘ 引数 : ByVal strProgID (String) – チェック・生成対象のProgID
‘ 戻り値 : Object または Nothing
‘ 概要 : レジストリ(HKCR)を直接走査してProgIDの存在を確認後、安全にインスタンス化する
‘ ——————————————————————————
Function SafeCreateObject(ByVal strProgID)
Set SafeCreateObject = Nothing

‘ 1. レジストリベースの存在確認
If Not CheckProgIdExists(strProgID) Then
‘ ログ出力基盤があればここに連携
Exit Function
End If

‘ 2. 存在が担保されているため、安全にインスタンス生成
On Error Resume Next
Set SafeCreateObject = CreateObject(strProgID)
If Err.Number <> 0 Then
‘ レジストリにはあるがDLLが破損している等の極まれなケースをキャッチ
Err.Clear
Set SafeCreateObject = Nothing
End If
On Error GoTo 0
End Function

‘ ——————————————————————————
‘ 関数名 : CheckProgIdExists
‘ 引数 : ByVal strProgID (String)
‘ 戻り値 : Boolean (True: 存在する / False: 存在しない)
‘ 概要 : WMIのStdRegProvを使用してHKCR直下のProgIDキーの有無を検証
‘ ——————————————————————————
Function CheckProgIdExists(ByVal strProgID)
Dim objReg, strKeyPath, lRet
Const HKEY_CLASSES_ROOT = &H80000000

CheckProgIdExists = False

‘ WMIレジストリプロバイダに接続
On Error Resume Next
Set objReg = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”)
If Err.Number <> 0 Then
‘ WMIが死んでいる環境へのフォールバック(稀)
On Error GoTo 0
CheckProgIdExists = FallbackCreateCheck(strProgID)
Exit Function
End If
On Error GoTo 0

If objReg Is Nothing Then Exit Function

‘ HKCR直下のProgIDキーパス
strKeyPath = strProgID

‘ 3つ目の引数(0)はサブキーの存在確認を意味する(StdRegProv.EnumKey等は使わず直パス確認)
‘ ※厳密にはHKCR\が存在するかをEnumValues等で確認するが、
‘ シンプルにRPCRT4等を使わずともGetObjectでキーの存在を安全に弾ける。
‘ ここではレジストリッチキーの有無を調べるために GetStringValue 等を利用する。
Dim strDefaultVal
lRet = objReg.GetStringValue(HKEY_CLASSES_ROOT, strKeyPath, “”, strDefaultVal)

‘ 戻り値が 0 (ERROR_SUCCESS) であれば、キーが存在し既定値が読み込める状態
If lRet = 0 Then
CheckProgIdExists = True
End If
End Function

‘ ——————————————————————————
‘ 関数名 : FallbackCreateCheck
‘ 概要 : WMIが使えない環境用のフォールバック(最小限の例外処理区画)
‘ ——————————————————————————
Function FallbackCreateCheck(ByVal strProgID)
FallbackCreateCheck = False
On Error Resume Next
Dim dummyObj
Set dummyObj = CreateObject(strProgID)
If Err.Number = 0 Then
FallbackCreateCheck = True
Set dummyObj = Nothing
End If
Err.Clear
On Error GoTo 0
End Function

アーキテクトからの実践的アドバイス:保守性とパフォーマンスの極意

1. 「野良COM」依存からの脱却
業務自動化ツールを配布する際、Excelのバージョン違いや、Officeの32bit/64bit差異によって使えないCOMコンポーネントが存在する。特に `MSXML2.DOMDocument` はバージョンレス(`MSXML2.DOMDocument`)ではなく、バージョンを明示(`MSXML2.DOMDocument.6.0`)した上で今回の事前チェックを通すべきだ。
2. サイレント・ログの重要性
もし `SafeCreateObject` が `Nothing` を返した場合、単に処理を止めるのではなく、「どの端末で、どのコンポーネントの登録が欠落しているか」をテキストログやイベントビューアに出力する設計に組み込むこと。これが整っていれば、リモートデスクトップ越しのヘルプデスク工数は劇的に削減される。

VBScriptは古い言語学派に属するかもしれないが、Windows環境の自動化において、その手軽さと強力さは未だに代えがたいものがある。
「動けばいいや」のコードを卒業し、レジストリ層から環境を支配する堅牢なアーキテクチャで、あなたの業務自動化スクリプトを「絶対に止まらないインフラ」へと昇華させてほしい。

タイトルとURLをコピーしました