AutoCAD VBAを掌握する極限の知見:Closeメソッドにおける「SaveChanges」の設計思想
自動化エンジニアとして現場に立つ者にとって、もっとも恐ろしいのは「コードが動かないこと」ではない。「コードが、開発者の意図しない挙動(非決定的な挙動)をすること」だ。
特に、図面ファイルを扱う自動化ツールにおいて、ファイルのクローズ処理はもっともクリティカルな局面の一つである。ここで設計を誤れば、ユーザーの作業内容を勝手に上書きして破壊するか、あるいは意図しないダイアログを表示させて自動処理をストップさせ、実務における「自動化」の価値を根底から覆すことになる。
今回は、AutoCAD VBAにおける `Document.Close` メソッドの第1引数 `SaveChanges` をテーマに、プロフェッショナルが実践すべき「制御の設計思想」を伝授する。
1. 致命的な設計ミス:デフォルト値に頼るな
初心者がもっとも陥りやすい罠は、`Doc.Close` を引数なしで呼び出すことだ。
' --- 典型的な初心者レベルのコード(非推奨) ---
Sub BadExample()
Dim doc As AcadDocument
Set doc = ThisDrawing ' または Documents.Open(...)
' 何らかの処理...
doc.Close ' ← ここが地雷
End Sub
なぜこれが「地雷」なのか。`Close` メソッドの第1引数を省略した場合、AutoCADは「図面に変更があるかどうか」を判定し、変更があれば「変更を保存しますか?」というダイアログを表示する。
バッチ処理で100個の図面をループ処理している最中に、このダイアログが1つでも出た瞬間、君のプログラムは「自動化ツール」から「ただの待ちぼうけツール」へと成り下がる。自動化の定義は、人間を介在させないことにあるのだ。
2. 三つの挙動:True / False / 省略 の決定的な違い
設計者は、以下の3つの状態を完全にコントロール下におかなければならない。
| 引数の値 | 挙動 | 実務上の用途 | 設計上のリスク |
|---|---|---|---|
| `True` | 変更を保存し、図面を閉じる | バッチ更新、自動書き込み処理 | 意図しない上書き(データの破壊) |
| `False` | 変更を破棄し、図面を閉じる | 検図用の一時オープン、クリーンアップ | 修正内容の消失 |
| 省略 (Default) | 変更があればダイアログを表示 | インタラクティブな操作 | 自動化における致命的な停止 |
「True」を選択すべき局面
図面内の属性情報を一括更新したり、標準レイヤーを強制適用したりする「書き込み型」のツールの場合、処理の最後に `True` を渡すことで、確実に結果をファイルに定着させる。
「False」を選択すべき局面
「図面内の特定のオブジェクトが存在するかチェックするだけ」といった「読み取り専用」に近い挙動を求める場合、あるいは「エラーが発生したため、汚染された図面を保存せずに破棄したい」というリカバリ局面では、迷わず `False` を選択する。
3. プロダクションレベルの設計戦略
実務で使える堅牢なツールを作るには、「今、自分はどのモードで動いているのか」を明示的に制御する設計が必要だ。
戦略A:バッチ処理(Headless Mode)
ユーザーの介入を一切許さない設計。常に `True` または `False` を明示的に指定し、ダイアログの発生を物理的に封じ込める。
戦略B:ユーザー支援ツール(Interactive Mode)
ユーザーが手動で図面を操作している最中に動くツール。ここでは、勝手に保存して良いのか、破棄して良いのかをユーザーに問う、あるいは「変更がある場合のみ保存を試みる」といった、状況判断(`IsModified` プロパティの活用)が必要になる。
4. 実装例:堅牢なクローズ・ラッパー
以下に、私がプロジェクトで実際に使用する、エラーハンドリングと状態判定を組み込んだ「プロフェッショナルなクローズ処理」のコード例を示す。単なる `Close` ではなく、「意図を込めた関数」として設計するのが一流の作法だ。
Option Explicit
' クローズの挙動を定義する列挙型(可読性と保守性を劇的に向上させる)
Public Enum CloseStrategy
csSaveAndClose ' 変更を保存して閉じる
csDiscardAndClose ' 変更を破棄して閉じる
csAskUser ' ユーザーに確認する(インタラクティブ用)
End Enum
''' <summary>
''' 図面を安全にクローズするための高度なラッパー関数
''' </summary>
''' <param name="doc">対象のAcadDocumentオブジェクト</param>
''' <param name="strategy">クローズ戦略</param>
Public Sub SafeCloseDocument(ByRef doc As AcadDocument, ByVal strategy As CloseStrategy)
On Error GoTo ErrorHandler
' 1. 図面が既に閉じられていないか、またはNothingでないかのチェック
If doc Is Nothing Then Exit Sub
' 2. 戦略に基づいた条件分岐
Select Case strategy
Case csSaveAndClose
' 変更がある場合のみ保存。変更がなければそのまま閉じる。
' AutoCADの内部挙動として、変更なしでのTrueはダイアログを出さない。
doc.Close True
Debug.Print "Log: Document saved and closed."
Case csDiscardAndClose
' 変更の有無に関わらず、強制的に破棄して閉じる
doc.Close False
Debug.Print "Log: Document discarded and closed."
Case csAskUser
' ユーザーへの確認が必要なケース。
' ただし、自動化ループ内での使用は厳禁。
If doc.IsModified Then
' ここでMsgBoxを出す設計にするが、
' 本来の自動化ロジックではこのStrategy自体を使わない。
If MsgBox("変更が保存されていません。保存しますか?", vbYesNoCancel + vbQuestion) = vbYes Then
doc.Close True
ElseIf MsgBox("変更を破棄しますか?", vbYesNoCancel + vbQuestion) = vbYes Then
doc.Close False
Else
' キャンセル時は何もしない(図面は開いたまま)
Exit Sub
End If
Else
doc.Close False
End If
End Select
Exit Sub
ErrorHandler:
' 図面が既に閉じられている場合などのエラーを捕捉
Err.Raise Err.Number, "SafeCloseDocument", "Failed to close document. Error: " & Err.Description
End Sub
''' <summary>
''' 実務での使用イメージ(バッチ処理)
''' </summary>
Sub BatchProcessExample()
Dim acadApp As AcadApplication
Set acadApp = ThisDrawing.Application
Dim doc As AcadDocument
Dim filePath As String
filePath = "C:\Temp\Sample.dwg" ' 実際にはループ等で取得
On Error Resume Next
Set doc = acadApp.Documents.Open(filePath)
On Error GoTo 0
If Not doc Is Nothing Then
' --- ここで何らかの自動処理を行う ---
' 例: doc.ModelSpace.AddLine(...)
' 処理完了後、確実に保存して閉じる(バッチ処理の鉄則)
SafeCloseDocument doc, csSaveAndClose
End If
End Sub
5. 最後に:アーキテクトからの助言
図面操作の自動化において、`Close` メソッドは単なる「終了処理」ではない。それは、「プログラムが管理してきたデータの整合性を、ファイルシステムへ確定させる儀式」である。
1. 決定論的なコードを書け: 引数を省略して「AutoCAD任せ」にするな。
2. 副作用を予見せよ: `True` を使うなら、その変更が後続のプロセスやデータベースに与える影響を計算に入れよ。
3. 状態を疑え: `IsModified` プロパティを活用し、現在の図面の状態を常に把握せよ。
このレベルの設計思想を持ってコードを書くことで、君のツールは「便利だが危うい道具」から、「現場で信頼される基幹システム」へと進化する。
健闘を祈る。
