【実務・中級編】【初心者向け】新規図面(Drawing1)の初回保存時に「名前を付けて保存」ダイアログを強制表示させるVBA制御 – AutoCAD VBA解析バイブル

スポンサーリンク
スポンサーリンク

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における「保存」の制御は、単なるプログラミング作業ではない。それは、ユーザーの作業フローを理解し、システムの境界条件(未保存状態)を正しく定義する設計作業である。

「未保存の図面」という例外状態を、設計の段階で完全にコントロール下に置くこと。それこそが、プロの自動化エンジニアと、単なるスクリプト作成者を分かつ境界線である。

タイトルとURLをコピーしました