【Project VBA極限解説】共有MS Projectを「読み取り専用トラップ」から解放する!別名保存&編集自動化の全貌
開発の現場において、複数メンバーでMicrosoft Project(mpp)のスケジュールを共有する際、最も生産性を低下させる要因は何か知っているか?
それは、「他のユーザーがすでに開いているため、読み取り専用でしか開けない」という警告ダイアログだ。
この罠に引っかかり、慌てて「別名で保存」し忘れて作業を進めた結果、最新のマスターデータに上書きできず、変更がコンフリクトして消滅する――。この絶望的なヒューマンエラーを、現場の根性論で防ごうなどと考えるのは今日で終わりにしよう。
今回は、Project VBAのオブジェクトモデルとライフサイクルを熟知したアーキテクトの視点から、「読み取り専用で開いたプロジェクトを検知し、瞬時にローカル作業用ファイルとして別名保存した上で、シームレスに編集作業へ移行する自動化フロー」を実装レベルで徹底解説する。
—
1. なぜ「手動の別名保存」は破綻するのか?
実務でよく見かける光景だが、共有サーバー上のマスターファイルをVBAから直接開かせようとする設計は、マルチユーザー環境において百害あって一利なしだ。
- 排他制御の壁: 誰かが開いている状態で開くと、VBAの `FileOpen` メソッドすらエラーを吐くか、意図せず読み取り専用でアタッチされる。
- ライフサイクルの誤認: 「読み取り専用」で開かれたProjectオブジェクトをそのまま操作し続け、最後に `ActiveProject.Save` を叩いた瞬間、悲劇的なエラーが発生する。読み取り専用ファイルへの上書き保存は拒絶されるからだ。
【正しいアプローチ】
マスターファイルは常に「参照用」の安全な聖域とし、VBAの起動フック、あるいは独立したランチャーから読み取り専用で安全にロード。それを即座にローカルの作業用ディレクトリへタイムスタンプ付きでクローン(別名保存)し、操作対象のコンテキストを瞬時にローカルファイルへ切り替える。これがプロのエンジニアリングだ。
—
2. 堅牢な自動化フローの設計思想
今回構築するルーチンの要件定義は以下の通りである。
1. パスの動的解決: 共有サーバーのマスターパスと、個人のローカル作業ディレクトリを環境に合わせて自動生成する。
2. 排他・状態チェック: 読み取り専用(ReadOnly)で開かれたことを確実に検知する。
3. 安全なクローン生成: 既存の同名ファイルとの競合を防ぐため、一意のファイル名(またはタイムスタンプ付与)で別名保存を行う。
4. オブジェクトのコンテキスト切替: 保存完了後、元ファイルを閉じ、新しく保存したローカルファイルを編集モードで再オープン、あるいはアクティブ化する。
—
3. プロダクションコード実装
以下のコードは、エラーハンドリングを完備し、実際の開発現場でそのままコピペして即戦力となるプロダクションコードだ。標準モジュールに配置して実行せよ。
Option Explicit
‘ ==============================================================================
‘ 処理名: 共有マスタープロジェクトを読み取り専用で取得し、ローカル作業用として別名保存するルーチン
‘ アーキテクトノート:
‘ マルチユーザー環境における競合を完全に排除し、安全なローカルワークスペースを
‘ 1アクションで構築するための実用的なエンタープライズコード。
‘ ==============================================================================
Sub InitializeLocalWorkingProject()
‘ ————————————————————————–
‘ 1. 定数定義(実際の運用環境のパスに合わせて書き換えてください)
‘ ————————————————————————–
Const MASTER_FILE_PATH As String = “\\ServerName\ProjectShare\MasterSchedule.mpp”
Dim localWorkDir As String
Dim localFilePath As String
Dim targetProject As Project
Dim originalName As String
‘ エラーハンドリングの有効化
On Error GoTo ErrorHandler
‘ ————————————————————————–
‘ 2. ローカル作業ディレクトリのパス構築
‘ ————————————————————————–
‘ ユーザーのドキュメントフォルダ等を取得して安全なワークスペースとする
localWorkDir = Environ(“USERPROFILE”) & “\Documents\ProjectWorkSpace\”
‘ フォルダが存在しない場合は自動生成する
If Dir(localWorkDir, vbDirectory) = “” Then
MkDir localWorkDir
End If
‘ タイムスタンプを付与したローカル作業用ファイル名の生成(コンフリクト防止)
‘ 例: MasterSchedule_20231025_143000.mpp
Dim timeStamp As String
timeStamp = Format(Now, “yyyymmdd_hhnnss”)
localFilePath = localWorkDir & “WorkingSchedule_” & timeStamp & “.mpp”
‘ ————————————————————————–
‘ 3. マスターファイルを読み取り専用で安全にオープン
‘ ————————————————————————–
‘ すでに誰かが開いていても「ReadOnly:=True」を指定することで確実にオープン
MsgBox “共有マスターからスケジュールを読み込んでいます…”, vbInformation, “自動化フロー実行中”
FileOpenEx Name:=MASTER_FILE_PATH, ReadOnly:=True
‘ アクティブになったプロジェクトをオブジェクト変数に格納
Set targetProject = ActiveProject
‘ ————————————————————————–
‘ 4. 読み取り専用の判定と別名保存(クローン生成)の実行
‘ ————————————————————————–
If targetProject.ReadOnly Then
Debug.Print “Info: ファイルは読み取り専用で開かれました。ローカルへの別名保存を開始します。”
‘ 別名で保存(ProjectのFileSaveAsメソッドを使用)
‘ ※PJFileFormatMppは標準のmpp形式を指定
FileSaveAs Name:=localFilePath, FormatID:=”MSProject.mpp”
MsgBox “共有ファイルが競合しているため、以下のローカル作業用ファイルを作成しました。” & vbCrLf & _
localFilePath, vbInformation, “ローカル作業モードへ移行”
Else
‘ 奇跡的に誰も開いておらず、書き込み可能で開けた場合でも、
‘ マスターへの直接誤操作を防ぐためにローカルへ保存させる安全設計
Debug.Print “Info: 書き込み権限で開かれましたが、安全のためローカルへ別名保存します。”
FileSaveAs Name:=localFilePath, FormatID:=”MSProject.mpp”
‘ 元の読み取り専用(または一時オープン)だった不要なウィンドウを閉じる
‘ (必要に応じて実装。今回はシンプルにローカルファイルを正とする)
End If
‘ ————————————————————————–
‘ 5. 後処理・正常終了
‘ ————————————————————————–
Set targetProject = Nothing
Exit Sub
ErrorHandler:
‘ 異常系ハンドリング
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error Description: ” & Err.Description, vbCritical, “致命的なエラー”
Set targetProject = Nothing
End Sub
—
4. コードの核心:アーキテクトからの技術解説
このコードが「なぜ現場でバグを起こさないのか」、その技術的根拠を3点に絞って解説する。
① `FileOpenEx` と `ReadOnly:=True` の明示的制御
標準の `FileOpen` ではなく、拡張版である `FileOpenEx` を用いることで、明示的に読み取り専用モードでのオープンを強制している。これにより、VBA実行時に予期せぬダイアログ(「他のユーザーが編集中です。どうしますか?」)で処理がフリーズする現象を完全にハック(回避)している。
② タイムスタンプによるデッドロックの回避
複数名が同時にこの自動化ツールを実行した際、ローカルのファイル名が固定だとファイル競合やアクセス拒否エラーを引き起こす。`Format(Now, “yyyymmdd_hhnnss”)` を用いて一意のファイル名を動的生成することで、「何人たりとも他のセッションと衝突しない」堅牢なロジックを担保している。
③ 環境変数への依存によるパスの堅牢性
`Environ(“USERPROFILE”)` を使用している点に注目してほしい。ハードコーディングされた `C:\Users\Yamada\…` のようなパスは、担当者が変わった瞬間に破綻する。Windowsの環境変数を動的に叩くことで、どの端末で実行されても確実に書き込み権限のあるユーザー領域を確保できる。
—
5. おわりに:真の自動化とは「事故の芽を摘むこと」
業務効率化ツールを作る際、初心者は「いかに楽に作業を終わらせるか」ばかりに目が行きがちだ。しかし、真のプロフェッショナルは「いかにユーザーがミスをする隙を与えないか」を設計の軸に置く。
今回紹介した別名保存の自動化フローを組み込むことで、ユーザーは「うっかりマスターを上書きしてチーム全員のスケジュールを破壊する」という悪夢から永遠に解放される。
あなたのプロジェクトにこの知見を導入し、泥臭い手動運用を今すぐ過去のものにしてほしい。
