AutoCAD VBA 掌握: 「保存されていない図面」によるランタイムエラーを根絶する堅牢な設計思想
業務自動化ツールを開発している際、もっとも「素人臭い」バグのひとつが、「未保存の新規図面に対して `Save` メソッドを叩き、ランタイムエラーでプログラムを停止させる」ことだ。
自動化ツールは、ユーザーが意図しない操作をしても、あるいは予期せぬ図面状態であっても、エレガントに、かつ安全に動作しなければならない。単に「動けばいい」というコードは、現場では「壊れやすい負債」でしかない。
本記事では、AutoCAD VBAにおいて、新規図面(Drawing1など)の初回保存時に「名前を付けて保存」ダイアログを強制的に表示させ、確実にファイルパスを確定させるための、プロフェッショナルな設計手法を伝授する。
1. なぜ `ActiveDocument.Save` では足りないのか
多くの初心者は、図面を保存する際に直感的に `ThisDrawing.Save` を記述する。しかし、AutoCADのオブジェクトモデルにおいて、`Save` メソッドは「既に物理的なファイルとして存在する図面を上書き保存する」ことを前提としている。
ユーザーがAutoCADを起動し、「新規作成」をクリックした直後の図面は、メモリ上に存在していても、ディスク上にはまだ「アイデンティティ(ファイルパス)」を持っていない。この状態で `Save` を実行すると、AutoCADは「どこに保存すればいいのかわからない」と悲鳴を上げ、VBAは実行時エラーを吐いて停止する。
これを防ぐためには、「その図面が既にディスクに存在するかどうか」を判定し、存在しない場合は `SaveAs`(名前を付けて保存)のプロセスへとフローを分岐させる設計が必要不可欠だ。
2. 判定の鍵:`FullName` プロパティの真実
図面の状態を判定する際、`ThisDrawing.Name` ではなく `ThisDrawing.FullName` を注視せよ。
- `Name`: 「Drawing1.dwg」のようなファイル名のみを返す。
- `FullName`: 「C:\Projects\Drawing1.dwg」のような、フルパスを返す。
新規図面の場合、`FullName` は一時的なパスを指しているか、あるいは実体が存在しない状態にある。我々が設計すべきロジックはシンプルだ。
「`ThisDrawing.FullName` のパスに、実際にファイルが存在するか?」
このチェックこそが、堅牢な自動化ツールの入り口となる。
3. プロダクション・クオリティの設計指針
実務レベルのコードを書く際、以下の3点を必ず考慮に入れなければならない。
1. Late Binding(遅延結合)の活用: ユーザーの環境によって参照設定(Reference)が異なるリスクを回避するため、ダイアログ表示には `CreateObject` を用いた遅延結合を採用する。
2. キャンセル操作への耐性: ユーザーが「名前を付けて保存」ダイアログで「キャンセル」を押した場合、プログラムはエラーで落ちるのではなく、処理を中断(Graceful Exit)しなければならない。
3. 例外処理の徹底: ファイルが書き込み禁止だった場合や、不正な文字が含まれていた場合を想定したエラーハンドリングを組み込む。
4. 実装例:堅牢な保存制御ルーチン
以下に、そのままプロダクション環境へ投入可能なレベルのコードを示す。このコードは、図面が未保存であればダイアログを表示し、保存が完了すればそのパスを返し、キャンセルされれば安全に終了する。
'---------------------------------------------------------------------------------------
' Module: Module1
' Purpose: 図面の保存状態を判定し、未保存の場合はダイアログを強制表示する
' Author: Chief Architect
'---------------------------------------------------------------------------------------
Option Explicit
''' <summary>
''' 図面が保存されているか確認し、未保存ならユーザーに保存を促す。
''' </summary>
''' <returns>保存されたファイルのフルパス。キャンセルされた場合は空文字を返す。</returns>
Public Function EnsureDocumentSaved() As String
On Error GoTo ErrorHandler
Dim doc As AcadDocument
Set doc = ThisDrawing
' 1. ファイルが既に存在するかチェック
If FileExists(doc.FullName) Then
' 既に保存済みであれば、現在のパスを返して終了
EnsureDocumentSaved = doc.FullName
Exit Function
End If
' 2. 未保存の場合、名前を付けて保存ダイアログを表示
Dim targetPath As String
targetPath = ShowSaveAsDialog()
' 3. ユーザーがキャンセルした場合の処理
If targetPath = "" Then
Debug.Print "User canceled the save operation."
EnsureDocumentSaved = ""
Exit Function
End If
' 4. 指定されたパスで保存を実行 (acSaveAsType: acCurrentVersion)
' ※ ここでは現在のAutoCADバージョンで保存する設定
doc.SaveAs targetPath
EnsureDocumentSaved = doc.FullName
Exit Function
ErrorHandler:
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical, "Error"
EnsureDocumentSaved = ""
End Function
''' <summary>
''' Windowsの標準的な「名前を付けて保存」ダイアログを表示する (Late Binding)
''' </summary>
Private Function ShowSaveAsDialog() As String
Dim fd As Object
' Microsoft Office FileDialog を利用するために late binding を使用
' 参照設定の手間を省き、配布時のトラブルを最小限に抑える
On Error Resume Next
Set fd = CreateObject("Microsoft.Office.Core.FileDialog.11") ' msoFileDialogSaveAs = 2
On Error GoTo 0
If fd Is Nothing Then
MsgBox "ダイアログオブジェクトの生成に失敗しました。環境を確認してください。", vbCritical
Exit Function
End If
With fd
.Title = "図面を保存する場所を選択してください"
.InitialFileName = ThisDrawing.Name ' デフォルトのファイル名案
' ダイアログを表示
If .Show = -1 Then ' -1 は「OK」が押されたことを示す
ShowSaveAsDialog = .SelectedItems(1)
Else
ShowSaveAsDialog = "" ' キャンセル時
End If
End With
End Function
''' <summary>
''' ファイルの存在確認を行うヘルパー関数
''' </summary>
Private Function FileExists(ByVal path As String) As Boolean
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
FileExists = fso.FileExists(path)
End Function
コードの解説と設計の意図
1. `FileExists` 関数: `FileSystemObject` を利用している。これは、`Dir` 関数よりも堅牢で、ネットワークパスなどの複雑な環境においても安定した動作を保証する。
2. `ShowSaveAsDialog` の Late Binding: `CreateObject(“Microsoft.Office.Core.FileDialog.11”)` を使用している。これにより、開発者のPCにOfficeが入っていれば、利用者のPCで「参照設定が足りない」というエラーでツールが止まる事態を防げる。
3. `doc.SaveAs` の戦略的配置: `doc.Save` ではなく `doc.SaveAs` を使うことで、新規図面に対しても、既存図面への上書きに対しても、同じロジックで一貫性を持たせている。
5. アーキテクトからの助言:データベース連携への応用
もし君が、この保存処理を「図面管理データベース(SQL ServerやAccessなど)」と連携させるツールの一部として設計しているなら、さらに注意が必要だ。
「ファイルパスの確定」と「DBレコードの作成」は、必ずアトミック(不可分)に行うべきである。
ダイアログでパスが決まった直後に、そのパスをDBに書き込む。もし、DBへの書き込みに失敗したならば、図面は保存されているがDBには存在しないという「データの不整合」が発生する。このような事態を避けるため、保存処理の戻り値(`EnsureDocumentSaved`)を必ずチェックし、成功したときのみ後続のDB処理へ進む、という厳格なフローを構築せよ。
結論
AutoCAD VBAにおける「保存」の制御は、単なるプログラミング作業ではない。それは、ユーザーの作業フローを理解し、システムの境界条件(未保存状態)を正しく定義する設計作業である。
「未保存の図面」という例外状態を、設計の段階で完全にコントロール下に置くこと。それこそが、プロの自動化エンジニアと、単なるスクリプト作成者を分かつ境界線である。
