【テクニカル・上級編】【実務中級者向け】「SaveAs」失敗時の代替保存先確保:ネットワーク切断時にローカルの「緊急退避フォルダ」へ自動保存する – AutoCAD VBA解析バイブル

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

データ消失の臨界点を回避せよ:AutoCAD VBAにおける「弾力的なSaveAs」の実装戦略

エンタープライズ環境におけるCAD運用において、最も忌むべき事態は何か。それは「数時間の作業が、ネットワークの瞬断によって虚無に帰すこと」だ。

サーバーへの保存(`SaveAs`)を実行した瞬間、ストレージへのパケットが消失する。あるいは、分散ファイルシステム(DFS)の同期エラーにより、書き込み権限が突如として剥奪される。このような事態に直面した際、単に「エラーメッセージを表示して終了する」だけのコードを書くのは、未熟なプログラマの仕事だ。

我々シニアエンジニアに求められるのは、「システムが失敗することを前提とした、堅牢なフォールバック(代替策)の設計」である。

本稿では、ネットワーク障害を検知した際、即座にローカルの「緊急退避領域」へタイムスタンプ付きでデータを隔離する、極めて実戦的な実装手法を解説する。

1. アーキテクチャの設計思想:Fail-Safe Design

単なる `On Error Resume Next` は、エラーの真因を隠蔽するだけの毒薬である。我々が実装すべきは、以下の3層構造を持つ防衛ラインだ。

1. Primary Path (Network/Server): 通常の業務フロー。
2. Detection Layer (Error Trapping): `SaveAs` メソッドの戻り値および、エラーオブジェクトの解析。
3. Emergency Path (Local Desktop/Temp): ネットワーク切断を検知した際の、唯一の生存ルート。

ここで重要なのは、緊急退避先のパスをハードコードしないことだ。Windows APIの概念を用い、ユーザーのプロファイル環境(`%USERPROFILE%`)に依存した、確実に書き込み可能なローカルディレクトリを動的に特定する必要がある。

2. 実装:堅牢な緊急退避ロジック

以下に、実務レベルでそのまま組み込める、エラーハンドリングとオブジェクト管理を徹底したコード例を示す。

Option Explicit

' ======================================================================================
' Module: EmergencySaveModule
' Description: ネットワーク障害時における図面の自動ローカル退避実装
' Author: Legendary Chief Architect
' ======================================================================================

''
' 図面を安全に保存する。失敗した場合はローカルの緊急フォルダへ退避する。
' @param targetPath: 本来保存すべきネットワーク上のフルパス
''
Public Sub RobustSaveAs(ByVal targetPath As String)
    Dim acadDoc As AcadDocument
    Set acadDoc = ThisDrawing
    
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    On Error GoTo ErrorHandler

    ' 1. 通常の保存試行
    Debug.Print "Attempting primary save: " & targetPath
    acadDoc.SaveAs targetPath
    
    Debug.Print "Primary save successful."
    Exit Sub

ErrorHandler:
    ' 2. エラー解析
    ' エラー番号がネットワーク断絶やアクセス拒否に関連する場合、退避プロセスへ移行
    ' AutoCADのSaveAsエラーは、環境により異なるが、基本的には実行時エラーとしてトラップされる
    Debug.Print "Primary save failed. Error: " & Err.Number & " - " & Err.Description
    
    ' 3. 緊急退避プロセスへの移行
    Call ExecuteEmergencyFallback(acadDoc, fso)
    
    ' エラーをクリアして正常終了扱いにする(ユーザーには通知が必要)
    Err.Clear
End Sub

