【実務中級】複数バージョンのAutoCADが混在する環境でのVBA実行:レジストリ参照による適切なAcadApplicationの起動制御
シニアエンジニアや社内CAD管理者であれば、一度は直面したことがあるはずだ。
「AutoCAD 2022がインストールされたPCと、2024が混在する環境で、共通のVBAツールが意図しないバージョンで起動し、型不一致エラーで沈黙する」という悪夢を。
一般的なVBA入門書は、こう教える。
`Set acadApp = GetObject(, “AutoCAD.Application”)` あるいは `CreateObject(“AutoCAD.Application”)` と。
だが、現実のエンタープライズ環境において、このコードは「動いたらラッキー」な爆弾に過ぎない。
なぜなら、COMの非依存ProgID(`AutoCAD.Application`)がどのバージョンのプロセスを指すかは、最後にインストールされた、あるいは最後にアクティブ化されたAutoCADの気まぐれに支配されるからだ。
今回は、複数バージョンのAutoCADが同居するカオスな環境下において、完全にバージョンを制御し、メモリリークをも根絶する「極限のAutoCAD VBAアーキテクチャ」を授けよう。
—
1. ProgIDの罠と、レジストリによる「バージョン特定」の真理
AutoCADはバージョンごとに独自のProgIDを持っている。
- AutoCAD 2022: `AutoCAD.Application.24.1`
- AutoCAD 2024: `AutoCAD.Application.24.3`
しかし、ハードコーディングでこれらを指定するのも愚策だ。クライアントの環境によってインストールパスやマイナーバージョンが異なる可能性がある。
真のプロフェッショナルは、Windowsレジストリから動的に、かつ確実にターゲットバージョンのCOMサーバーを特定し、起動する。
レジストリ構造の理解
AutoCADのバージョン情報は、以下のハイブに刻まれている。
`HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\` または `HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\`
このレジストリを走査し、目的のリリースイヤー(例: “R24.3” = AutoCAD 2024)に紐付くCLSID(Class ID)を直接取得するアプローチが最も堅牢である。
—
2. 実装コード:バージョン指定型 安全起動エンジン
以下のコードは、指定した西暦バージョン(例: 2024)のAutoCADが存在するかをレジストリから検証し、該当プロセスが存在すればアタッチ、なければ新規起動を安全に行う実務レベルのモジュールである。
Option Explicit
‘ Windows API Declarations for Registry access if needed,
‘ but for VBA, WScript.Shell is often sufficient and cleaner for Registry querying.
”’
”’
”’ 対象の西暦バージョン (例: 2022, 2024)
”’
Public Function GetSpecificAutoCADApplication(ByVal targetYear As Long) As Object
Dim progId As String
Dim acadApp As Object
On Error GoTo ErrorHandler
‘ 1. バージョンに応じた正確なProgIDを解決する
progId = ResolveProgIDByYear(targetYear)
If progId = “” Then
Err.Raise vbObjectError + 1000, “AutoCADLoader”, “指定されたバージョン (” & targetYear & “) のAutoCADがこのシステムに見つかりません。”
End If
‘ 2. 実行中のインスタンス取得(GetObject)を試みる
‘ ※バージョン固有ProgIDに対するGetObjectは、該当バージョンが起動中の場合のみ成功する
On Error Resume Next
Set acadApp = GetObject(, progId)
On Error GoTo ErrorHandler
‘ 3. インスタンスが存在しない場合は新規起動(CreateObject)
If acadApp Is Nothing Then
Set acadApp = CreateObject(progId)
End If
‘ 4. 可視化の保証
acadApp.Visible = True
Set GetSpecificAutoCADApplication = acadApp
Exit Function
ErrorHandler:
‘ 異常系:オブジェクトの取りこぼしを防ぐクリーンアップ
Set acadApp = Nothing
Err.Raise Err.Number, “GetSpecificAutoCADApplication”, “AutoCADの起動に失敗しました。詳細: ” & Err.Description
End Function
”’
”’
Private Function ResolveProgIDByYear(ByVal targetYear As Long) As String
Dim internalVer As String
‘ Autodesk AutoCADの内部バージョンマッピング
Select Case targetYear
Case 2021: internalVer = “24.0”
Case 2022: internalVer = “24.1”
Case 2023: internalVer = “24.2”
Case 2024: internalVer = “24.3”
Case 2025: internalVer = “25.0”
Case Else
ResolveProgIDByYear = “”
Exit Function
End Select
‘ バージョン固有ProgIDの構築
Dim candidateProgID As String
candidateProgID = “AutoCAD.Application.” & internalVer
‘ レジストリ(CLSID)に登録されているか簡易チェック
If TestProgIDExists(candidateProgID) Then
ResolveProgIDByYear = candidateProgID
Else
ResolveProgIDByYear = “”
End If
End Function
”’
”’
Private Function TestProgIDExists(ByVal progID As String) As Boolean
Dim wsh As Object
On Error GoTo NotExist
Set wsh = CreateObject(“WScript.Shell”)
‘ レジストリのClassesルートからCLSIDの存在を確認
wsh.RegRead “HKEY_CLASSES_ROOT\” & progID & “\CLSID\”
TestProgIDExists = True
Set wsh = Nothing
Exit Function
NotExist:
TestProgIDExists = False
Set wsh = Nothing
End Function
—
3. メモリ最適化とCOMプロセスのライフサイクル管理
シニアエンジニアが最も執着すべきなのは「COMオブジェクトの完全な解放」と「ゾンビプロセスの根絶」である。
AutoCADを外部からVBA(あるいはExcel VBA等)で操作する場合、`.Application` や `.ActiveDocument` を変数に格納した瞬間、裏でCOMの参照カウンターがインクリメントされる。
処理の途中でエラーが発生したり、適切に `Nothing` を代入しないままプロシージャを抜けたりすると、タスクマネージャーに `acad.exe` が幽霊のように居座り続け、メモリを圧迫し、次回起動時のフリーズやファイルロックを引き起こす。
鉄則のクリーンアップパターン
オブジェクト変数を使用する際は、必ず `Finally` 相当のエラーハンドリング構造を構築せよ。
Public Sub ExecuteBatchDrawingProcess()
Dim acadApp As Object
Dim acadDoc As Object
On Error GoTo ErrorHandler
‘ AutoCAD 2024の明示的起動
Set acadApp = GetSpecificAutoCADApplication(2024)
‘ ドキュメントのオープン
Set acadDoc = acadApp.Documents.Open(“C:\CADData\Standard.dwg”)
‘ — ここに実際の業務ロジックを記述 —
acadDoc.Utility.Prompt “Automation processing executed successfully.”
‘ —————————————
acadDoc.Save
CleanUp:
‘ 【極めて重要】参照の明示的破棄(逆順が望ましい)
If Not acadDoc Is Nothing Then
‘ 必要に応じてドキュメントを閉じる
‘ acadDoc.Close False
Set acadDoc = Nothing
End If
‘ アプリケーション自体の参照も切る(プロセスを即座に終了させたい場合は .Quit を検討)
If Not acadApp Is Nothing Then
Set acadApp = Nothing
End If
Exit Sub
ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “System Error”
Resume CleanUp
End Sub
—
4. チーフアーキテクトからの提言:レガシーとモダンを繋ぐ知見
複数バージョンの混在環境における最大のリスクは、AutoCAD自体の仕様変更や、API(ActiveX Automation)の下位互換性の限界にある。
1. 早期バインディング(Early Binding)の誘惑を断て
参照設定に `AutoCAD x.x Type Library` を追加したくなる気持ちは分かる。だが、それをやると「特定のバージョンでしかコンパイルできない(=マルチバージョン対応が不可能になる)」という致命的な呪縛にかかる。複数バージョン環境を制したいのであれば、徹底して遅延バインディング(Late Binding / `As Object`)を貫き通すことだ。
2. プロセスアタッチの限界を理解せよ
`GetObject(, “AutoCAD.Application.24.3”)` は、すでにユーザーが手動で立ち上げている AutoCAD 2024 のインスタンスを掴む。もしユーザーが複数の 2024 を起動している場合、どのインスタンスが返されるかはOSのCOMルーティングに依存する。厳密な制御が必要な場合は、新規インスタンスを `CreateObject` で隔離するか、ウィンドウハンドル(HWND)を用いた高度なフックを検討すべき領域に入る。
社内システムのインフラを預かる者として、環境の差異にシステム側が適応するべきだ。レジストリを直視し、COMのライフサイクルをコントロール下に置くこと。それこそが、現場を止めることのない真のプロフェッショナルエンジニアリングである。
