AutoCAD自動化の深淵:数千の図面を「壊さず、止めず」処理する極限のバッチアーキテクチャ
AutoCAD VBAによるバッチ処理を単なる「マクロ」だと思っているなら、今すぐその認識を捨てろ。数千枚の図面を相手にする時、君が書いているのはプログラムではない。「崩壊寸前のリソースをいかに延命させ、完遂させるか」というサバイバルゲームだ。
今回は、AutoCADのオブジェクトモデルを掌握し、メモリリークの悪夢から解放されるための、真に堅牢なバッチ処理のアーキテクチャを伝授する。
—
1. 鬼門の「AcadDocument」ライフサイクル管理
大量の図面を扱う際、最も多くのエンジニアが躓くのは「メモリ解放」だ。`Documents.Open` で開いた図面を `Close` しても、VBAの裏では参照が残り続けることがある。これは単なるコードの書き損じではない。COMオブジェクトの参照カウントがゼロにならない限り、AutoCADのプロセスは肥大化し続け、数時間後に必ずクラッシュする。
鉄則:明示的解放とエラーハンドリングの徹底
Public Sub BatchProcessDrawings(ByVal folderPath As String)
Dim fso As Object: Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim folder As Object: Set folder = fso.GetFolder(folderPath)
Dim file As Object
Dim doc As AcadDocument
‘ 最適化: バッチ処理中は不要なUIを殺す
Application.Visible = False ‘ 隠しモードでの実行
For Each file In folder.Files
If LCase(fso.GetExtensionName(file.Name)) = “dwg” Then
On Error Resume Next ‘ 破損図面やロックファイル対策
Set doc = Application.Documents.Open(file.Path, True)
If Err.Number = 0 Then
‘ — ここにメイン処理を記述 —
ProcessDrawingContent doc
doc.Close SaveChanges:=True
End If
‘ メモリの強制回収の儀式
Set doc = Nothing
On Error GoTo 0
‘ GCがないVBAでの悪あがき:
‘ DoEventsでOSに制御を戻し、メモリのフラグメントを抑制する
DoEvents
End If
Next
Application.Visible = True
End Sub
—
2. Windows APIによる「生存確認」の真実
AutoCADのバッチ処理において、最も恐ろしいのは「ダイアログの出現による処理の停止」だ。`On Error Resume Next` だけでは太刀打ちできない。特定の図面で発生する「フォント置換ダイアログ」や「プロキシ警告」を検知し、API経由で強制的に `Enter` を送信する。これがプロの仕事だ。
外部からメッセージを叩き潰す(User32.dllの活用)
If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function PostMessage Lib “user32” Alias “PostMessageA” (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As Long
Else
‘ レガシー環境対応
Private Declare Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function PostMessage Lib “user32” Alias “PostMessageA” (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
End If
‘ 警告ウィンドウを検知して閉じるルーチンを随時コールする
Private Sub KillDialog()
Dim hwnd As LongPtr
hwnd = FindWindow(vbNullString, “AutoCAD Message”) ‘ タイトルは適宜調整
If hwnd <> 0 Then PostMessage hwnd, &H10, 0, 0 ‘ WM_CLOSEを送信
End Sub
—
3. パフォーマンスを極限まで引き出す「システム変数」の制御
処理速度を決定づけるのはコードの書き方ではない。AutoCADのエンジンがどれだけ「軽量」に動くかだ。バッチ処理の開始時に以下の変数を必ず制御せよ。
- `FILEDIA` (0): ファイル選択ダイアログを抑制。これを忘れるとバッチは確実に死ぬ。
- `PICKFIRST` (0): 事前選択を無効化し、メモリ負荷を軽減。
- `WHIPTHREAD` (3): マルチスレッド処理を有効化(再描画の高速化)。
- `HIGHLIGHT` (0): 図形選択時のハイライトをオフにするだけで、数千回繰り返すループでは劇的な速度差が生まれる。
—
4. チーフアーキテクトからの助言:VBAは「ハブ」に徹せよ
大規模なバッチ処理において、VBAだけで完結させようとするのは愚策だ。VBAはあくまで「AutoCADを操作するインターフェース」として使い、重い計算や複雑なデータ加工は外部のスクリプト(PythonやC#)に投げろ。
特に、図面内の情報を抽出してデータベース化するなら、`ObjectDBX` を利用することを強く推奨する。`AcadApplication` を経由せずに図面データを直接メモリ上に読み込むこの技術は、通常の `Open` より数倍速く、かつバックグラウンドで完結する。
結論
君たちが書くべきは、「壊れないコード」ではなく「壊れた時に何が起きたか正確にログを吐き出し、即座に次の図面へ移行するコード」だ。
今日から、すべての `Open` には最大試行回数を設定し、すべてのループには `DoEvents` を仕込み、そして何より、AutoCADという巨大で不安定なCOMオブジェクトを、まるで壊れ物を扱うように丁寧に、しかし非情に管理せよ。
これが、この過酷な現場で生き残る唯一の流儀だ。健闘を祈る。
