こんにちは!AutoCAD VBAの世界へようこそ。業務自動化の旅を一歩ずつ進めているあなたを、心から歓迎します。
「マクロの記録」を卒業し、実務で使える本格的なプログラムを書き始めると、必ずぶつかる大きな壁があります。それが「図面間でオブジェクトをコピーした際、コピー先での図形の身元(ハンドル番号)が分からなくなる」という問題です。
図面Aにある「重要部品(ハンドル番号:`A1F`)」を、図面Bへコピーしたとします。コピーされた瞬間、その図形には図面Bのルールに従って、まったく新しいハンドル番号(例:`C2B`)が自動的に割り振られます。
もし、あなたが外部のExcelシートやデータベース(Access/SQL Serverなど)で「ハンドル番号 `A1F` は、単価15,000円のセンサーである」という管理をしていた場合、コピー先の図面Bでその紐付けは完全に失われてしまいます。
「コピー先での新しいハンドル番号を、どうやって正確に追跡すればいいのだろう?」
この難題をエレガントに解決するのが、AutoCAD VBAに秘められた強力な機能`CopyObjects`メソッドと、その相棒である`IdMapping(ClonedObjects)`です。
今回は、この「図面間オブジェクトコピーにおける新旧ハンドル番号の完全追跡術」について、オブジェクトモデルの仕組みから具体的なコード、現場での落とし穴まで、優しく丁寧に解説します。ここをクリアすれば、あなたのAutoCAD VBAの実力は「初学者」から「実務中級者(プロフェッショナル)」へと一気に引き上がりますよ!
—
1. なぜハンドル番号が変わるのか?
まずは基本のおさらいです。AutoCADのすべての図形(オブジェクト)には、図面内で唯一無二の識別子である「ハンドル(Handle)」が割り当てられています。これは、図面が保存されても、次に開かれても、決して変わらない「不変のマイナンバー」です。
しかし、この不変性にはルールがあります。それは「1つの図面ファイルの中だけで一意(ユニーク)である」ということです。
そのため、オブジェクトを別の図面へコピー(ディープクローン)すると、コピー先の図面ですでに使われているハンドル番号と衝突するのを防ぐため、AutoCADはコピー先の図面用に新しいハンドル番号を再発行します。
 (イメージ:図面Aから図面Bへコピーされた瞬間、IDカードが新しく書き換わる)
