【AutoCAD VBA】複数バージョン共存の悪夢を断つ:COM参照の動的解決と堅牢なオープン制御
開発現場のエンジニア諸君、日々複雑怪奇なレガシー図面と格闘していることだろう。
特に、PC内にAutoCAD 2022、2023、2024といった複数のバージョンが同居する「マルチバージョン環境」において、VBAや外部COM連携で痛い目を見た者は少なくないはずだ。
「昨日まで動いていたマクロが、別バージョンのCADを起動した途端に沈黙した」
「`GetObject` が意図しないバージョンのプロセスを掴んでしまい、Type Mismatch(型が一致しません)のエラーで強制終了する」
今回は、こうした現場のエンジニアを絶望の淵に追い込む「バージョン競合とCOMバインドの罠」を完全になくすための極限の知見を授けよう。レイトバインドの本質を理解し、実務で絶対に破綻しないプロダクションコードの書き方を解説する。
—
1. なぜ「早期バインド(Early Binding)」はマルチ環境で地雷なのか?
VBAエディタ(VBE)の「参照設定」から `AutoCAD x.x Type Library` にチェックを入れるアプローチ――いわゆる早期バインドは、開発時にはインテリセンスが効いて非常に快適だ。しかし、これがマルチバージョン環境では最大の悪手となる。
参照設定を行った時点で、レジストリには特定のバージョン(例: `AutoCAD.Application.24.1` など)がハードコードされる。ユーザーのPC環境が変わったり、裏で別バージョンのAutoCADがバックグラウンド起動したりした瞬間、COMの型定義のミスマッチにより、コードは無慈悲なエラーを吐く。
プロフェッショナルな設計思想:完全なる「レイトバインド(Late Binding)」の徹底
複数バージョン共存環境を制するためには、コンパイル時解決を一切捨て去り、実行時に動的にオブジェクトを生成・制御する完全なレイトバインドを導入しなければならない。型定義子(`As AcadApplication` など)を排除し、すべて `As Object` で抽象化するのだ。
—
2. 意図したバージョンを確実に手懐ける:ProgIDの動的解決ロジック
複数のAutoCADがインストールされている場合、単に `CreateObject(“AutoCAD.Application”)` を呼ぶと、OSが最後にインストールされた(あるいはアクティブな)バージョンを気まぐれに返す。これでは業務ツールとして使い物にならない。
特定のバージョン(例: AutoCAD 2023 なら `AutoCAD.Application.24.2`)をピンポイントで起動、あるいは既存のプロセスから安全にアタッチする設計が必要だ。
—
3. 【プロダクションコード】堅牢なマルチバージョン・オープン制御モジュール
以下のコードは、実務の現場でそのまま組み込める、バージョン指定型の安全な図面オープン・制御モジュールである。エラーハンドリングとCOMオブジェクトの解放(ライフサイクル管理)を徹底している点に注目してほしい。
Option Explicit
‘ ==============================================================================
‘ モジュール名: modAutoCADController
‘ 概要: 複数バージョン共存環境におけるAutoCAD動的アタッチ&図面オープン制御
‘ ==============================================================================
Public Sub ExecuteOpenDrawingWithVersion()
Dim targetVersion As String
Dim targetFilePath As String
Dim acadApp As Object
‘ 制御したいバージョンを指定 (例: AutoCAD 2023なら “AutoCAD.Application.24.2”)
‘ ※環境に合わせてProgIDを書き換えてください
targetVersion = “AutoCAD.Application.24.2”
‘ 処理対象のDWGファイルパス
targetFilePath = “C:\Projects\SampleDrawing_2023.dwg”
On Error GoTo ErrorHandler
‘ 1. 指定バージョンのAutoCADインスタンスを取得(または新規起動)
Set acadApp = GetOrCreateAcadInstance(targetVersion)
If acadApp Is Nothing Then
MsgBox “AutoCADのインスタンス生成に失敗しました。”, vbCritical, “致命的エラー”
Exit Sub
End If
‘ 2. 可視化とアクティブ化
acadApp.Visible = True
AppActivate acadApp.Caption
‘ 3. 図面の安全なオープン処理
Call OpenDrawingSafely(acadApp, targetFilePath)
MsgBox “図面のオープン制御が正常に完了しました。”, vbInformation, “完了”
‘ 4. クリーンアップ(オブジェクト変数の確実な解放)
Set acadApp = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
If Not acadApp Is Nothing Then Set acadApp = Nothing
End Sub
‘ ——————————————————————————
‘ 指定されたProgIDのAutoCADインスタンスを取得、または新規起動する関数
‘ ——————————————————————————
Private Function GetOrCreateAcadInstance(progID As String) As Object
Dim acadApp As Object
On Error Resume Next
‘ 既存の同名プロセスから取得を試みる(GetObjectはマルチ環境では誤動作しやすいため、
‘ バージョン固定のProgIDでCreateObjectの挙動を利用するか、プロセスを精査する)
‘ マルチ環境における確実なアプローチ:
‘ 指定したProgIDで強制的に新規インスタンスを立ち上げる、
‘ またはCreateObjectでOSにルーティングさせる。
Set acadApp = CreateObject(progID)
If Err.Number <> 0 Then
‘ 該当バージョンが見つからない場合のエラーハンドリング
Err.Clear
Set acadApp = Nothing
End If
On Error GoTo 0
Set GetOrCreateAcadInstance = acadApp
End Function
‘ ——————————————————————————
‘ すでに開いている図面の重複チェックを行いつつ安全にオープンするプロシージャ
‘ ——————————————————————————
Private Sub OpenDrawingSafely(ByRef acadApp As Object, ByVal filePath As String)
Dim docs As Object
Dim doc As Object
Dim i As Long
Dim isAlreadyOpen As Boolean
Set docs = acadApp.Documents
isAlreadyOpen = False
‘ すでに開かれているドキュメントコレクションを走査
For i = 0 To docs.Count – 1
Set doc = docs.Item(i)
‘ 大文字小文字を区別せずにパスを比較
If StrComp(doc.FullName, filePath, vbTextCompare) = 0 Then
isAlreadyOpen = True
Exit For
End If
Next i
If isAlreadyOpen Then
‘ すでに開いている場合はアクティブ化
doc.Activate
Debug.Print “既存の図面をアクティブ化しました: ” & filePath
Else
‘ 開いていない場合は新規にオープン
‘ ※ファイルが存在するかどうかの事前チェック(FSO等)を推奨
Set doc = docs.Open(filePath)
Debug.Print “図面を新しくオープンしました: ” & filePath
End If
‘ オブジェクト参照の解放
Set doc = Nothing
Set docs = Nothing
End Sub
—
4. プロフェッショナルが守るべき3つの鉄則
上記のコードと設計思想を実装するにあたり、現場のリーダーとして以下の3点をチームに徹底してほしい。
① `GetObject()` の安易な使用を禁止する
「起動中のCADを掴む」ために `GetObject(, “AutoCAD.Application”)` を使う開発者が多いが、複数バージョン共存環境では「先に見つかった無関係なバージョンのプロセス」を掴んでしまう致命的なバグを引き起こす。バージョンを特定したい場合は、ProgID(`AutoCAD.Application.XX.X`)を明示的に指定した `CreateObject` を用いるか、Running Object Table (ROT) を走査する高度なAPI連携を検討すべきだ。
② メモリリークとCOMプロセスのゾンビ化を防ぐ
VBAからAutoCADを操作すると、VBA側が終了してもWindowsのバックグラウンドに `acad.exe` のゾンビプロセスが残り続ける現象が多発する。
これを防ぐためには、コード内で取得したオブジェクト(`Documents`, `AcadDocument` など)は、スコープを抜ける前に必ず `Set xxx = Nothing` で参照を断ち切ること。COMの参照カウントを0にすることが、安定稼働の絶対条件である。
③ バージョン間でのAPI仕様の差異(上位互換の罠)に備える
新しいバージョンで追加されたプロパティやメソッドを古いバージョンのAutoCADに対してレイトバインドで呼び出すと、実行時エラーが発生する。複数バージョンをサポートするツールを作る場合は、共通のコアAPI(古くから存在する基本図形操作など)のみに絞るか、バージョン番号を動的に取得して条件分岐(`Select Case`)を入れる設計が不可欠だ。
—
総括
AutoCADの複数バージョン共存環境におけるCOM制御は、一見すると泥臭い試行錯誤の連続に見える。しかし、「レイトバインドの徹底」「バージョン明示によるインスタンス制御」「厳格なオブジェクトライフサイクル管理」というエンジニアリングの原則を遵守すれば、環境に左右されない極めて堅牢な自動化システムを構築できる。
あなたの書くコードが、現場の非効率な手作業を根絶やしにする強力な武器となることを期待する。
