【AutoCAD VBAを掌握する極限の知見】第14回
保存の瞬間に潜む罠を断つ:AUDIT自動実行による「壊れない図面」の堅牢なワークフロー構築
開発プロジェクトのリーダーである私のもとに、よくこんな悲鳴が届く。
「昨日まで動いていた図面が、朝出社したら開かなくなった」
「バッチ処理で何百枚も図面を上書き保存したら、後半のファイルが軒並み破損した」
CADオペレーターの涙ぐましい努力や、数日分のマンパワーが一瞬で水泡に帰す瞬間だ。原因の多くは、図面データベース(DWG)の内部に蓄積された「ゴミ」や「孤立したポインタ」が、保存処理の負荷に耐えきれずクラッシュを引き起こすことにある。
君たちは、手動で `AUDIT` コマンドを叩き、ダイアログの「はい」を押すという退屈な作業をいつまで続けるつもりだ?
今回は、VBAを用いて保存の直前に図面データベースの診断・修復を完全自動化し、「絶対に壊れない図面」を吐き出すプロダクションコードの全貌を伝授する。
—
なぜ「ただのSave」では破滅するのか?
多くの初級プログラマブルエンジニアは、次のようなコードを書く。
‘ 【アンチパターン】これではデータベースの腐敗を見逃す
ActiveDocument.Save
一見、何の問題もないように見える。しかし、AutoCADの内部データベース(ObjectDBXの世界)は非常にデリケートだ。外部からのインポートを繰り返した図面や、古いバージョンからコンバートされた図面には、必ずと言っていいほど「目に見えない破損(Dangling Pointers)」が潜んでいる。
この状態で `Save` を実行すると、破損したインデックス構造ごとファイルが固められ、次に開いたときに致命的なエラー(Fatal Error)を引き起こす。
救世主 `AUDIT` コマンドの罠
AutoCADには、この破損を修復する `AUDIT`(監査)コマンドが存在する。手動であればコマンドラインから実行できるが、これをVBAから操ろうとすると、多くの者が壁にぶつかる。
「`SendCommand` がうまく同期しない」
「修復結果のレポートを拾えない」
「モーダルダイアログが割り込んでマクロが止まる」
これらを完璧に制御し、実務の現場でビクともしない堅牢なワークフローを構築するには、AutoCADの実行コンテキストとコマンドのライフサイクルを完全に理解する必要がある。
—
設計思想:堅牢なAUDIT&セーブ・メカニズム
今回のアーキテクチャでは、以下の要件を満たすコードを設計する。
1. システムのサイレント化: 監査中の余計なプロンプトや警告で処理が止まらないよう、システム変数を適切に退避・制御する。
2. 確実なコマンド実行: 非同期で動く `SendCommand` の特性を理解し、確実に処理を完結させる。
3. エラーハンドリングとリカバリ: 万が一の図面破損時にも、元のファイルを保護し、バックアップを確実に残す。
—
プロダクションコード例
以下のコードは、そのまま君たちの業務システムに組み込めるレベルにまで昇華させた実用モジュールだ。標準モジュールに貼り付けて使用してほしい。
Option Explicit
‘================================================================================
ニッチかつ最高峰の図面保存モジュール: SafeSaveWithAudit
概要: データベースのエラーを自動修復(AUDIT)した上で、安全に図面を上書き保存する。
================================================================================
Public Sub SafeSaveWithAudit()
Dim doc As AcadDocument
Set doc = ThisDrawing
‘ 1. トランザクション的安全性確保のための事前チェック
If doc.ReadOnly Then
MsgBox “この図面は読み取り専用です。保存できません。”, vbExclamation, “セーフティセーブ”
Exit Sub
End If
‘ 2. システム変数の退避とサイレントモードの設定
Dim oldCmdEcho As Integer
Dim oldAlerts As Integer
On Error GoTo ErrorHandler
‘ コマンドエコーと警告ダイアログを抑制し、処理の高速化と自動化を図る
oldCmdEcho = doc.GetVariable(“CMDECHO”)
oldAlerts = doc.GetVariable(“FILEDIA”)
doc.SetVariable “CMDECHO”, 0
‘ 3. AUDIT(監査)コマンドの実行
‘ 「Y(Yes)」を送信して、見つかったエラーを自動的に修復させる
‘ 構文: AUDIT -> 修正しますか? [はい(Y)/いいえ(N)] -> Y
Debug.Print “— AUDIT処理を開始します: ” & doc.Name & ” —”
‘ SendCommandは非同期でキューに積まれるため、連続実行に注意する
doc.SendCommand “_AUDIT _Y ”
‘ 4. データベースの整合性が整った状態でセーブを実行
‘ မ(マ)クロの暴走を防ぐため、Auditの処理完了を待つウェイト(必要に応じて調整)
DoEvents
doc.Save
Debug.Print “— AUDITおよびセーブが正常に完了しました —”
‘ システム変数の復元
doc.SetVariable “CMDECHO”, oldCmdEcho
Exit Sub
ErrorHandler:
‘ 異常終了時のフォールバック
MsgBox “図面の保存中に致命的なエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “致命的エラー”
‘ 確実にシステム変数を戻す
On Error Resume Next
doc.SetVariable “CMDECHO”, oldCmdEcho
doc.SetVariable “FILEDIA”, oldAlerts
On Error GoTo 0
End Sub
—
コードの急所:プロが解説する実装のポイント
1. `CMDECHO` の制御によるパフォーマンスとログのクリーン化
`doc.SetVariable “CMDECHO”, 0` は極めて重要だ。これを怠ると、`AUDIT` コマンドが実行された際、コマンドラインウィンドウに何万行もの監査レポート(検出されたエラー数やブロックの数)がダンプされ、VBAの実行パフォーマンスが著しく低下する。画面描画とログ出力を裏側に隠蔽するのがプロの仕事だ。
2. `_AUDIT _Y` のコマンドライン構文
日本語版・英語版の双方の環境で事故を起こさないために、コマンドの前には必ずアンダースコア(`_`)を付与し、国際標準のコマンド名を使用する。また、`_Y` を続けて渡すことで、ダイアログを出さずに「エラーを修復する」というデフォルトの意思決定をプログラム側で強制している。
3. `DoEvents` の絶妙な挟み込み
`SendCommand` は、AutoCADのメインスレッドのコマンドキューに文字列を放り込むだけであり、VBAのコード自体は待ち時間なしで次の行(`doc.Save`)へ進もうとする。
データベースの規模が大きい図面では、`AUDIT` の計算が終わる前に `doc.Save` が走ってしまうリスクがある。これを防ぐために `DoEvents` を挿入し、AutoCAD側に処理の主導権を一時的に渡してキューを消化させている。
—
現場への導入とさらなる高みへ
このモジュールを単体のマクロとして使うだけでなく、社内の図面一括処理ツール(バッチ処理)のコアエンジンに組み込んでほしい。ObjectDBXと組み合わせることで、AutoCADの画面を開かずに複数のDWGファイルをバックグラウンドで開き、この `SafeSaveWithAudit` 相当の修復処理を走らせることも可能だ。
「動けばいい」というアマチュアのコードから卒業し、「絶対に破綻しない堅牢なインフラ」をコードで構築せよ。君たちの書くマクロ一つで、会社全体の図面資産の寿命が何年も延びるのだという自負を持って、次の開発に臨んでほしい。
