【実務・中級編】【上級プロフェッショナル向け】ネットワーク切断時の「緊急ローカル退避保存」:保存エラーをトラップしてデータを守る – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:ネットワーク切断時の「緊急ローカル退避保存」

開発プロジェクトのリーダーである私たちが、現場の設計者から最も恐れられる瞬間を知っているか?
それは、終業間際、数時間に及ぶ渾身のモデリングの末に、「ネットワークエラー:ファイルを保存できませんでした」という冷酷なダイアログが表示された瞬間だ。

共有サーバーの瞬断、VPNの切断、あるいはNASのトラブル。
CADオペレーターがいくら神業的なスピードで図面を描こうとも、インフラの魔神が微笑んだ瞬間に、未保存のデータは揮発する。AutoCADの自動保存(AUTOSAVE)機能もあるが、あれはタイムラグがあり、かつ指定パスがサーバー上に設定されている場合、ネットワーク障害時には無力と化す。

今回は、AutoCAD VBAのイベントとエラーハンドリングの深淵を突き詰め、「サーバー保存が失敗した瞬間に、自動でローカルのTemp領域へ緊急退避させ、作業ロスを絶対にゼロにする」ための堅牢なプロダクションコードを伝授する。

—

なぜ「通常のSaveAs」では現場を救えないのか?

素人プログラマーは、次のようなコードを書く。

‘ 【アンチパターン】これではネットワーク切断時に沈黙する
Sub BadSave()
On Error Resume Next
ThisDrawing.Save
If Err.Number <> 0 Then
MsgBox “保存に失敗しました!”
End If
On Error GoTo 0
End Sub

このアプローチがなぜゴミなのか?理由は3つある。

1. `ThisDrawing.Save` の非力さ:
すでに一度も保存されていない新規図面や、リモートパスへのアクセス権限・タイムアウト制御において、単なる `On Error` ではAutoCAD内部のCOM例外を完全に捕捉しきれないケースがある。
2. パスの動的書き換えの欠如:
保存先がダメなら、どこに・どのような命名規則で退避させるべきかという「フォールバック戦略」がコードに組み込まれていない。
3. ユーザーへの認知負荷:
エラーが出て止まるだけのプログラムは、パニックに陥った設計者を助けない。「どこに救出されたのか」を明確に示し、かつ図面オブジェクトのデータベース(Database)を汚染しない設計が不可欠だ。

プロフェッショナルは、「保存プロセスそのものを監視し、例外をトランザクションのように巻き戻してローカルへ強制退避させる」仕組みを構築する。

—

堅牢な緊急退避システムのアーキテクチャ

今回構築するシステムの要件は以下の通りである。

1. トランザクション的思考: サーバーへの上書き保存(`SaveAs` または `Save`)を実行し、エラーが発生した場合は即座にトラップする。
2. 安全なローカルパスの生成: 実行ユーザー名、元のファイル名、タイムスタンプを結合し、ファイル名の衝突(Collision)を防いだ状態で `Environ(“TEMP”)` へ退避させる。
3. 図面タイトルの維持: ローカルへ緊急退避させた後も、ドキュメントのポインタやステータスを適切に管理し、作業を継続できるようにする。

—

プロダクションコード:緊急ローカル退避モジュール

以下のコードを、AutoCADのVBAプロジェクト(`ThisDrawing` または標準モジュール)に実装せよ。実務の現場でそのままコピー&ペーストし、即座に稼働させることが可能なレベルまで磨き上げている。

Option Explicit

‘ ==============================================================================
‘ 処理名: ネットワーク切断対策・緊急ローカル退避保存ルーチン
‘ 概要 : サーバーへの保存失敗を検知し、ローカルTempへタイムスタンプ付きで強制退避
‘ ==============================================================================
Public Sub EmergencySaveToLocal()
Dim targetDoc As Document
Set targetDoc = ThisDrawing

Dim originalFullName As String
Dim fileNameOnly As String
Dim fileExtension As String
Dim localTempPath As String
Dim emergencyFileName As String
Dim timeStamp As String

‘ 1. 現在のドキュメントのパスと名前を取得
On Error GoTo PathError
originalFullName = targetDoc.FullName

‘ まだ一度も保存されていない(未命名)図面の場合のハンドリング
If originalFullName = “” Then
fileNameOnly = “UnsavedDrawing”
fileExtension = “.dwg”
Else
fileNameOnly = GetFileNameWithoutExtension(targetDoc.Name)
fileExtension = GetExtension(targetDoc.Name)
End If
On Error GoTo 0

‘ 2. タイムスタンプの生成 (YYYYMMDD_HHMMSS形式)
timeStamp = Format(Now, “yyyymmdd_HHMMSS”)

‘ 3. ローカルのTempフォルダパスを取得し、退避ファイル名を構築
localTempPath = Environ(“TEMP”) & “\”
emergencyFileName = localTempPath & fileNameOnly & “_EMERGENCY_” & timeStamp & fileExtension

‘ 4. 保存の試行(メイン処理)
‘ まずは通常通りに保存を試みる
On Error GoTo ServerSaveFailed

