AutoCADバッチ処理の深淵:数千枚の図面を「壊さず」完遂させるアーキテクチャ
AutoCADのバッチ処理において、初心者は「ループでファイルを開いて閉じる」だけのコードを書き、そして必ず「メモリリーク」と「ゾンビプロセス」の海に溺れる。
数千枚規模の図面を一括処理する際、最も重要なのは「AutoCADという重厚なCOMオブジェクトのライフサイクルをいかに完璧に制御するか」だ。本稿では、実務レベルで「落ちない」ための堅牢なバッチ処理設計を伝授する。
—
なぜ、安易なループ処理は「死」を招くのか
多くのコードが陥る罠は、`Documents.Open`を繰り返した後に、`Document.Close`を呼び出すだけで満足してしまうことだ。しかし、AutoCADのCOMインターフェースは非常にデリケートである。
- ゾンビプロセスの蓄積: 処理途中でエラーが発生し、`Close`が呼ばれずにメモリ上に隠れたAutoCADが残る。
- イベントの暴走: `Document`が開かれるたびに意図しないイベントハンドラが発火し、処理が停止する。
- メモリリーク: COMオブジェクトを適切に解放(`Nothing`代入)しないと、GC(ガベージコレクション)が追いつかず、後半の処理が劇的に遅くなる。
これらを解決するための「アーキテクトの作法」をコードに落とし込もう。
—
【実用コード】堅牢なバッチ処理テンプレート
このコードは、指定フォルダ内の全てのDWGを順次開き、処理を行い、確実に閉じるためのテンプレートだ。
Option Explicit
‘ メインバッチ処理関数
Public Sub BatchProcessDrawings()
Dim fso As Object
Dim folder As Object
Dim file As Object
Dim targetFolder As String
targetFolder = “C:\Projects\TargetDrawings\” ‘ 対象フォルダ
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set folder = fso.GetFolder(targetFolder)
‘ AutoCADのシステム変数を一時退避(最適化のため)
Dim oldSDI As Integer
oldSDI = ThisDrawing.GetVariable(“SDI”)
ThisDrawing.SetVariable “SDI”, 0 ‘ MDIモードで実行
For Each file In folder.Files
If LCase(fso.GetExtensionName(file.Path)) = “dwg” Then
ProcessSingleDrawing file.Path
End If
Next file
ThisDrawing.SetVariable “SDI”, oldSDI
MsgBox “全処理完了”
End Sub
‘ 個別ファイル処理の堅牢なラッパー
Private Sub ProcessSingleDrawing(filePath As String)
Dim doc As AcadDocument
‘ エラーハンドリングを強固に構築
On Error Resume Next
Set doc = Application.Documents.Open(filePath)
If Err.Number <> 0 Then
Debug.Print “Open Error: ” & filePath
Exit Sub
End If
On Error GoTo 0
‘ 実際の加工ロジックを分離
Call ExecuteMyLogic(doc)
‘ 変更を保存して閉じる
‘ 常に「保存する」か「破棄する」を明確に制御すること
doc.Close True
‘ 参照の強制破棄
Set doc = Nothing
End Sub
‘ 実際の業務ロジック
Private Sub ExecuteMyLogic(ByRef doc As AcadDocument)
‘ 例:モデル空間内の全テキストを特定フォントに変更するなど
‘ ここに重い処理を書く際も、必ずエラーハンドリングを忘れないこと
doc.Utility.Prompt “Processing: ” & doc.Name & vbCr
End Sub
—
アーキテクトの視点:3つの鉄則
1. `On Error Resume Next` の正しい使い方
バッチ処理において、1つのファイルが壊れていただけで全工程を停止させるのは非効率だ。`ProcessSingleDrawing`の中で個別にエラーをキャッチし、ログファイルに記録して「次のファイルへ進む」設計にせよ。
2. COMオブジェクトのライフサイクル管理
`Set doc = Nothing` は、VBAにおいては「気休め」に近いが、大規模処理では重要だ。特に、ループ内で生成した一時的なオブジェクト(SelectionSetsやBlocksのコレクション)は、`Delete`メソッドを明示的に呼び出すか、スコープを細かく区切ることでメモリを解放する意識を持て。
3. 外部データベースとの連携は「トランザクション」を意識せよ
もし図面情報からExcelやSQL Serverへデータを書き出すなら、「ファイルを開いた直後にDB接続し、閉じる直前に切断」してはならない。
大量の接続・切断はオーバーヘッドが大きすぎる。DB接続はメインルーチンの開始時に一度だけ確立し、全ファイル処理後に閉じる「シングルトン接続」を採用すべきだ。
—
結論:自動化は「防衛」から始まる
優れた自動化ツールとは、速いことよりも「止まらないこと」だ。
今回提示したテンプレートは、極めてシンプルだが、最も多くのエンジニアが犯す「メモリとリソースの放置」を防ぐ設計になっている。
次にあなたが取り組むべきは、このコードに「ログ出力機能」を付与し、どのファイルで何が起きたかを完璧に追跡できる環境を整えることだ。自動化の世界に「魔法」はない。あるのは、細部まで徹底的に制御された「規律」だけである。
さあ、コードを書いて、自分自身をルーチンワークの呪縛から解放してくれ。
