【実務・中級編】【実務中級】AcadDocument.SelectionSets.Add時の「既に存在します」エラーを回避する汎用関数化 – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見

【実務中級】AcadDocument.SelectionSets.Add時の「既に存在します」エラーを完全に封殺する堅牢な汎用設計

AutoCAD VBAによる自動化開発において、避けて通れないのが「選択セット(SelectionSet)」の操作だ。図面内の図形を効率的にフィルタリングし、一括処理するためのこの強力なオブジェクトは、実務の現場において幾度となく呼び出される。

しかし、中級者へのステップアップの過程で、誰もが一度はこの絶望的なエラーに直面する。

> 実行時エラー ‘-2145386093 (80210013)’:
> 指定された名前のオブジェクトは既に存在します。

なぜこのエラーが起きるのか、そしてプロフェッショナルはこの問題にどうアプローチすべきか。今回は、単なる気休めのエラー処理ではなく、AutoCADのオブジェクトモデルの深層を理解した上で導き出した「完璧な重複回避・汎用関数」を授けよう。

1. なぜ「既存チェックと削除」のコードが氾濫し、破綻するのか?

多くの開発者は、SelectionSetsに同名のコレクションが存在するかどうかを判定するために、以下のようなコードを書き散らす。

‘ 【アンチパターン】よく見かける冗長かつ脆弱な実装
Sub BadExample()
Dim sset As AcadSelectionSet
Dim found As Boolean
found = False

‘ コレクションを総なめして名前をチェックする(悪夢のO(N)探索)
For Each sset In ThisDrawing.SelectionSets
If sset.Name = “MyProcessSet” Then
found = True
Exit For
End If
Next sset

If found Then
ThisDrawing.SelectionSets.Item(“MyProcessSet”).Delete
End If

Set sset = ThisDrawing.SelectionSets.Add(“MyProcessSet”)
End Sub

このコードの何が問題か?
1. パフォーマンスの劣化: 図面内に無数の選択セットが残留している場合、ループによる線形探索は確実にボトルネックになる。
2. メモリリークの温床: `Delete`メソッドを叩くタイミングや、オブジェクトの解放(`Set sset = Nothing`)を怠ると、AutoCADのセッション内に幽霊のような参照が残り続け、最悪の場合クラッシュを引き起こす。
3. コードの冗長性: ツール内のあちこちにこの「存在確認&削除」のボイラープレート(定型句)が散らばり、保守性を著しく低下させる。

プロの開発者であれば、「エラーを恐れて事前に泥臭く探すな。例外をスマートにハンドリングせよ」という鉄則を思い出すべきだ。

2. 到達点:Try-Get-Create パターンによる汎用関数の構築

AutoCADのCOMインターフェースの挙動を逆手に取り、最小限のオーバヘッドで確実に目的のSelectionSetを取得・生成する関数を設計する。

以下のコードを、あなたのプロジェクトの「共通モジュール(例: `mUtils.bas`)」に配置してほしい。

Option Explicit

/

  • 指定された名前のSelectionSetを確実に取得する(存在しない場合は新規作成)
  • @param doc 対象のAcadDocument
  • @param setName 取得・作成する選択セット名
  • @return AcadSelectionSet 活性化された選択セットオブジェクト

/
Public Function GetOrCreateSelectionSet(ByVal doc As AcadDocument, ByVal setName As String) As AcadSelectionSet
Dim targetSSet As AcadSelectionSet

‘ 1. まず「削除して新規作成する」というアプローチでトラップを張る
‘ 既に存在する場合はエラーになるため、トラップ内でキャッチして削除・再作成を行う
On Error GoTo ErrorHandler

‘ 新規作成を試みる(同名が存在すれば即座にエラー-2145386093が発生)
Set targetSSet = doc.SelectionSets.Add(setName)

Exit_Routine:
On Error GoTo 0
Set GetOrCreateSelectionSet = targetSSet
Exit Function

ErrorHandler:
‘ エラー番号が「指定された名前のオブジェクトは既に存在します」であるか確認
‘ AutoCADのCOMエラー番号: -2145386093 (&H80210013)
If Err.Number = -2145386093 Then
On Error Resume Next
‘ 既存の同名セットを強制削除
Set targetSSet = doc.SelectionSets.Item(setName)
targetSSet.Delete

‘ 再度作成を試みる
Set targetSSet = doc.SelectionSets.Add(setName)
On Error GoTo 0
Resume Exit_Routine
Else
‘ その他の予期せぬエラーは上位へスロー
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “API Error”
Resume Exit_Routine
End If
End Function

3. この設計が「実務レベル」である理由

① エラーを「例外」として正しく扱う

事前にループで名前を探すコストを支払う代わりに、「Addメソッドを直撃し、ぶつかったら片付ける」というリアクティブな設計を採用している。これにより、同名が存在しない大半のケース(ノーマルパス)において、処理速度を極限まで高めている。

② AutoCADのメモリ管理とオブジェクトのライフサイクル

AutoCAD VBAにおいて、`SelectionSets.Add` は図面データベースに永続的なオブジェクト登録を行う。関数内で確実に古いインスタンスを `Delete` してから再生成することで、図面ファイル(`.dwg`)内にゴミデータ(無駄なシンボルテーブルレコード)が蓄積するのを防ぐ。
※データベース連携やマクロの連続実行において、この「ゴミを残さないクリーンな状態維持」が、ファイル肥大化やクラッシュを防ぐ最大の防壁となる。

③ 呼び出し側のコードが圧倒的に美しくなる

この関数を導入することで、実際の業務ロジックは以下のように極めてシンプルに記述できるようになる。

Sub SampleBusinessLogic()
Dim sset As AcadSelectionSet

‘ 一行で「安全に」選択セットを手に入れる
Set sset = GetOrCreateSelectionSet(ThisDrawing, “CUST_LAYER_FILTER”)

‘ — ここから実務の処理 —
Dim filterType(0) As Integer
Dim filterData(0) As Variant

filterType(0) = 8 ‘ 画層フィルター
filterData(0) = “0” ‘ “0”画層を指定

‘ 選択セットに図面からエンティティを充填
sset.Select acSelectionSetAll, , , filterType, filterData

MsgBox “「0」画層のエンティティ数: ” & sset.Count & ” 件を捕捉しました。”, vbInformation

‘ 処理が終わったらクリア(※オブジェクト自体のDeleteは関数側に任せるため、ここではClearのみで十分)
sset.Clear
Set sset = Nothing
End Sub

4. チーフアーキテクトからの最終提言

VBAによるAutoCADカスタマイズの成否は、「APIの癖をいかにハックし、破綻のないラッパーを用意できるか」に懸かっている。

今回紹介した `GetOrCreateSelectionSet` 関数は、単なるエラー回避のテクニックにとどまらない。「AutoCADのCOMオブジェクトモデルの不完全さを補い、開発者を無用な例外処理の地獄から解放する」ための実践的なアーキテクチャだ。

あなたのプロジェクトにこのパターンを組み込み、明日からの開発スピードとコードの堅牢性を劇的に向上させてほしい。妥協のないコードだけが、プロのエンジニアリングの信頼を勝ち取るのだから。

タイトルとURLをコピーしました