ネットワーク越しの保存は「水物」である ― Project VBAにおける堅牢なリトライ戦略
Project VBA(Microsoft ProjectのVBA)を扱うエンジニアにとって、ネットワークドライブ上のプロジェクトファイル保存は常に「悪夢」と隣り合わせだ。VPNの瞬断、ファイルサーバーのロック、あるいはWindowsのファイルシステムキャッシュの気まぐれ。
標準的な `FileSave` メソッドを信じて疑わない者は、いつか必ず「保存失敗によるデータロスト」という致命的な代償を支払うことになる。
今日は、単なるエラーハンドリングの枠を超え、Windows APIを駆使して「接続状態を物理的に検知」し、再試行を行う極限のセーフティネットの実装論を共有する。
—
1. なぜ、標準の保存ルーチンでは不十分なのか
VBAの `Application.FileSave` は非常に脆弱だ。ネットワークが切断された際、APIはタイムアウトまで待機し、そのまま無慈悲にランタイムエラーを投げる。
ここで重要なのは、「エラーが起きた」という事実だけでなく、「何が原因で失敗したのか」を低レイヤーで特定することだ。単なる `On Error Resume Next` で誤魔化すのは素人の所業。我々がやるべきは、接続の死活監視と、オブジェクト解放によるメモリのクリーンアップを伴う、戦略的なリトライである。
—
2. 実装の核心:WNetGetConnectionによるネットワーク監視
ネットワークドライブの生死を確認するためには、`mpr.dll` の `WNetGetConnection` を利用する。これはOSレベルでネットワークパスの生存を確認する最も低コストな手法だ。
以下のコードは、保存失敗時に指定回数リトライを試み、その過程でネットワークの導通確認を挟む堅牢なルーチンである。
Option Explicit
‘ ネットワーク接続確認のためのWin32 API宣言
Private Declare PtrSafe Function WNetGetConnection Lib “mpr.dll” Alias “WNetGetConnectionA” ( _
ByVal lpszLocalName As String, _
ByVal lpszRemoteName As String, _
ByRef cbRemoteName As Long) As Long
”’
”’
Private Function IsNetworkPathAlive(ByVal Path As String) As Boolean
Dim driveLetter As String
Dim buffer As String 255
Dim bufferLen As Long
driveLetter = Left(Path, 2)
bufferLen = 255
‘ 0が返れば接続成功、それ以外は切断または非ネットワークパス
IsNetworkPathAlive = (WNetGetConnection(driveLetter, buffer, bufferLen) = 0)
End Function
”’
”’
Public Sub RobustSaveProject(ByVal filePath As String)
Dim retryCount As Integer
Dim maxRetries As Integer: maxRetries = 3
Dim success As Boolean: success = False
Do While retryCount < maxRetries And Not success On Error Resume Next ' 明示的にファイルを保存 Application.FileSaveAs Name:=filePath If Err.Number = 0 Then success = True Else retryCount = retryCount + 1 ' ここでネットワークの死活を確認 If Not IsNetworkPathAlive(filePath) Then Debug.Print "ネットワーク切断を検知。再接続待機中... (" & retryCount & "/" & maxRetries & ")" Sleep 2000 ' 2秒待機(Sleep関数は別途定義が必要) Else ' ネットワークは生きているが保存に失敗した場合は、少し時間を置いてメモリを解放する DoEvents Sleep 1000 End If End If On Error GoTo 0 Loop If Not success Then MsgBox "致命的エラー: 保存に失敗しました。ローカルへの退避を推奨します。", vbCritical End If End Sub ---
3. メモリとリソースの最適化:エンジニアの作法
上記のコードに加え、大規模なプロジェクトを扱う際は以下の点に留意せよ。
1. DoEventsの適切な挿入: ネットワークI/Oを待機する間、VBAのシングルスレッドモデルをブロックしないこと。`DoEvents` を挟むことで、OSがネットワークリソースを再確保する隙間を作る。
2. オブジェクトの明示的解放: プロジェクト操作後に `Set Project = Nothing` を行うことは基本だが、特にファイルシステムオブジェクト(FSO)を併用する場合は、スコープを最小限にし、即座にメモリを解放せよ。VBAのガベージコレクションは信用するな。
3. レガシー環境への配慮: `PtrSafe` キーワードを必ず付与し、64bit/32bit双方のOffice環境で動作するように設計する。これがプロフェッショナルとしての最低限の要件だ。
結論:技術は「念のための備え」に宿る
システムは必ず壊れる。ネットワークは必ず切れる。
「うまく動いているとき」のコードは誰にでも書けるが、「システムが悲鳴を上げているときに、いかに優雅にリカバリするか」こそが、シニアエンジニアの価値を決める。
今回提示したリトライロジックは、単なるコードの断片ではない。貴殿が抱えるレガシーシステムを、明日からの運用から解放するための「盾」である。このアーキテクチャを理解し、現場の過酷な環境へと実装してほしい。
健闘を祈る。
