AutoCAD VBAの深淵:寸法スタイル一括置換に見る「真のオブジェクト管理」
AutoCAD VBAは、単なるスクリプトの寄せ集めではない。これは、AutoCADという巨大なCADエンジンの心臓部を直接操作する特権的コードである。
多くの開発者は、`For Each`ループでオブジェクトを回し、力技でプロパティを書き換えて満足する。しかし、システムが数万要素を持つ図面や、ネットワーク越しに共有される巨大なプロジェクトを扱うとき、その「素人仕事」はメモリリークとパフォーマンス低下という形で必ず牙を剥く。
本稿では、寸法スタイルの一括変更という極めて実務的なテーマを通じ、メモリ管理、スタックの安全性、そしてエンジニアとしての「作法」を伝授する。
—
1. 原理:なぜ「単純なループ」が危険なのか
AutoCADのオブジェクトモデルにおいて、`AcadDimension`は極めて重い。特に多くのオーバーライドや拡張データ(XData)を保持している場合、不用意な参照はオブジェクトの断片化を招く。
我々が目指すべきは、「オブジェクトへのアクセスを最小限にし、COMインターフェースを確実に解放する」ことだ。VBAはガベージコレクションを持たない。お前たちが明示的に解放しなければ、AutoCADはメモリを食い潰し、いずれ無言でクラッシュする。
—
2. 実装:堅牢なるスタイル置換のアーキテクチャ
単にスタイル名を変えるだけではない。ターゲットとなるスタイルが図面内に存在するか、あるいは別のファイルからインポートする必要があるかという「メタデータの整合性」を担保せねばならない。
以下のコードは、単なる置換ではなく、エラーハンドリングとオブジェクト参照の最適化を考慮した実務レベルの実装である。
Option Explicit
‘ 伝説的な堅牢性を備えたスタイル置換ルーチン
Public Sub UpdateDimensionStyles(ByVal targetStyleName As String)
Dim doc As AcadDocument
Dim ss As AcadSelectionSet
Dim ent As AcadEntity
Dim dimObj As AcadDimension
Dim fType(0) As Integer
Dim fData(0) As Variant
Set doc = ThisDrawing
‘ 1. セレクションセットの動的生成(メモリリークを避けるためのクリーンアップが必要)
On Error Resume Next
Set ss = doc.SelectionSets.Add(“DimSet”)
If Err.Number <> 0 Then
Set ss = doc.SelectionSets.Item(“DimSet”)
ss.Clear
End If
On Error GoTo 0
‘ 2. フィルタ設定:寸法オブジェクトのみを抽出
fType(0) = 0: fData(0) = “DIMENSION”
ss.Select acSelectionSetAll, , , fType, fData
‘ 3. トランザクション的処理(画面更新を停止してパフォーマンスを最大化)
doc.Utility.Prompt “処理を開始します…”
For Each ent In ss
If TypeOf ent Is AcadDimension Then
Set dimObj = ent
‘ スタイル名の変更を実行
‘ 存在しないスタイルを適用すると例外が発生するため、必ず事前チェックすること
If StyleExists(doc, targetStyleName) Then
dimObj.StyleName = targetStyleName
dimObj.Update
End If
End If
Next ent
‘ 4. 後処理:オブジェクトの明示的解放(重要)
ss.Delete
Set ss = Nothing
Set doc = Nothing
doc.Utility.Prompt “全ての寸法スタイルを更新しました。”
End Sub
‘ 指定スタイルが図面内に存在するかを判定する軽量ヘルパー
Private Function StyleExists(doc As AcadDocument, styleName As String) As Boolean
Dim dimStyle As AcadDimStyle
On Error Resume Next
Set dimStyle = doc.DimStyles.Item(styleName)
StyleExists = Not (dimStyle Is Nothing)
Set dimStyle = Nothing
End Function
—
3. シニアエンジニアが意識すべき「隠れたコスト」
メモリの断片化とCOM解放
VBAの`Set obj = Nothing`は、単なる作法ではない。AutoCADのCOMサーバーに対し、「このインターフェースはもう不要だ」と明示的に通知する信号だ。特に`SelectionSets`は、削除せずに残すとAutoCADのセッションが終了するまでメモリに残り続ける。必ず `ss.Delete` を実行せよ。
Windows APIによる「思考停止」の回避
もしこの処理が数百万要素に及ぶ場合、VBAのネイティブループでは限界が来る。その時こそ、`ObjectARX`や`.NET API`への移行を検討するべきだ。VBAはあくまで「Glue(接着剤)」であり、重い計算処理を担うべきではない。しかし、どうしてもVBAで完結させる必要があるなら、`DoEvents`をループに挟み、GUIが「フリーズしている」とWindowsに誤判定されないよう配慮するのも、システム管理者としての最低限の責務である。
大規模環境での保守性
実務では「スタイル名が重複している」「図面がロックされている」といった例外は日常茶飯事だ。本コードでは`On Error Resume Next`を最小範囲で使用しているが、本番環境ではエラーログをファイル出力するモジュールを別途用意し、どの図面で失敗したかを追跡できるようにしておくのが、伝説級のアーキテクトが辿り着く「静かな運用」である。
—
結びに代えて
コードを書くことは、誰にでもできる。しかし、そのコードが「数年後の誰かの環境で、何万回実行されても壊れない」ように設計することは、選ばれた者にしかできない。
AutoCAD VBAはレガシーと言われることもある。だが、オブジェクトモデルの本質を理解したエンジニアの手にかかれば、それは今なお最強の自動化ツールとなり得る。
次回の記事では、`AcadEntity`のXDataを直接操作し、図面内の情報をデータベースとリアルタイム同期する手法について掘り下げるとしよう。
現場からは以上だ。妥協なき実装を期待する。
