AutoCAD VBAを掌握する極限の知見:PickFirstプロパティによる事前選択オブジェクトの完全制御
AutoCAD VBAの内部アーキテクチャの深層に踏み込むとき、多くの開発者が直面する壁のひとりが「選択セット(SelectionSets)」の挙動、特に「コマンド実行前にユーザーが画面上で何を選択していたか(事前選択:PickFirst)」のハンドリングである。
標準のAutoCADコマンドは、オブジェクトを先に選んでからコマンドを発動する(名詞-動詞形式:Noun-Verb)ことも、コマンドを起動してからオブジェクトを選ぶ(動詞-名詞形式:Verb-Noun)こともシームレスに処理する。しかし、素朴に記述したVBAマクロは、このプリミティブなコンテキストを無視しがちであり、ユーザーの操作感を著しく損なう原因となる。
本稿では、`AcadApplication.Preferences.Selection.PickFirst` を軸に、事前選択されたオブジェクト群のライフサイクルを完全に掌握し、プロフェッショナルなアドオンに匹敵する操作性を実現するための極限の知見を公開する。
—
1. PickFirstアーキテクチャの深層とVBAのコンテキスト乖離
AutoCADの内部データベースにおいて、現在選択されているオブジェクト群は「PICKFIRST」というシステム変数、およびセレクションセットの特殊なインスタンスとして管理されている。
VBAからこの状態にアクセスする場合、以下の2つのアプローチが存在する。
1. グローバル環境設定の制御 (`AcadPreferencesSelection.PickFirst`)
アプリケーションレベルで「事前選択機能そのものを有効/無効」にする設定。
2. アクティブ選択セットの強制的取得 (`AcadDocument.PickFirstSelectionSet`)
VBAの実行開始時点で、すでにユーザーによって選択状態にあるエンティティ群をプログラム内にキャプチャする仕組み。
この2つを混同すると、マクロ実行時に「意図せず選択がクリアされてしまう」「既存の選択状態とプログラム側の処理が競合してエラー(eInvalidOpen等)を引き起こす」といった、レガシー環境特有の深刻な不具合に直結する。
—
2. 実装パターン:事前選択オブジェクトの安全な捕獲と制御
シニアエンジニアとして担保すべき要件は明確である。
- ユーザーの利便性: マクロ実行前に選択されていた図形があれば、それを自動的に処理対象とする。
- フォールバック: 事前選択がゼロの場合は、通常通りユーザーにプロンプトを出して選択を促す。
- 状態のクリーンアップ: VBA処理終了後、AutoCADの選択状態やシステム変数を汚染しない。
以下のコードは、これらの要件を極限まで最適化した実用的なモジュールである。
Option Explicit
” —————————————————————-
” @Title: PickFirst最適化処理サンプル
” @Description: 事前選択された図形を安全に取得し、適切なライフサイクル管理の元で処理する
” —————————————————————-
Public Sub ProcessWithPickFirstOptimization()
Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Dim ssPickFirst As AcadSelectionSet
Dim ssTarget As AcadSelectionSet
Dim ent As AcadEntity
‘ アプリケーションおよびドキュメントの参照を取得
Set acadApp = ThisDrawing.Application
Set acadDoc = ThisDrawing.ActiveDocument
On Error GoTo ErrorHandler
‘ 1. アプリケーションレベルのPickFirstが有効か確認(必要に応じて強制設定も可)
If acadApp.Preferences.Selection.PickFirst = False Then
‘ 業務要件によってはここでTrueに強制変更する設計もアリ
‘ acadApp.Preferences.Selection.PickFirst = True
End If
‘ 2. ピックファースト用セレクションセットの安全なインスタンス化
‘ 既存の同名セットが存在する場合のエラーを防ぐため、事前に完全消去する
Call PurgeSelectionSet(acadDoc, “VBA_PickFirst_Buffer”)
Set ssPickFirst = acadDoc.SelectionSets.Add(“VBA_PickFirst_Buffer”)
‘ 3. 現在アクティブな事前選択(PickFirst)を取得
ssPickFirst.Get來自PickFirstSelectionSet
If ssPickFirst.Count > 0 Then
‘ — ケースA: 事前選択が存在する場合 (Noun-Verb) —
MsgBox “事前選択されたオブジェクト数: ” & ssPickFirst.Count, vbInformation, “PickFirst制御”
‘ ここで事前選択されたオブジェクト群に対する一括処理を実行
For Each ent In ssPickFirst
‘ 例:レイヤを変更する、特定のプロパティを書き換えるなど
‘ Call ProcessEntity(ent)
Next ent
‘ 処理完了後、AutoCAD側の過剰なハイライト状態や選択状態をクリア
‘ (標準コマンドの挙動に合わせるため、必要に応じて選択を解除する)
ssPickFirst.Clear
Else
‘ — ケースB: 事前選択が存在しない場合 (Verb-Noun) —
MsgBox “事前選択はありません。手動で選択を促します。”, vbInformation, “PickFirst制御”
Call PurgeSelectionSet(acadDoc, “VBA_Manual_Buffer”)
Set ssTarget = acadDoc.SelectionSets.Add(“VBA_Manual_Buffer”)
‘ ユーザーに対象選択を要求
ssTarget.SelectOnScreen
If ssTarget.Count > 0 Then
For Each ent In ssTarget
‘ 手動選択されたオブジェクトの処理
Next ent
End If
‘ 手動選択セットの開放
ssTarget.Delete
End If
CleanUp:
‘ 4. メモリリーク防止:オブジェクト参照の完全解放
On Error Resume Next
If Not ssPickFirst Is Nothing Then ssPickFirst.Delete
Set ssPickFirst = Nothing
Set ssTarget = Nothing
Set acadDoc = Nothing
Set acadApp = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “System Error”
Resume CleanUp
End Sub
” —————————————————————-
” 補助プロシージャ: 既存のセレクションセット名が競合しないようにパージする
” —————————————————————-
Private Sub PurgeSelectionSet(ByRef doc As AcadDocument, ByVal ssName As String)
Dim sSets As AcadSelectionSets
Dim i As Long
Set sSets = doc.SelectionSets
For i = sSets.Count0 To 1 Step -1
If sSets(i).Name = ssName Then
sSets(i).Delete
Exit For
End If
Next i
End Sub
—
3. チーフアーキテクトが警鐘を鳴らす「メモリ管理とCOMの罠」
VBA環境において、`AcadSelectionSet` の管理を怠ることは、AutoCAD自体のプロセス不安定化(クラッシュやメモリリーク)を意味する。特にCOMインターフェースを介したAutoCADのオブジェクトモデルは、GC(ガベージコレクション)の挙動がVBA独自の実装に依存しているため、以下の鉄則を遵守しなければならない。
セレクションセットの永続化と名前衝突の回避
AutoCADの図面データベース内において、`SelectionSets` コレクションに登録された名前は、明示的に `.Delete` メソッドを呼び出さない限り、ドキュメントが閉じられるまでメモリ上に残存し続ける。
コード内で動的に生成するセレクションセットには一意のプレフィックスを付与し、処理の前後(特にエラー発生時も含めて)で確実に `Delete` を実行するイディオムが不可欠である。上記のサンプルコードで実装している `PurgeSelectionSet` は、レガシーな実務環境で最も頻発する「セレクションセット重複エラー (Err.Number: 457 等)」を根絶するための防衛的プログラミングの極みである。
オブジェクトの明示的解放 (`Nothing` 代入)
VBAのスコープを抜ける際、`AcadEntity` や `AcadSelectionSet` などのCOMラッパーオブジェクト変数に対し、明示的に `Set xxx = Nothing` を行わない場合、背後にあるARX(AutoCAD Runtime Extension)のオブジェクト参照カウントが適切にデクリメントされず、図面を開閉するたびに微小なメモリリークが蓄積していく。長時間稼働する社内CADインフラにおいては致命傷となり得るため、クリーンアップ処理の徹底は義務である。
—
4. まとめ:システム間連携と次世代への布石
`AcadApplication.Preferences.Selection.PickFirst` とセレクションセットの高度な制御は、単なるコードの効率化に留まらない。外部のデータベースやERPシステム、BIM/CIMプラットフォームと連携する際、「ユーザーが今、画面のどこにフォーカスし、何を選択しているか」というコンテキストをミリ秒単位で正確に把握・制御できるかどうかが、プロフェッショナルツールと「おもちゃのマクロ」を分かつ分水嶺となる。
レガシーなVBA環境であっても、アーキテクチャの本質を理解し、メモリライフサイクルを完全に支配下におくことで、最新の.NET APIに引けを取らない堅牢性と高速性を発揮させることが可能である。現場の制約に屈することなく、極限まで最適化されたコードベースを構築し続けてほしい。