この「再発行された新しいハンドル番号」をリアルタイムに、かつ正確にキャッチして「コピー元 `A1F` = コピー先 `C2B`」という変換リスト(マッピング)を作る必要があります。
—
2. 鍵を握る「IDマッピング(IdMapping)」の仕組み
AutoCAD VBAでオブジェクトを別図面へコピーする際は、`AcadDocument.Database.CopyObjects` メソッドを使用します。このメソッドの定義を見てみましょう。
‘ CopyObjectsの構文
objSourceDb.CopyObjects(ObjectsArray, Owner, [IdMap])
- `ObjectsArray`: コピーしたいオブジェクトの配列。
- `Owner`: コピー先の格納先(例:コピー先図面のモデル空間など)。
- `IdMap` (省略可能ですが、今回これが主役です!): `IdMapping`オブジェクトを受け取るための変数。
この第3引数である `IdMap` に空の変数を渡してメソッドを実行すると、AutoCADはコピー処理の裏側で「どのオブジェクト(コピー元)が、どのオブジェクト(コピー先)に変換されたか」の全記録をこの変数に書き込んで返してくれます。
この中に、新旧のオブジェクトIDがペア(`AcadIdPair`)としてギッシリ詰まっているのです。
—
3. 【実戦コード】異なる図面間でオブジェクトをコピーし、ハンドルを追跡する
それでは、実際に動くコードを見てみましょう。
このコードは、「現在アクティブな図面(コピー元)」から選択した図形を、「新しく作成した図面(コピー先)」へコピーし、新旧のハンドル番号の対応表をイミディエイトウィンドウに出力するものです。
Option Explicit
Sub CopyObjectsWithTracking()
‘ =========================================================================
‘ 目的: 図面間でオブジェクトをコピーし、コピー先で割り振られた
‘ 新しいハンドル番号を正確に追跡・特定する
‘ =========================================================================
Dim docSource As AcadDocument
Dim docTarget As AcadDocument
Set docSource = ThisDrawing ‘ 現在アクティブな図面(コピー元)
‘ 1. コピー対象のオブジェクトを選択(ここでは例として、ユーザーに画面上で選択させます)
Dim sset As AcadSelectionSet
On Error Resume Next
Set sset = docSource.SelectionSets.Item(“TempSSet”)
If Err.Number <> 0 Then
Set sset = docSource.SelectionSets.Add(“TempSSet”)
Err.Clear
End If
On Error GoTo 0
MsgBox “コピーしたい図面上のオブジェクトを選択してください。”, vbInformation, “準備”
sset.SelectOnScreen
If sset.Count = 0 Then
MsgBox “オブジェクトが選択されませんでした。処理を中断します。”, vbExclamation
sset.Delete
Exit Sub
End If
‘ 2. 選択されたオブジェクトを配列(Variant型)に格納
Dim objArray() As Object
ReDim objArray(sset.Count – 1)
Dim i As Integer
For i = 0; i < sset.Count; i++
Set objArray(i) = sset.Item(i)
Next i
' 選択セットは用が済んだら速やかに削除(メモリ解放のため)
sset.Delete
' 3. コピー先となる新しい図面を作成
Set docTarget = ThisDrawing.Application.Documents.Add
' 4. コピー先図面の「モデル空間(ModelSpace)」をコピー先(Owner)として指定
Dim objTargetMS As AcadModelSpace
Set objTargetMS = docTarget.ModelSpace
' 5. IDマッピングを受け取るための変数を宣言(ここが最大のポイント!)
Dim idMap As Variant
' 6. オブジェクトのコピーを実行
' ※CopyObjectsは「コピー元のデータベース」から実行します。
On Error GoTo Err_Copy
docSource.Database.CopyObjects objArray, objTargetMS, idMap
On Error GoTo 0
' 7. コピーされた「新旧ペア」を解析し、ハンドル番号を追跡する
Debug.Print "=== コピー完了!新旧ハンドル対応表 ==="
Dim idPair As AcadIdPair
Dim sourceObj As AcadObject
Dim targetObj As AcadObject
Dim sourceHandle As String
Dim targetHandle As String
' idMapの中身を1ペアずつ取り出して走査する
For Each idPair In idMap
' idPair.Key : コピー元のObjectID
' idPair.Value : コピー先のObjectID
' ※注意: コピー対象のオブジェクトだけでなく、レイアウトや画層などの
' 依存オブジェクトの情報も含まれる場合があるため、IsClonedプロパティで
' 「実際にコピーされた図形かどうか」を判定します。
If idPair.IsCloned Then
' コピー元のObjectIDから、元のオブジェクトを特定し、ハンドルを取得
Set sourceObj = docSource.ObjectIdToObject(idPair.Key)
sourceHandle = sourceObj.Handle
' コピー先のObjectIDから、新しいオブジェクトを特定し、新しいハンドルを取得
Set targetObj = docTarget.ObjectIdToObject(idPair.Value)
targetHandle = targetObj.Handle
' 結果をイミディエイトウィンドウに出力
Debug.Print "図形種別: " & sourceObj.ObjectName & _
" | 元ハンドル: " & sourceHandle & _
" --> 新ハンドル: ” & targetHandle
End If
Next idPair
MsgBox “コピーとハンドル追跡が完了しました!” & vbCrLf & _
“VBA画面の「イミディエイトウィンドウ」を確認してください。”, vbInformation, “成功”
Exit Sub
Err_Copy:
MsgBox “コピー中にエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
If Not sset Is Nothing Then sset.Delete
End Sub
—
4. 陥りやすい「3つの落とし穴」とプロの回避策
この一連の処理を実務で運用するにあたり、初心者が必ずと言っていいほどハマる「罠」があります。これらを事前に知っておくだけで、開発効率は劇的に向上します。
落とし穴①:`IsCloned` の判定を忘れてエラーになる
`IdMapping` の中には、あなたが明示的に選択したオブジェクト(ラインやサークルなど)以外の情報も含まれることがあります。例えば、画層(Layer)や線種(Linetype)など、コピーに伴って自動的に生成・マッピングされた「システム周辺のオブジェクト」です。
これらをすべて無理やり図形として処理しようとすると、型エラー(Type Mismatch)を起こす原因になります。
- 対策: `If idPair.IsCloned Then` を使い、「実際に今回複製(クローン)された図形オブジェクトのみ」をフィルタリングして処理してください。
落とし穴②:64bit版AutoCADにおける「ObjectID」の型問題
現在のAutoCADはほぼ100%が64bit版です。VBA内部で `ObjectID` を扱う際、かつての32bit時代の感覚で `Long` 型変数に代入しようとすると、桁溢れ(オーバーフロー)エラーを起こします。
- 対策: コード例のように、`ObjectIdToObject` メソッドに `idPair.Key`(Variant型)を直接渡すか、変数に受ける場合は `LongPtr`(または `Variant`)を使用するようにしてください。これにより、64bit環境でも安全に動作します。
落とし穴③:オブジェクトのライフサイクルとメモリ解放
図面間のコピーは非常にメモリを消費する処理です。特に数千個のオブジェクトを一度にコピーする場合、VBAのオブジェクト参照がメモリに残ったままだと、AutoCADが異常終了(クラッシュ)することがあります。
- 対策: 使用したオブジェクト変数(`sourceObj` や `targetObj` など)は、ループの最後やプロシージャの終了時に `Set sourceObj = Nothing` として明示的にメモリから解放する習慣をつけましょう。
—
5. まとめ:データ連携のプロフェッショナルへ
お疲れ様でした!
今回学んだ `CopyObjects` と `IdMapping` を使ったハンドルの追跡手法は、AutoCADと外部システム(Excel、データベース、生産管理システムなど)を有機的に結びつけるための「架け橋」となる技術です。
図面が変わっても、Excel側のデータベースと図面内の図形が「新ハンドル番号」を介してガッチリと結びついていれば、
- 「図面Aから図面Bに部品をコピーしたら、自動的に見積書の数量と金額が更新された」
- 「コピー先の図面で図形をクリックするだけで、元の設計仕様書(PDF)が瞬時に開く」
といった、極めて高度な業務自動化(DX)システムを構築することができます。
少し難しく感じたかもしれませんが、一歩一歩コードを動かしながら、イミディエイトウィンドウに表示されるハンドル番号の「変化」を目で追いかけてみてください。「なるほど、こういうことか!」と腑に落ちる瞬間がきっと訪れます。
ここをクリアすれば、あなたのAutoCAD VBAの基礎力はもう盤石です。自信を持って、次のステップへ進んでくださいね。応援しています!
