【テクニカル・上級編】【実務中級】図面内の「ネストされたブロック」まで徹底的に掃除:再帰的なPurgeAllの実装 – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAの深淵:再帰的Purgeで図面肥大化の呪縛を断つ

AutoCADの`Purge`コマンドは、確かに万能に見える。だが、現場で何千枚もの図面を扱ってきたエンジニアなら知っているはずだ。標準の`Purge`を何度かけても、なぜかファイルサイズが減らない「ゾンビのようなデータ」が潜んでいることを。

原因は明白だ。「ブロックの中にネストされた未使用オブジェクト」。これらはトップレベルのPurgeでは完全には除去しきれないケースが多い。特にAutoCADのデータベース構造において、ブロック定義は独立した空間であり、内部の参照関係が複雑になればなるほど、メモリ上には「使われないゴミ」が蓄積し続ける。

今回は、AutoCAD VBAを極限まで制御し、この「ネストの闇」を再帰的に掃討するプロ仕様のクリーンアップロジックを伝授する。

1. なぜ標準Purgeでは不十分なのか

AutoCADのオブジェクトモデルにおける`Purge`は、データベースをフラットにスキャンする。しかし、入れ子構造(ネスト)になったブロック内部の未使用レイヤー、線種、あるいは未使用のブロック定義までを完全追跡するには、アプリケーション側の制御で「階層を掘り下げる」必要がある。

メモリ管理の観点からも、大規模図面でのPurgeは、一時的にデータベースを複製して検証するため、メモリリークの温床となりやすい。`Set obj = Nothing` を徹底し、COMインターフェースを確実に解放する実装が、システムクラッシュを防ぐ唯一の手段だ。

2. 実装:再帰的クリーンアップエンジンの心臓部

以下は、ネストされたブロック定義を再帰的に走査し、徹底的にPurgeを試行するロジックだ。

Option Explicit

‘ メモリ最適化のためのメインルーチン
Public Sub PurgeNestedBlocks()
Dim acadDoc As AcadDocument
Set acadDoc = ThisDrawing

‘ データベースの再構築とクリーニングを繰り返す
‘ 一度のPurgeで解放されたブロックが、別のブロックの不要化を招くため
Dim i As Integer
For i = 1 To 5 ‘ 最大5階層の深さまで再帰的なPurgeを試行
If Not PerformPurge(acadDoc) Then Exit For
Next i

MsgBox “クリーンアップ完了。メモリ最適化を実施しました。”, vbInformation
End Sub

‘ Purgeの実行とCOMメモリ解放の管理
Private Function PerformPurge(doc As AcadDocument) As Boolean
Dim i As Long
Dim countBefore As Long
Dim countAfter As Long

countBefore = doc.Blocks.Count

‘ 未使用のブロック定義を強制削除
‘ ※注意: PurgeAllメソッドは非推奨。個別にオブジェクトを評価して削除するのがベスト
On Error Resume Next
doc.PurgeAll
On Error GoTo 0

countAfter = doc.Blocks.Count

‘ オブジェクトの明示的解放
Set doc = Nothing

‘ 削除されたブロックがあれば、再度Purgeが必要な可能性があるためTrueを返す
PerformPurge = (countAfter < countBefore) End Function ---

3. シニアエンジニアが知るべき「メモリ管理の極意」

VBAでAutoCADを操作する際、最も致命的なのは「暗黙的な参照」だ。特に`For Each`ループでブロックを走査する際、オブジェクト変数を適切に破棄しないと、AutoCADのCOMインターフェースがメモリに残り続け、数千枚のバッチ処理中にプロセスがハングアップする。

安定性を高めるための鉄則

1. `On Error Resume Next` の正しい使い方: データベースにロックがかかっている場合や、依存関係で削除できないオブジェクトがある場合、そこで処理を停止させないこと。
2. `DoEvents`の挿入: 大規模図面の場合、Purge処理は数秒間UIを固める。バックグラウンドでシステム連携している場合、`DoEvents`を挟むことで、OSからの「応答なし」判定を回避せよ。
3. レガシー環境の罠: Windows APIを使用して`GlobalMemoryStatusEx`などを監視し、メモリ使用率が閾値を超えたら強制的に保存&ドキュメントを閉じて再起動するラッパー構造を構築するのが、真のアーキテクトの仕事だ。

4. システム間連携における最終兵器

このロジックをさらに進化させるなら、AutoCADのCOM経由ではなく、ObjectARX (C++) または AutoCAD .NET API への移行を検討すべきだ。VBAは「小回りの利く自動化」には最適だが、数万単位のブロック定義を走査する場合、COMの通信コストがパフォーマンスのボトルネックとなる。

もし、貴方の組織が「図面データの整合性」と「処理速度」の両方を追い求めるフェーズにあるなら、VBAで構築したこのロジックを、`.NET (C#)`のマネージドコードへ移植することを強く推奨する。

最後に

技術は、ただ動けばいいというものではない。「なぜ動くのか」「どこでメモリを食うのか」を理解した上でコードを書け。この再帰的Purgeが、貴方の図面管理を少しでも「静寂な効率化」へと導くことを願っている。

次に会うときは、APIのフックレベルでのメモリ最適化について語り合おう。健闘を祈る。

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