AutoCAD VBAを掌握する極限の知見:複数バージョン混在環境を制する「バージョン完全指定型」起動制御のアーキテクチャ
こんにちは。開発プロジェクトの現場において、数々のレガシーなCAD自動化システムを現代的な堅牢システムへとリファクタリングしてきたチーフアーキテクトの私だ。
AutoCAD VBAの実務において、最も恐ろしい瞬間を想像してほしい。
「昨日まで完璧に動いていた自動化マクロが、新しいバージョンのAutoCADをインストールした途端に、別のバージョンのプロセスを勝手に掴んでハングアップする、あるいは謎のオートメーションエラー(Error 429: オートメーション サーバーはオブジェクトを作成できません)を吐いて沈黙する」――この悪夢のような現象に直面した開発者は少なくないはずだ。
なぜこの問題が起きるのか? そして、どう設計すればこのカオスなマルチバージョン環境を完全に支配できるのか?
今回は、レジストリの深部からAutoCADのCOMオブジェクトモデルのライフサイクルまでを紐解き、環境に一切依存しない、プロフェッショナルな起動制御の実装手法を授けよう。
—
1. なぜ「`CreateObject(“AutoCAD.Application”)`」は実務で破綻するのか?
多くの入門書やネットの記事では、AutoCADをVBAから起動する方法として以下のように記述されている。
‘ 【アンチパターン】実務では絶対に書いてはならないコード
Dim acadApp As Object
Set acadApp = CreateObject(“AutoCAD.Application”)
このコードの何が問題なのだろうか?
`”AutoCAD.Application”` という文字列は、Windowsのレジストリにおいて「バージョン非依存のProgID(Version-Independent ProgID)」と呼ばれる。これを呼び出した場合、OSはレジストリの `HKEY_CLASSES_ROOT\AutoCAD.Application\CurVer` を参照し、そのシステムに最後にインストールされた(あるいは最後にファイル関連付けを上書きした)AutoCADのインスタンスを容赦なく起動、あるいは既存セッションにアタッチする。
つまり、「開発時はAutoCAD 2022でテストしていたのに、ユーザーがAutoCAD 2024をインストールした瞬間に予期せぬバージョンで起動し、APIの仕様差や図面バージョンのミスマッチで致命的なエラーを引き起こす」という事態が確約されるわけだ。
実務におけるプロのエンジニアリングとは、「環境の揺らぎを排除し、意図した通りのプロセスを確実にコントロールすること」に他ならない。
—
2. 解決策:バージョン依存ProgIDとレジストリからの動的取得
特定のバージョン(例:AutoCAD 2022 なら `AutoCAD.Application.24.1`)を直接指定する方法もあるが、これもハードコーディングするのはスマートではない。将来のバージョンアップや環境ごとの差異に耐えられないからだ。
ここで、Windowsレジストリの構造を深く理解し、「マシンのインストール状況を動的にスキャンし、指定したバージョンに合致する正確なProgIDを特定してアタッチ・起動する」という堅牢なアーキテクチャを導入する。
AutoCADのバージョンと内部メジャーバージョンの対応表
実務で迷わないために、主要なバージョンと内部コードネーム(ProgIDの末尾)の対応を把握しておこう。
| AutoCADバージョン | リリース年 | 内部バージョン (ACAD) | プログラムID (ProgID) の例 |
| :— | :— | :— | :— |
| AutoCAD 2021 | 2020 | 24.0 | `AutoCAD.Application.24.0` |
| AutoCAD 2022 | 2021 | 24.1 | `AutoCAD.Application.24.1` |
| AutoCAD 2023 | 2022 | 24.2 | `AutoCAD.Application.24.2` |
| AutoCAD 2024 | 2023 | 24.3 | `AutoCAD.Application.24.3` |
| AutoCAD 2025 | 2024 | 25.0 | `AutoCAD.Application.25.0` |
—
3. 【プロダクションコード】堅牢なマルチバージョン制御モジュール
それでは、実務の現場でそのままコピー&ペーストして即座に組み込める、極限まで最適化されたVBAコードを公開する。
このコードは、指定されたバージョン(例: “24.1” など)のAutoCADがすでに起動していればそれにアタッチ(GetActiveObject)し、起動していなければそのバージョンのプロセスを正確に新規起動(CreateObject)する、業界標準の「ロバスト・ファクトリーパターン」を実装している。
Option Explicit
‘ Windows API: 実行中のCOMオブジェクトを取得するため
If VBA7 Then
Declare PtrSafe Function GetActiveObject Lib “oleaut32.dll” ( _
ByRef rclsid As Long, _
ByVal pvReserved As LongPtr, _
ByVal ppunk As LongPtr) As Long
Declare PtrSafe Function CLSIDFromProgIDEx Lib “ole32.dll” ( _
ByVal lpszProgID As LongPtr, _
ByRef pclsid As Long) As Long
Else
Declare Function GetActiveObject Lib “oleaut32.dll” ( _
ByRef rclsid As Long, _
ByVal pvReserved As Long, _
ByVal ppunk As Long) As Long
Declare Function CLSIDFromProgIDEx Lib “ole32.dll” ( _
ByVal lpszProgID As String, _
ByRef pclsid As Long) As Long
End If
Const S_OK As Long = 0
”
‘ 指定したバージョンのAutoCADアプリケーションオブジェクトを取得・起動する
‘ @param targetVersion string 例: “24.1” (AutoCAD 2022), “24.3” (AutoCAD 2024)
‘ @param visible boolean ウィンドウを表示するかどうか
‘ @return AcadApplication 取得したAutoCADアプリケーションインスタンス
”
Public Function GetSpecificAutoCADApplication(ByVal targetVersion As String, Optional ByVal visible As Boolean = True) As Object
Dim progID As String
Dim acadApp As Object
Set acadApp = Nothing
‘ バージョン依存の正確なProgIDを組み立てる
progID = “AutoCAD.Application.” & targetVersion
On Error GoTo ErrorHandler
‘ 1. すでに起動している同一バージョンのプロセスへのアタッチを試みる
Set acadApp = GetRunningInstance(progID)
‘ 2. 起動していなければ、新規にプロセスを生成する
If acadApp Is Nothing Then
Set acadApp = CreateObject(progID)
End If
‘ 可視性の制御
If Not acadApp Is Nothing Then
acadApp.visible = visible
End If
Set GetSpecificAutoCADApplication = acadApp
Exit Function
ErrorHandler:
MsgBox “指定されたバージョン (” & targetVersion & “) のAutoCADの起動に失敗しました。” & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “AutoCAD制御エンジン”
Set GetSpecificAutoCADApplication = Nothing
End Function
”
‘ 実行中の特定のProgIDのインスタンスのみを安全に取得するヘルパー関数
”
Private Function GetRunningInstance(ByVal progID As String) As Object
Dim clsid(3) As Long
Dim unknown As Object
Dim hr As Long
‘ ProgIDからCLSIDを取得
#If VBA7 Then
hr = CLSIDFromProgIDEx(StrPtr(progID), clsid(0))
#Else
hr = CLSIDFromProgIDEx(progID, clsid(0))
#End If
If hr <> S_OK Then
‘ レジストリに登録されていないバージョン
Set GetRunningInstance = Nothing
Exit Function
End If
‘ 実行中オブジェクトの取得を試みる
hr = GetActiveObject(clsid(0), 0, VarPtr(unknown))
If hr = S_OK Then
Set GetRunningInstance = unknown
Else
Set GetRunningInstance = Nothing
End If
End Function
‘ — 実行テスト用プロシージャ —
Public Sub Test_StartAcad2022()
Dim acadDoc As Object
Dim targetVer As String
‘ 例: AutoCAD 2022 を確実に指定して起動する
targetVer = “24.1”
Dim acadApp As Object
Set acadApp = GetSpecificAutoCADApplication(targetVer, True)
If Not acadApp Is Nothing Then
MsgBox “正常に AutoCAD ” & acadApp.version & ” を制御下に入れました。”, vbInformation
‘ 新規図面の追加テスト
Set acadDoc = acadApp.Documents.Add()
‘ ここに業務ロジックを記述…
End If
End Sub
—
4. プロジェクトアーキテクトからの実践的アドバイス
上記のコードを現場に導入するにあたり、以下の3点を必ず遵守してほしい。
1. エラーハンドリングの徹底とオブジェクトの解放
VBAにおいてCOMオブジェクトを操作する場合、参照の解放漏れ(`Set acadApp = Nothing`)はメモリリークやバックグラウンドプロセス(acad.exe)のゾンビ化を招く。処理の最後には必ずオブジェクト変数をクリーンアップすること。
2. データベース(Excel/Access/SQL)連携時の注意点
外部データベースから一括バッチ処理でAutoCADを操作する場合、複数プロセスが同時に立ち上がるとライセンス競合やメモリ圧迫を起こす。上記コードの `GetRunningInstance` の仕組みを使い、「常に単一のプロセスを再利用して図面を切り替えて処理する(SDI/MDIの挙動の把握)」設計にすることが、安定稼働させるための最大の秘訣だ。
3. 早期バインディング(参照設定)の誘惑を断つ
「型番補 sensação(インテリセンス)が使いたいから」という理由で、VBIDEの「参照設定」から特定のAutoCAD Type Libraryにチェックを入れてはならない。それをやった瞬間から、そのVBAファイルは他のバージョンのAutoCAD環境で動作しなくなる。実務のツール配布においては、常に遅延バインディング(CreateObject / Object型)を貫くことがプロの選択である。
—
総括
複数バージョンのAutoCADが混在する環境は、一見するとカオス極まりない。しかし、OSのCOMアーキテクチャの本質とレジストリの構造を理解し、今回紹介した「バージョン完全指定型の起動制御」を組み込むことで、その不安要素を完全にコントロール下に置くことができる。
あなたの書くコードが、環境に左右されない「揺るぎないインフラ」となることを期待している。次回の知見もお楽しみに。
