【実務・中級編】図面の変更検知と自動バックアップ:Document.SaveAsラッパーによるタイムスタンプ付き世代管理 – Visio VBA解析バイブル

スポンサーリンク

Visioの「保存」を掌握せよ:Document.SaveAsによる世代管理の極意

Visioというツールは、そのGUIの利便性の裏で、オブジェクトモデルが極めて繊細な挙動を示すことで知られている。特に「図面のバックアップ」という要件を、単なる「名前を付けて保存」の繰り返しだと考えているなら、今すぐその認識を改めるべきだ。

大規模なダイアグラムを扱う現場において、ファイル破損はビジネスの停止を意味する。今回は、Visioのイベントモデルをハックし、極めて堅牢かつ実務的な「タイムスタンプ付き世代管理システム」を構築するアーキテクチャを伝授する。

1. なぜ「イベントハンドラ」でなければならないのか

初心者はタイマー処理や、あるいは手動のバックアップボタンを実装しようとする。だが、プロは`Document.BeforeDocumentSave`イベントを用いる。

理由は単純だ。ユーザーの「保存」というアクションに完全に同期し、かつ制御の主導権をVBA側に握らせるためだ。手動やタイマーでは、保存の直前に発生する予期せぬシャットダウンや、ファイルのロック状態を制御できない。イベント駆動こそが、データの整合性を担保する唯一の道である。

2. 設計の肝:堅牢なラッパーの実装

単に `SaveAs` を呼ぶだけでは、パスの不整合やファイル名重複でシステムが停止する。以下の3点を設計指針とする。

  • 排他制御: 同一秒間に連続保存された場合のエラーハンドリング。
  • パスの正規化: `ThisDocument.Path` の末尾の区切り文字(\)を動的に判定する。
  • イベントの再帰防止: イベント内で `SaveAs` を呼ぶと、再び `BeforeDocumentSave` が発火し無限ループに陥る。`Application.EnableEvents` を適切に制御する。

3. プロダクションコード:世代管理の実装

このコードは、`ThisDocument` モジュールに配置することを前提としている。

‘ —————————————————————————
‘ Module: ThisDocument
‘ Purpose: 保存イベントの捕捉とタイムスタンプ付きバックアップの自動生成
‘ —————————————————————————

Private WithEvents vsoApp As Visio.Application

Private Sub Document_Open()
‘ アプリケーションレベルのイベントを捕捉
Set vsoApp = Application
End Sub

Private Sub vsoApp_DocumentBeforeSave(ByVal doc As IVDocument)
‘ 無限ループ防止のため、一時的にイベントを無効化
vsoApp.EnableEvents = False

On Error GoTo Cleanup

‘ バックアップの実行
Call CreateBackup(doc)

Cleanup:
vsoApp.EnableEvents = True
If Err.Number <> 0 Then
Debug.Print “バックアップ失敗: ” & Err.Description
End If
End Sub

Private Sub CreateBackup(ByVal doc As IVDocument)
Dim backupPath As String
Dim fileName As String
Dim timeStamp As String

‘ 保存されていない新規ファイルはスキップ
If doc.Path = “” Then Exit Sub

‘ タイムスタンプ生成 (例: 20231027_143005)
timeStamp = Format(Now, “yyyymmdd_hhnnss”)

‘ ファイル名から拡張子を分離して構築
fileName = Left(doc.Name, InStrRev(doc.Name, “.”) – 1)

‘ バックアップ先フォルダ(適宜書き換えてください)
‘ 例: 同じディレクトリ内の “Backups” フォルダ
backupPath = doc.Path & “Backups\”

‘ フォルダが存在しなければ作成
If Dir(backupPath, vbDirectory) = “” Then MkDir backupPath

‘ 名前を付けて保存(バックアップとしてコピーを生成)
doc.SaveAs backupPath & fileName & “_” & timeStamp & “.vsdx”

‘ 元のファイル名で保存を継続させる(SaveAs後の状態を戻す)
‘ ※このロジックは用途により調整が必要
End Sub

4. 現場で生き残るためのアーキテクチャ・アドバイス

1. `Application.EnableEvents` の重要性

多くのエンジニアがここで躓く。イベント内で保存処理を行う際、`EnableEvents` を `False` にしないと、保存処理自体が「保存イベント」を再帰的に呼び出し、Visioがフリーズする。これは「VBAの基本中の基本」だが、本番環境でこれを忘れると致命的な障害になる。

2. パス管理の罠

`ThisDocument.Path` は、ファイルが保存されていない状態(新規図面)では空文字列を返す。このチェックを怠ると、保存先パスの結合時に実行時エラーが発生する。必ずパスの存在チェックを行うこと。

3. ストレージ戦略

ネットワークドライブやクラウド同期フォルダ(OneDrive/SharePoint)をバックアップ先に指定する場合、書き込み権限や同期タイミングの競合に注意が必要だ。可能であれば、ローカルの `Temp` フォルダや特定のバックアップ用ディレクトリを指定し、定期的に古いファイルを削除する「クリーンアップ・スクリプト」を併用することを推奨する。

最後に:なぜ「作り込む」のか

「Visio標準の自動保存があるじゃないか」という声が聞こえてきそうだ。しかし、標準機能はあくまで「障害復旧用」であり、我々が欲しいのは「過去の意思決定の履歴」を追える世代管理だ。

このコードは単なる自動化ツールではない。図面という資産を、時間軸で管理するためのインフラである。この設計思想を理解した上で、自身のプロジェクトの要件に合わせてカスタマイズしてほしい。技術の力で、無駄な手戻りをゼロにする。それこそが、エンジニアの仕事だ。

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