If originalFullName = “” Then
‘ 新規図面の場合は名前をつけて保存
targetDoc.SaveAs emergencyFileName
MsgBox “図面は未保存だったため、ローカルTempに緊急保存しました。” & vbCrLf & emergencyFileName, vbExclamation, “緊急退避完了”
Else
‘ 上書き保存を試行
targetDoc.Save
‘ ここに到達できればサーバー保存は成功
Exit Sub
End If

Exit Sub

ServerSaveFailed:
‘ ==========================================================================
‘ 【例外処理】サーバー保存時のエラー(ネットワーク切断等)をここでキャッチ
‘ ==========================================================================
Dim errDesc As String
errDesc = Err.Description

On Error GoTo LocalSaveFatal

‘ サーバーがダメなら、強制的にローカルTempへ「名前をつけて保存 (SaveAs)」を実行
‘ これにより、メモリ上の最新データを確実にハードディスクに掴み取る
targetDoc.SaveAs emergencyFileName

‘ 成功時の警告とリカバリ案内
MsgBox “【警告】ネットワーク接続のエラーを検知しました!” & vbCrLf & _
“サーバーへの保存に失敗したため、データを以下のローカルパスに緊急退避しました。” & vbCrLf & vbCrLf & _
emergencyFileName & vbCrLf & vbCrLf & _
“エラー詳細: ” & errDesc, _
vbCritical + vbOKOnly, “【緊急】データ保護発動”

Exit Sub

LocalSaveFatal:
‘ ネットワークもローカルディスクすら書き込み不可という極限状態
MsgBox “【致命的エラー】ローカルストレージへの退避にも失敗しました。” & vbCrLf & _
“CADを終了せず、外部ストレージやクリップボードへの退避を手動で行ってください。” & vbCrLf & _
“エラー: ” & Err.Description, _
vbCritical, “完全保存失敗”
Exit Sub

PathError:
MsgBox “図面情報の取得に失敗しました。”, vbCritical, “エラー”
End Sub

‘ — ヘルパー関数: 拡張子なしのファイル名を取得 —
Private Function GetFileNameWithoutExtension(ByVal fullName As String) As String
Dim p As Long
p = InStrRev(fullName, “.”)
If p > 0 Then
GetFileNameWithoutExtension = Left(fullName, p – 1)
Else
GetFileNameWithoutExtension = fullName
End If
End Function

‘ — ヘルパー関数: 拡張子を取得 —
Private Function GetExtension(ByVal fullName As String) As String
Dim p As Long
p = InStrRev(fullName, “.”)
If p > 0 Then
GetExtension = Mid(fullName, p)
Else
GetExtension = “.dwg”
End If
End Function

—

コードの設計思想とエンジニアリング的解説

このコードが「なぜプロフェッショナル仕様なのか」、その裏側にある設計思想を解説する。

1. 二段構えの例外トラップ(フォールバック・パターン)

通常の `ThisDrawing.Save` でエラーが発生した際、処理は `ServerSaveFailed` ラベルへジャンプする。
ここではエラーメッセージを保持したまま、即座に `targetDoc.SaveAs emergencyFileName` を実行する。
これにより、「ネットワークパスへの書き込み試行で発生したタイムアウトやI/Oエラーをバイパスし、確実にI/Oの向き先をローカルへ切り替える」という離れ業をやってのけている。

2. 衝突を防ぐ一意の命名規則(Collision Avoidance)

緊急退避の際に単に `backup.dwg` などという名前をつけてはならない。複数回エラーが起きた場合や、複数の図面を同時に扱っている場合に上書き事故が起きる。
`Format(Now, “yyyymmdd_HHMMSS”)` を付与することで、タイムスタンプベースの完全な一意性を担保し、データのロストを防いでいる。

3. 最悪のシナリオ(LocalSaveFatal)への備え

ネットワークもダメ、もしやローカルの空き容量もない、あるいは権限がないという「最悪の極限状態」すら想定している。
万が一ローカル保存すら失敗した場合でも、プログラムがクラッシュしてAutoCADごと落ちるのを防ぎ、ユーザーに手動退避を促すメッセージボックスをポップさせる。プログラマブルな傲慢さを捨て、最後の砦としてメッセージでユーザーを導く設計だ。

—

現場への導入と運用のアドバイス

このマクロを現場に展開するにあたり、以下のポイントをリーダーとして徹底してほしい。

  • リボンメニューやCUIへの統合:

設計者に `Alt + F8` でマクロを開かせてはならない。クイックアクセスツールバーやカスタムリボンにこの `EmergencySaveToLocal` を割り当て、「通常の保存ボタンの代わりにこれを押させる」、あるいはアプリケーションイベント(`DocumentBeforeSave` など)のフックと組み合わせることで、意識させずにこの安全網を機能させるのが理想だ。

  • Tempフォルダの定期清掃:

このスクリプトはローカルの `Temp` にファイルを量産するため、Windowsのタスクスケジューラなどで古いTempファイルを掃除するポリシーをIT部門と連携して組んでおくこと。

インフラストラクチャはいつか必ず裏切る。だが、コードを書く私たちは、その裏切りからユーザーの労力を守り抜くことができる。
この知見をあなたの開発環境にインストールし、真に堅牢なAutoCAD自動化環境を構築せよ。

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