AutoCAD VBAの深淵:CopyObjectsによる図面間転送の極致
AutoCADの自動化において、最も「素人」が陥りやすい罠が、クリップボード経由のコピー&ペースト(`SendCommand`等による`_COPYCLIP`や`_PASTECLIP`)だ。これはUIスレッドに依存し、メモリを浪費し、何より予期せぬ外部要因で処理が停止する。
真のエンジニアは、AutoCADのメモリ空間を直接操作する。今回は、`Database.CopyObjects`を用いた、図面間転送の決定版を伝授する。
—
なぜCopyObjectsなのか:メモリと安定性の物理学
`CopyObjects`は、単なるコピーコマンドではない。AutoCADのデータベース・エンジンが提供する、「オブジェクトの所有権を別データベースへ移行する」ための低レベルAPIである。
- クリップボード不要: Windowsのクリップボード汚染を回避し、バックグラウンドで完結する。
- アトミックな操作: 大量オブジェクトを一括で処理でき、トランザクションの整合性を保ちやすい。
- 名前衝突の制御: `IdMapping`を利用することで、ブロック定義や画層、線種の名前衝突時に自動でサフィックスを付与するか、既存の定義を継承するかを厳密に制御できる。
—
実装の核心:CopyObjectsによる図面間転送
以下のコードは、アクティブ図面からターゲット図面へ、選択したオブジェクトを直接転送するプロフェッショナル・実装テンプレートだ。
Option Explicit
‘ 図面間転送の最速解
Public Sub ExportObjectsToDrawing(ByVal targetDoc As AcadDocument, ByVal objectsToCopy() As AcadEntity)
Dim sourceDb As AcadDatabase
Dim targetDb As AcadDatabase
Dim idMap As New AcadIdPair
Dim objCollection() As AcadObject
Dim i As Long
‘ 1. オブジェクト配列の型変換(AcadEntity -> AcadObject)
ReDim objCollection(LBound(objectsToCopy) To UBound(objectsToCopy))
For i = LBound(objectsToCopy) To UBound(objectsToCopy)
Set objCollection(i) = objectsToCopy(i)
Next i
‘ 2. データベースの取得
Set sourceDb = ThisDrawing.Database
Set targetDb = targetDoc.Database
‘ 3. CopyObjects実行
‘ 第4引数にNothingを渡すと、オブジェクトは所有者を持たない状態で生成される
‘ その後、targetDb.ModelSpaceへAppendする必要がある場合が多い
sourceDb.CopyObjects objCollection, targetDb.ModelSpace, idMap
‘ メモリ最適化:明示的な解放
‘ VBAは参照カウント方式だが、大規模処理では明示的なNothing化が重要
Set sourceDb = Nothing
Set targetDb = Nothing
Set idMap = Nothing
End Sub
—
シニアエンジニアが意識すべき「3つの制約」
この手法を本番環境で運用する場合、以下の技術的制約を無視してはならない。
1. 依存関係の解決(Deep Cloning)
`CopyObjects`は指定したオブジェクトのみをコピーする。もしコピー対象が「外部参照」や「複雑なブロック」を含む場合、依存する辞書データ(Dictionary)や名前付きオブジェクトが不足し、転送先で図面が破損(またはエラー)する。
- 解決策: 依存オブジェクトもコレクションに含めるか、`WBlock`メソッドによる図面単位の切り出しを検討せよ。
2. IdMappingの活用
`CopyObjects`の第3引数である`IdMapping`を精査することで、コピーされたオブジェクトの「転送先での新しいObject ID」を追跡できる。
- 極意: これを使えば、コピー直後に属性ブロックの値を書き換えたり、画層を動的に変更するなどの後処理が、確実に行える。
3. レガシー環境でのメモリリーク
VBA(COM)環境では、`AcadObject`の参照が保持され続けるとガベージコレクションが正しく働かないことがある。
- 運用上の鉄則: ループ内でオブジェクトを生成・操作する場合は、必ず `Set obj = Nothing` を徹底すること。特に図面をまたぐ処理では、`targetDoc`のオブジェクトモデルへの参照をスコープアウトさせるタイミングを厳密に制御せよ。
—
アーキテクトからの提言:次のステップへ
もし君が扱っている図面が数万要素を超えるなら、VBAの限界を認め、ObjectARX(C++)または.NET APIへ移行する準備をすべきだ。しかし、VBAであっても`CopyObjects`の特性を理解していれば、クリップボード経由の低俗なスクリプトとは一線を画す、圧倒的な安定性を誇るツールを構築できる。
AutoCADは「描画ツール」ではない。「データベース管理システム」である。
この視点を持った時、君の自動化コードは、ただの「作業補助」から、真の「エンジニアリング・インフラ」へと昇華するはずだ。
健闘を祈る。
