【テクニカル・上級編】【中級者向け】Visioの保存処理で「読み取り専用」属性のファイルを検知し、別名保存を促すエラーハンドリング – Visio VBA解析バイブル

スポンサーリンク

Visio VBAの深淵:共有ファイルの排他制御と「読み取り専用」の静かなる罠

諸君、現場でVisioを操っているか。

自動化の黎明期から今日に至るまで、Visioのオートメーションは常に「ファイルの安全性」という名の地雷原を歩くようなものだ。特に共有フォルダ上のVSDXファイル。ネットワークの瞬断、OSのファイルロック、そして読み取り専用属性の壁。これらを考慮しない「`.Save`」は、いずれ必ず致命的な実行時エラーを引き起こし、現場のエンジニアを絶望させる。

今日は、小手先のメソッド呼び出しを超え、Windows APIとメモリ管理を駆使した「堅牢なファイル制御」の極意を伝授しよう。

1. なぜ Visio の `Save` は失敗するのか

Visioの `Document.Save` メソッドは、内部的にファイルシステムへの排他的アクセスを要求する。もし対象ファイルが既に他者によって開かれている、あるいはOSレベルで「読み取り専用」属性が付与されている場合、Visioは無慈悲にも例外を投げる。

ここで重要なのは、「例外をキャッチしてから対処する」のではなく、「触れる前に属性を解読する」という防衛的プログラミングだ。

2. Windows API による属性先行検知

VBAの標準関数 `GetAttr` も悪くはないが、共有環境での確実な排他制御や、アクセス権限の詳細までを見極めるには、Windows APIの `GetFileAttributes` を直接叩くのがシニアの流儀だ。

以下に、ファイル保存前に実行すべき「安全確認モジュール」を提示する。

Option Explicit

‘ カーネル32の属性取得関数をインポート
If VBA7 Then
Private Declare PtrSafe Function GetFileAttributes Lib “kernel32” Alias “GetFileAttributesW” (ByVal lpFileName As LongPtr) As Long
Else
Private Declare Function GetFileAttributes Lib “kernel32” Alias “GetFileAttributesW” (ByVal lpFileName As String) As Long
End If

Private Const FILE_ATTRIBUTE_READONLY As Long = &H1

”’

”’ ファイルが読み取り専用かどうかを判定する
”’

Public Function IsFileReadOnly(ByVal filePath As String) As Boolean
Dim attr As Long
‘ 文字列をUnicodeに変換してAPIへ渡す(マルチバイト文字対応)
attr = GetFileAttributes(StrPtr(filePath))

If attr = -1 Then
‘ ファイルが存在しない場合のエラーハンドリング
IsFileReadOnly = False
Else
IsFileReadOnly = (attr And FILE_ATTRIBUTE_READONLY) <> 0
End If
End Function

3. 実践:排他制御を考慮した保存シーケンス

単に保存を試みるのではなく、属性チェックを通し、必要であれば「別名保存(SaveAs)」を促すガード節を実装する。

Public Sub SafeSaveDocument(ByRef doc As Visio.Document)
Dim targetPath As String
targetPath = doc.FullName

‘ 属性チェック:読み取り専用なら強制的に別名保存へ誘導
If IsFileReadOnly(targetPath) Then
MsgBox “対象ファイルは読み取り専用です。別名で保存してください。”, vbCritical
Call SaveAsDialog(doc)
Exit Sub
End If

‘ ここで初めて保存を試みる
On Error Resume Next
doc.Save
If Err.Number <> 0 Then
MsgBox “保存失敗: ” & Err.Description, vbCritical
‘ 必要に応じてログ出力処理をここに実装
End If
On Error GoTo 0
End Sub

Private Sub SaveAsDialog(ByRef doc As Visio.Document)
‘ Visio標準の保存ダイアログを呼び出す
‘ ユーザーの介在を許すことで、書き込み可能な場所へ逃がす
Application.DoCmd (visCmdFileSaveAs)
End Sub

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

シニアエンジニアとして忘れてはならないのが、「Visioのオブジェクトはメモリを食う」という事実だ。

特に `Document` オブジェクトをループ処理で大量に開閉する場合、明示的な `Nothing` 代入を怠ると、Visioプロセスがバックグラウンドに残り続け、共有ファイルのロックが解除されない「ゾンビ状態」に陥る。

  • スコープの最小化: 可能な限りプロシージャ内で完結させ、終了時に `Set doc = Nothing` を徹底せよ。
  • イベントの切断: 複雑なシステム間連携を行う際は、 `Application.DocumentSaved` 等のイベントシンクを適切に解除すること。イベントが循環参照を起こすと、プロセスはメモリリークを起こし、次の保存処理が不可能になる。

結びに:伝説のアーキテクトからの助言

「自動化」とは、プログラムを動かすことではない。「いかなる状況下でもシステムを停止させないこと」こそが、真の自動化エンジニアの職責だ。

共有フォルダ上のVSDXは、ネットワークの不確定性という悪魔と隣り合わせにある。今日紹介したAPIによる属性チェックは、その悪魔に対する最も基本的な「防御の構え」だ。

もし諸君が、より高次元の排他制御を求めるなら、次は `CreateFile` APIを用いた「共有モード」でのファイルオープンを研究するといい。だが、まずはこのコードを読み込み、現場のレガシーな環境で「落ちないシステム」を構築することから始めてほしい。

コードは嘘をつかない。書いた人間の知見と、細部へのこだわりが、そのままシステムの安定性として返ってくるのだから。

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