AutoCAD大量バッチ処理の「死の淵」を越える――破損図面を制するエラーハンドリングの極意
AutoCADのバッチ処理において、最も忌むべき存在は「図面ファイルが有効ではありません(Drawing file is not valid)」というダイアログによる処理の停止だ。深夜の全社図面棚卸しを仕掛けた翌朝、たった一つの破損ファイルによって処理が数時間前に停止していたときの絶望――。
真のエンジニアは、例外を「想定外」とは呼ばない。「発生すべき必然」として設計する。本稿では、レガシーなAutoCAD VBA環境において、いかにして無停止のバッチパイプラインを構築するか、その技術的真髄を伝授する。
—
1. 鬼門「Openメソッド」の挙動とVBAの限界
AutoCADの`Documents.Open`メソッドは、ファイルに異常があると例外をスローし、即座に制御をホスト(VBA実行環境)から引き剥がそうとする。標準的な `On Error GoTo` だけでは、ダイアログそのものがユーザー操作を要求し、無人実行を阻害する。
これを打破するには、「AutoCADのイベントループを汚染させない」ことが最優先事項となる。
極限の知見:COMオブジェクトの管理と解放
VBAは参照カウンタ方式のメモリ管理を行うが、AutoCADのオブジェクトモデルは非常に「重い」。ループ内でドキュメントを開閉する際、`ThisDrawing`への参照を残したまま放置すると、メモリリークだけでなく、次のファイルを開く際にプロセスの不整合(ゾンビオブジェクト)を引き起こす。
—
2. 破損ファイルを排除する堅牢なエラーハンドラ実装
以下に、実務で検証済みの「バッチ処理継続用スケルトン」を示す。
‘ バッチ処理のメインループ
Public Sub BatchProcessDrawings(fileList As Collection)
Dim doc As AcadDocument
Dim filePath As Variant
Dim logFile As Integer
logFile = FreeFile
Open “C:\Logs\ErrorLog.txt” For Append As #logFile
For Each filePath In fileList
On Error Resume Next ‘ エラーをトラップするために一時的に無効化
‘ ドキュメントを開く
Set doc = Application.Documents.Open(filePath, True) ‘ ReadOnlyで開くのが鉄則
If Err.Number <> 0 Then
‘ 【重要】エラー発生時は即座にログを吐き出し、次のループへ
Print #logFile, “Failed: ” & filePath & ” | Error: ” & Err.Description
Err.Clear
Else
‘ 正常な場合のみ処理を実行
On Error GoTo 0
Call ProcessIndividualDrawing(doc)
‘ 【極意】必ず明示的にCloseし、参照をNothingにする
doc.Close SaveChanges:=False
Set doc = Nothing
‘ メモリの強制解放を促す(DoEventsでイベントループを処理)
DoEvents
End If
Next filePath
Close #logFile
End Sub
—
3. レガシー環境を生き抜くための「Windows API」活用
VBAの標準機能では、稀にAutoCAD内部のフリーズを検知できないことがある。その際、Windows APIを用いてプロセス監視を行うのがシニアレベルの最適解だ。
隠れたダイアログを強制破棄する
もしシステム設定が不適切で「破損ファイル警告ダイアログ」が出てしまった場合、`FindWindow` APIを使用して当該ウィンドウを探索し、`PostMessage`で`WM_CLOSE`を送り込むことで、プログラムを強制的に進行させる手法がある。
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 LongPtr
End If
‘ ダイアログが出た瞬間に消去する簡易ロジック
‘ 必要に応じてタイマー処理(SetTimer)と組み合わせること
Private Sub KillDialog()
Dim hwnd As LongPtr
hwnd = FindWindow(vbNullString, “AutoCAD”) ‘ ダイアログタイトルに合わせる
If hwnd <> 0 Then
PostMessage hwnd, &H10, 0, 0 ‘ WM_CLOSE
End If
End Sub
—
4. 最後に:アーキテクトからの提言
この実装における最大のポイントは、「コードの潔癖さ」である。
1. ReadOnlyの徹底: バッチ処理で元の図面を破壊するリスクを排除せよ。
2. ログの構造化: 破損ファイルリストはCSV形式で書き出すべきだ。後ほど、そのリストを元に「修復コマンド(RECOVER)」を自動実行する二次処理パイプラインへ回すためである。
3. リソースの枯渇: 長時間のバッチ処理では、AutoCADプロセスのメモリ使用量が肥大化する。処理件数が100を超える場合は、バッチを分割し、シェルからAutoCADを再起動させるラッパープログラムを外側に置くのが、真の安定運用である。
VBAはレガシーと言われるが、その挙動を完全に掌握した者の手にかかれば、現代のスクリプト言語よりも遥かに深く、AutoCADの根幹に干渉できる。
「止まらないシステム」を作るのは魔法ではない。それは、エラーを「予見」し、その発生を「統計」に取り、何よりも「オブジェクトの寿命」をエンジニア自身が管理する、執念の積み重ねに他ならない。
健闘を祈る。
