【極限の知見】AutoCADの「壁」を越える:マルチインスタンス制御と安全なデータ連携の設計思想
こんにちは。AutoCAD VBAの世界へようこそ。
マクロの記録ボタンを押し、「動いた!ラッキー!」と喜んでいたフェーズはもう卒業ですね。ここからは、「プログラムがプログラムを、プロセスがプロセスを操る」という、一段上のアーキテクチャの領域へ足を踏み入れていただきます。
今日扱うテーマは、非常にエキサイティングで、かつ、多くのエンジニアが挫折する難所です。
それは、「複数のAutoCADプロセス(マルチインスタンス)を跨いだ、図面データの受け渡しと同期保存」。
「今動いているこのAutoCAD(インスタンスA)から、別のウィンドウで開いているAutoCAD(インスタンスB)の図面を操作したい」
あるいは「複数の図面を別々のプロセスで開き、一斉に整合性を保ちながら保存したい」
そんな願いを叶えるための、プロフェッショナルな設計思想を伝授しましょう。
1. 「ThisDrawing」という名の、心地よい檻
まず、あなたがこれまで慣れ親しんできた `ThisDrawing` というオブジェクトについて、その「正体」を再定義しましょう。
VBAを書いているとき、私たちは無意識に `ThisDrawing.ActiveDocument` と書いています。これは非常に便利ですが、実は「自分自身が属しているプロセス(檻)の中」でしか通用しない言葉なのです。
プロセスの境界線(Process Boundary)
AutoCADを2つ起動しているとき、Windowsのタスクマネージャーを見ると、`acad.exe` が2つ並んでいるはずです。これらは、たとえ同じAutoCADであっても、「全く別の宇宙(メモリ空間)」に住んでいます。
- インスタンスAの宇宙: 独自のメモリ、独自のオブジェクト、独自の `ThisDrawing`
- インスタンスBの宇宙: 独自のメモリ、独自のオブジェクト、独自の `ThisDrawing`
インスタンスAのVBAから、インスタンスBの `ThisDrawing` を直接触ろうとすると、VBAは「そんなオブジェクトは知らないよ!」とエラーを吐いて止まってしまいます。これが、初心者が最初にぶち当たる「プロセスの壁」です。
2. 壁を越える架け橋:COM(Component Object Model)
では、どうやってこの壁を越えるのか? そこで登場するのが COM (Component Object Model) という技術です。
Windowsには、実行中のアプリケーションをリストアップし、外部からそれらを操作するための「名簿」のような仕組み(ROT: Running Object Table)があります。これを利用して、別のプロセスにいるAutoCADを「捕まえる」ことができるのです。
インスタンスを捕まえるための「魔法の言葉」
通常、新しいAutoCADを立ち上げるには `CreateObject` を使いますが、「既に開いている別のAutoCAD」を捕まえるには `GetObject` を使います。
' --- 概念図 ---
' [ あなたのVBA ] --- (GetObject) ---> [ 別のAutoCADプロセス ]
3. 実践:マルチインスタンス・コントロール・アーキテクチャ
それでは、具体的なコードを見ていきましょう。単に「動く」コードではなく、「現場で壊れない」ための堅牢な設計を盛り込んでいます。
実装のポイント:オブジェクトではなく「データ」を渡せ
ここが最も重要な知見です。
インスタンスAからインスタンスBへ、「図形のオブジェクトそのもの」を渡そうとしてはいけません。 オブジェクトはメモリ上の住所(ポインタ)で管理されていますが、その住所はインスタンスAの中でしか意味をなさないからです。
「図面のパス」や「座標値」「属性値」といった「純粋なデータ」として受け渡しを行うこと。 これが、プロフェッショナルな設計の鉄則です。
Option Explicit
''' <summary>
''' 実行中の別のAutoCADインスタンスを取得し、指定した図面を保存する
''' </summary>
Sub SyncSaveInOtherInstance()
Dim targetAcadApp As Object ' AutoCAD.Application
Dim targetDoc As Object ' AutoCAD.Document
Dim targetFilePath As String
' 1. 操作対象となる図面のパスを指定(本来は引数などで渡す)
targetFilePath = "C:\Work\Project_A.dwg"
On Error Resume Next
' 2. 【重要】実行中のAutoCADインスタンスを捕まえる
' GetObject(, "AutoCAD.Application") は、現在起動中のAutoCADを探します
Set targetAcadApp = GetObject(, "AutoCAD.Application")
If Err.Number <> 0 Then
MsgBox "実行中のAutoCADが見つかりません。AutoCADを起動してください。", vbCritical
Exit Sub
End If
On Error GoTo ErrorHandler
' 3. ターゲットのアプリ内で、特定の図面を探す
' 注意:インスタンスAからインスタンスBの「どの図面」を触るかは、
' 図面名やフルパスで判定する必要があります。
Dim doc As Object
Dim found As Boolean
found = False
For Each doc In targetAcadApp.Documents
' ファイルパスを比較して、目的の図面を特定する
If LCase(doc.FullName) = LCase(targetFilePath) Then
Set targetDoc = doc
found = True
Exit For
End If
Next doc
If Not found Then
MsgBox "指定された図面がターゲットのAutoCAD内で開かれていません。", vbExclamation
Exit Sub
End If
' 4. 図面の同期保存を実行
Debug.Print "保存を開始します: " & targetDoc.Name
targetDoc.Save
Debug.Print "保存が完了しました。"
MsgBox "別インスタンスの図面を安全に保存しました。", vbInformation
CleanUp:
' オブジェクトの解放(メモリリーク防止)
Set targetDoc = Nothing
Set targetAcadApp = Nothing
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanUp
End Sub
4. 陥りやすい「地雷」を回避する
この技術を扱う際、ベテランでも時折踏んでしまう地雷がいくつかあります。
① ゾンビプロセスの恐怖
`GetObject` で接続した後に、プログラムが異常終了したり、正しく `Set object = Nothing` を行わなかったりすると、AutoCADのプロセスがメモリ上に残り続けることがあります。これを「ゾンビプロセス」と呼びます。
タスクマネージャーに `acad.exe` が大量に残っている場合は、これらが原因です。必ず `On Error` でエラーハンドリングを行い、確実にオブジェクトを解放する癖をつけましょう。
② バージョン不一致の罠
AutoCAD 2023 と 2024 が両方インストールされている環境では、`GetObject(, “AutoCAD.Application”)` がどちらを指すかは、Windowsのレジストリ登録順に依存します。
「特定のバージョンを操作したい」という場合は、`AutoCAD.Application.24`(バージョン番号を指定)のように、より具体的なProgIDを使用する検討が必要です。
③ パフォーマンスの重み
複数のインスタンスをループで回して大量の処理を行うのは、非常にコスト(負荷)が高い操作です。
- 悪い例: 1つずつインスタンスを捕まえては、1つの図面を操作して、また閉じる。
- 良い例: インスタンスを一度捕まえたら、その中の `Documents` コレクションを全て走査し、一括で処理を行う。
最後に:ここをクリアすれば、あなたはもう「マクロ使い」ではない
「複数のAutoCADを操る」という技術は、単なる自動化の枠を超え、「システム設計」の領域です。
オブジェクトの寿命を意識し、プロセスの壁を理解し、データとして情報をやり取りする。この一連の流れをマスターすれば、あなたは単に「作業を楽にする人」から、「業務プロセスそのものを設計するエンジニア」へと進化できます。
最初はエラーに泣かされるかもしれません。でも、そのエラーメッセージの一つ一つが、プロセスの境界線を教えてくれる貴重なガイドになります。
一歩ずつ、着実に進んでいきましょう。応援していますよ!
