【Project VBA極意】ネットワーク共有の悪夢を断つ。堅牢な排他制御ロックの実装術
ネットワーク共有フォルダ上のProjectファイルを複数人で開く。多くの現場で起きているこの惨劇は、もはや「運用ルール」で解決できる段階ではない。
「読み取り専用で開かれています」という警告が出る頃には、すでに誰かの作業は上書きされ、消滅している。今回は、VBAエンジニアが避けて通れない「自前で実装する排他制御(Lock File)」の設計思想と、プロダクション環境で耐えうる堅牢な実装コードを授ける。
—
なぜ既存のファイルロックでは不十分なのか?
多くの初心者は、Excelの標準機能や単なるファイル存在チェックに頼る。だが、それはあまりに脆い。
- 非同期の罠: ファイルを開くタイミングとロックを作成するタイミングの間に、ミリ秒単位の競合が発生する。
- ゾンビロック問題: PCがフリーズしたり、VBAが異常終了した際、ロックファイルが残ったままになる。これを放置すると、誰もプロジェクトにアクセスできなくなる。
我々が実装すべきは、「誰が、いつ、どのPCで」作業しているかを明記し、かつ「異常終了時には自動的に無効化される」設計だ。
—
堅牢なロック管理の設計思想
以下の3ステップで排他制御を構築する。
1. アトミックな生成: `Open … For Output` で排他的にロックファイルを生成し、失敗すれば即座に中断する。
2. メタデータの格納: ロックファイルには「ユーザー名」「PC名」「タイムスタンプ」を書き込む。これにより、万が一のデッドロック時に管理者が特定できる。
3. 生存確認(Heartbeat)の擬似実装: 起動時に古いロックファイルを検知した場合、最終更新時刻を確認し、一定時間(例:1時間)経過していれば強制解放するロジックを入れる。
—
実装コード:`LockManager` モジュール
このクラスをプロジェクトに組み込み、`Workbook_Open` イベントの先頭で呼び出すだけで、あなたのプロジェクトは「守られた領域」へと進化する。
‘ — LockManager.cls —
Option Explicit
Private Const LOCK_PATH As String = “\\Server\Shared\Project_Lock.tmp”
Private Const LOCK_TIMEOUT_MINUTES As Long = 60
‘ ロックを取得する。失敗した場合はFalseを返す
Public Function TryLock() As Boolean
Dim fileNum As Integer
Dim lockUser As String
‘ ロックファイルが存在する場合の生存確認
If Dir(LOCK_PATH) <> “” Then
If IsLockExpired() Then
Kill LOCK_PATH
Else
MsgBox “現在他のユーザーが編集中です。”, vbCritical
Exit Function
End If
End If
‘ アトミックな書き込み(排他生成)
fileNum = FreeFile
Open LOCK_PATH For Output As #fileNum
Print #fileNum, Environ(“Username”) & “|” & Environ(“ComputerName”) & “|” & Now
Close #fileNum
TryLock = True
End Function
‘ ロックを解放する(Workbook_BeforeCloseで呼び出す)
Public Sub ReleaseLock()
If Dir(LOCK_PATH) <> “” Then Kill LOCK_PATH
End Sub
‘ 最終更新時刻から一定時間経過しているか判定
Private Function IsLockExpired() As Boolean
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim lastModified As Date
lastModified = fso.GetFile(LOCK_PATH).DateLastModified
If DateDiff(“n”, lastModified, Now) > LOCK_TIMEOUT_MINUTES Then
IsLockExpired = True
End If
End Function
—
実装上の重要な注意点:ここがプロの境界線
1. `Workbook_BeforeClose` の徹底
ロックの解放は、`Workbook_BeforeClose` イベントで必ず実行すること。ただし、ユーザーが「タスクマネージャーで強制終了」した場合、このイベントは走らない。だからこそ、先述の `IsLockExpired` (タイムアウト判定)が命綱になる。
2. ネットワーク遅延への耐性
ネットワークドライブのファイル操作は、ローカルとは比較にならないほど遅い。`Dir()` 関数や `Kill` 命令の直後に、必要であれば `DoEvents` を入れ、OSのファイルシステムがロックを認識するまでのラグを考慮する余裕を持つこと。
3. ロギングの推奨
可能であれば、ロックの成功・失敗を `C:\Logs\project_access.log` のような別ファイルに追記して残しておくべきだ。トラブルシューティングの際、「誰がいつロックを放置したのか」を突き止める唯一の証拠となる。
—
結論:自動化は「防衛」から始まる
優れた自動化ツールとは、機能が多いことではない。「壊れないこと」だ。
複数人が触れる環境で、脆弱な設計のままVBAを走らせるのは、ブレーキのない車で高速道路を走るようなものだ。
このロック機構を導入し、競合の不安から解放された状態で、本来の価値創造に時間を使ってほしい。それが、世界最高峰の自動化エンジニアとしての私の提言だ。
さあ、コードを書いて、システムを「守り」に転じさせろ。