''
' ローカル環境への緊急退避を実行する内部関数
''
Private Sub ExecuteEmergencyFallback(ByRef acadDoc As AcadDocument, ByRef fso As Object)
    Dim localFolder As String
    Dim fileName As String
    Dim timestamp As String
    Dim emergencyPath As String
    
    On Error GoTo CriticalError
    
    ' A. ローカルの退避先ディレクトリを特定 (デスクトップ下の "CAD_EMERGENCY_SAVE" を想定)
    ' WScript.Shellを使用して、環境変数からユーザープロファイルを取得する
    Dim shell As Object
    Set shell = CreateObject("WScript.Shell")
    localFolder = shell.SpecialFolders("Desktop") & "\CAD_EMERGENCY_SAVE"
    
    ' B. ディレクトリが存在しない場合は作成
    If Not fso.FolderExists(localFolder) Then
        fso.CreateFolder localFolder
    End If
    
    ' C. ファイル名の生成 (元のファイル名 + ISO 8601形式のタイムスタンプ)
    ' ネットワークパスからファイル名のみを抽出
    fileName = fso.GetFileName(acadDoc.FullName)
    If fileName = "" Then fileName = "Unknown_Drawing.dwg"
    
    timestamp = Format(Now, "yyyyMMdd_HHmmss")
    emergencyPath = localFolder & "\" & fso.GetBaseName(fileName) & "_" & timestamp & ".dwg"
    
    ' D. 緊急保存の実行
    Debug.Print "CRITICAL: Redirecting save to local path: " & emergencyPath
    acadDoc.SaveAs emergencyPath
    
    ' E. ユーザーへの通知(重要)
    ' ここでMsgBoxを使うのは、ユーザーに「データが救済されたこと」を認識させるためである
    MsgBox "【警告】ネットワーク接続エラーを検知しました。" & vbCrLf & _
           "図面をローカル環境へ緊急退避しました:" & vbCrLf & emergencyPath, _
           vbExclamation, "Data Survival Protocol Activated"

    ' オブジェクトの明示的解放(メモリリーク防止)
    Set shell = Nothing
    Set fso = Nothing
    Exit Sub

CriticalError:
    MsgBox "致命的なエラー: 緊急退避にも失敗しました。メモリ上のデータのみが残っています。" & vbCrLf & _
           "直ちにAutoCADのプロセスを維持してください。", vbCritical, "System Failure"
    Set shell = Nothing
    Set fso = Nothing
End Sub

3. 深層解説:プロフェッショナルのための知見

オブジェクトのライフサイクルとメモリ管理

上記のコードでは、`FileSystemObject` や `WScript.Shell` を使用している。VBAにおいて、これらのCOMオブジェクトは、スコープを抜ける際に適切に解放(`Set obj = Nothing`)されるべきだ。特に、大規模な自動化スクリプトの中でエラーハンドリングを繰り返す場合、解放を怠るとメモリリークを引き起こし、AutoCAD自体の不安定化を招く。

なぜ `FileSystemObject` なのか

VBA標準の `Dir` 関数は、ネットワークパスの扱いにおいて極めて脆弱である。UNCパス(`\\Server\Share\…`)が切断された際、`Dir` は予期せぬ挙動を示すことがある。一方、`Scripting.FileSystemObject` はWindowsのシェル構造に深く統合されており、ネットワークエラーに対してもより強固な例外処理が可能だ。

タイムスタンプの重要性

緊急退避ファイルには、必ず `yyyyMMdd_HHmmss` 形式のタイムスタンプを付与せよ。これは単なる慣習ではない。複数の保存失敗が発生した場合、どのファイルが「最新の生存データ」であるかを、ファイルシステム上のソート順だけで即座に判断できるようにするためだ。

システム間連携への視点

このロジックは、将来的にVB.NETやC#によるアドイン開発へ移行する際の「アルゴリズムの設計図」となる。エラーを単なる「停止理由」としてではなく、「状態遷移のトリガー」として捉える設計思想こそが、ミッションクリティカルな業務システムを支えるのである。

結論

「保存に失敗しました」というエラーをユーザーに突きつけるのは、エンジニアの怠慢である。「ネットワークが切断されましたが、データはローカルに保護されました」と伝えるのが、プロフェッショナルの仕事だ。

この実装を、君たちのシステムに組み込みたまえ。データは、失われるためにあるのではない。守るためにあるのだ。

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