AutoCAD VBAを掌握する極限の知見:`AcadUtility`が生死を分ける。対話型インターフェースとエラーハンドリングの神髄
自動化の限界を突破したいと願うすべてのシニアエンジニア、そして現場の泥臭い要求をVBAでねじ伏せてきたシステム管理者たちへ。
世に溢れるAutoCAD VBAの入門書は、決まって静的な図形描画のコードから始まる。座標を直値で打ち込み、あらかじめ分かっているハンドル名でオブジェクトを操作する――そのような「お遊戯」のコードは、実際の設計現場では何の役にも立たない。
現場が求めるのは、「ユーザーの意図を正確に汲み取り、ダイナミックに対話するシステム」である。
今回は、`AcadDocument.Utility` オブジェクトに焦点を当てる。`GetPoint` や `GetEntity` といった対話型メソッドの真の挙動、そして実務者を長年悩ませてきた「あの悪名高いエラー」を完全に無力化する極限の知見を授けよう。
—
1. `AcadUtility` とは何か? オブジェクトモデルの裏側
多くの開発者は、`Utility` を単なる「おまけの便利ツール群」と勘違いしている。しかし、COMのアーキテクチャ的観点から見れば、`Utility` は AutoCADのコアエンジン(Arx)とVBAのランタイムを繋ぐ唯一無二の同期インターフェース である。
図面ウィンドウへのマウスポインタの投影、スナップ計算、選択セットの構築。これらはすべて重いC++の内部処理を伴う。VBAからこれを叩く際、メモリのライフサイクルやコンテキストのスイッチングを意識していなければ、メモリリークや、最悪の場合のAutoCAD本体のクラッシュを引き起こす。
特に `Utility` オブジェクトは、親である `AcadDocument` がアクティブでなければ正しく機能しない。バックグラウンド処理や、複数ドキュメントをまたぐコンテキスト切り替え時には細心の注意が必要だ。
—
2. ユーザー対話の二大巨頭:`GetPoint` と `GetEntity`
対話型インターフェースの要となるのが `GetPoint`(座標取得)と `GetEntity`(図形選択)である。これらは単に値を返すだけの関数ではない。実行した瞬間、AutoCADのコマンドラインとグラフィックス領域の制御権をユーザーに一時返還する「モーダルな入力待ち状態」を作り出す。
実務で使える堅牢なラッパーの実装
まずは、実務レベルのコードを見てほしい。エラーハンドリングとプロンプトの制御を完璧に盛り込んだ実践的な実装だ。
Option Explicit
” —————————————————————–
” ユーザー対話型インターフェースの模範実装
” —————————————————————–
Public Sub ExecuteInteractiveProcess()
Dim acadDoc As AcadDocument
Set acadDoc = ThisDrawing
On Error GoTo ErrorHandler
‘ 1. 基準点の取得 (GetPoint)
Dim basePoint As Variant
‘ 第1引数にプロンプト、第2引数に基準点(ラバーバンド用)を指定可能
basePoint = acadDoc.Utility.GetPoint(, vbCrLf & “基準となる挿入点を指定してください: “)
MsgBox “取得した座標: X=” & basePoint(0) & “, Y=” & basePoint(1) & “, Z=” & basePoint(2), vbInformation, “座標取得成功”
‘ 2. 対象エンティティの取得 (GetEntity)
Dim selectedObj As AcadEntity
Dim pickPoint As Variant
‘ GetEntityは「オブジェクトへの参照」と「実際にクリックされた座標」を同時に返す
acadDoc.Utility.GetEntity selectedObj, pickPoint, vbCrLf & “処理対象の図形を選択してください: ”
‘ 選択されたオブジェクトの型を安全に判定
MsgBox “選択された図形タイプ: ” & selectedObj.ObjectName & vbCrLf & _
“クリック座標: X=” & pickPoint(0) & “, Y=” & pickPoint(1), vbInformation, “エンティティ取得成功”
Exit Sub
ErrorHandler:
‘ ここに制御が移る条件の大部分は「ユーザーによるキャンセル」である
If IsUserCancel(Err.Number) Then
MsgBox “ユーザーによって操作がキャンセルされました。”, vbExclamation, “中断”
Else
MsgBox “予期せぬエラーが発生しました: ” & Err.Description & ” (Code: ” & Err.Number & “)”, vbCritical, “致命的エラー”
End If
End Sub
—
3. 悪名高いエラー `-2147352567` の完全無力化
シニアエンジニアなら誰もが一度はこのエラー踏み、夜中に冷汗をかいたことがあるはずだ。
> エラー `-2147352567 (80020009)`
> Automation エラーです。 例外が発生しました。
ユーザーが `GetPoint` や `GetEntity` の実行中に `[Esc]` キーを押したり、右クリックでキャンセルしたりした瞬間、AutoCAD VBAはこの長大な負の整数エラーを容赦なく投げてよこす。
これを単に `On Error Resume Next` で逃げるのは、アマチュアのやることだ。予期せぬメモリ例外や他の致命的なエラーまで握りつぶしてしまうことになる。
厳密なエラーコード判定ロジック
エラー `-2147352567`(16進数表記では `&H80020009`、Automationの例外エラー)は、Utilityメソッドにおける「キャンセル」のシグナルとして返される。これを明確に捕捉するファンクションを常備せよ。
” —————————————————————–
” ユーザーによるキャンセル(Escキー等)を厳密に判定する関数
” —————————————————————–
Private Function IsUserCancel(ByVal ErrNumber As Long) As Boolean
Select Case ErrNumber
Case -2147352567 ‘ 80020009: Utilityメソッドでの標準的なキャンセル
IsUserCancel = True
Case 52 ‘ Bad file name or number (稀に発生する環境依存の割り込み)
IsUserCancel = True
Case Else
IsUserCancel = False
End Select
End Function
この判定を入れることで、「ユーザーが意図して中断したケース」と「プログラムやAutoCAD環境に異常が発生したケース」を完全に分離し、堅牢なシステムを構築できる。
—
4. プロフェッショナルのためのメモリ最適化とライフサイクル管理
VBAはガベージコレクションを持たない言語である。特にAutoCADのCOMラッパーオブジェクト (`AcadEntity`, `AcadSelectionSet` など) は、背後でC++の重厚なポインターを保持している。
`GetEntity` や選択セットの操作で取得したオブジェクトは、使い終わったら明示的に `Nothing` を代入してメモリを解放する ことが、長期稼働するマクロの絶対条件である。
‘ 処理終了時のメモリ解放の作法
If Not selectedObj Is Nothing Then
‘ オブジェクト変数の参照を明示的に断つ
Set selectedObj = Nothing
End If
これを怠ると、巨大な図面を相手に何度もスクリプトを実行した際にVBAランタイムのメモリフットプリントが肥大化し、最悪の場合ドキュメントごとのクラッシュ(致命的なエラーによる強制終了)を引き起こす。シニアたるもの、メモリのあと片付けまで美しくコードを書くべきだ。
—
総括
`AcadDocument.Utility` を制する者は、AutoCAD VBAのインタラクティブ性を制する。
単に図面を描画するだけのスクリプトから脱却し、オペレーターと対話しながらリアルタイムに図面を検証・生成するシステムへとステップアップするためには、今回解説した「正確なオブジェクトの捕捉」と「神出鬼没のキャンセルエラーの制御」が不可欠となる。
レガシーと言われようとも、正しく設計されたVBAのコードは、現場において最強の自動化兵器たり得ると知れ。
