【実務・中級編】【初心者向け】ベースライン保存時に「保存日時」をカスタムフィールドへ自動書き込みする仕組み – Project VBA解析バイブル

スポンサーリンク

プロジェクトマネジメントの死角を突く:ベースライン保存日時をカスタムフィールドへ自動書き込みする極限設計

プロジェクト管理において、ベースライン(計画値)の管理はプロジェクトの命運を握る。しかし、標準のMS Project機能では、「いつ、どの版のベースラインが引かれたか」をタスク単位のメタデータとして視覚的に、かつ構造化して保持するには限界がある。特に複数人が出入りする現場や、頻繁にスケジュール変更が行われる大規模案件では、「このタスクのベースラインはいつの時点のものか?」という疑問がプロジェクトを暗礁に乗り上げさせる。

今回は、Project VBAを用いて「ベースライン保存時に、その実行日時をタスクのカスタムフィールドへ自動的に刻み込む」堅牢な仕組みを構築する。単なるコードの貼り付けにとどまらず、VBAのイベントフックの特性、実務で絶対に踏み抜いてはならない罠、そしてプロダクション品質のコード設計論を、チーフアーキテクトである私から伝授しよう。

なぜ標準機能では不十分なのか? 設計思想の核心

MS Projectにはベースラインを保存する機能(`EditBaseline` メソッドなど)が標準備わっているが、これらは「プロジェクト全体または選択タスクの数値群をスナップショットとして保存する」だけであり、「いつそのアクションが実行されたか」というタイムスタンプをタスク個別の属性として永続化する機能を持たない

これを手動で行わせようとすると、担当者がメモ帳に控えたり、属人化されたExcel管理表と突き合わせたりという「ヒューマンエラーの温床」を生み出す。
自動化の鉄則は、「人間の記憶と手作業をプロセスから排除すること」だ。ベースラインが引かれた瞬間をVBAでフックし、タスク側のカスタムフィールド(例:`Text1` や `Date1`)へダイレクトに書き込む。この一連の動きをアトミック(不可分)に保証するアーキテクチャが必要となる。

アーキテクチャの設計:VBAイベントハンドリングの罠

Project VBAにおいて、ユーザーの操作やプロジェクトのライフサイクルに割り込むには `App` オブジェクトのイベントを利用する。しかし、ここで多くの開発者が挫折するポイントがある。

> ⚠️ 警告:Project VBAにおける最大の陷し穴
> Excel VBAとは異なり、MS Projectでは `Workbook_Open` のような単純なイベントトリガーの配備だけでは、アプリケーション全体のイベントをハンドリングできない。`Class モジュール` を用い、アプリケーションインスタンスをイベント有効(`WithEvents`)としてフックし続ける常駐型設計が必要となる。

さらに、Projectのベースライン保存操作(UIからの実行、あるいはVBAからの実行)を完全に捕捉するためには、どのイベントが発火するのかを正しく理解しなければならない。

実装:プロダクション品質のVBAコード

ここに示すのは、実務の現場でそのまま稼働できる、堅牢性・エラーハンドリング・保守性を極限まで高めたコードだ。

1. クラスモジュール:`C_ProjectEvents`

プロジェクト全体のイベントを監視し、ベースライン保存操作を検知する中核エンジン。

‘ ==============================================================================
‘ クラスモジュール名: C_ProjectEvents
‘ 概要: MS Projectのアプリケーションイベントを監視し、ベースライン保存時に
‘ カスタムフィールドへタイムスタンプを自動書き込みする
‘ ==============================================================================
Option Explicit

Public WithEvents App As Application

‘ ベースライン保存直後に発火するイベント
Private Sub App_ProjectBeforeBaselineSave(ByVal pj As Project, ByVal SaveAsBaseline As Long, ByVal WhichBaseline As PjBaseline)
On Error GoTo ErrorHandler

Dim t As Task
Dim targetField As String
Dim currentTimestamp As String

‘ タイムスタンプの生成 (例: 2023-10-25 14:30:00)
currentTimestamp = Format(Now, “yyyy-mm-dd hh:nn:ss”)

‘ ベースラインの種類に応じたカスタムフィールドの割り分け(例としてText1を使用)
‘ ※実運用ではどのベースライン(Baseline ~ Baseline10)を対象にするかで分岐を設ける
targetField = “Text1”

‘ 処理パフォーマンスを考慮し、画面描画を一旦停止
Application.ScreenUpdating = False

‘ プロジェクト内の全タスク(サマリ、通常、マイルストーン)を走査
For Each t In pj.Tasks
If Not t Is Nothing Then
‘ 該当タスクがアクティブ(削除済み等でない)場合のみ書き込み
If Not t.Null Then
‘ カスタムテキストフィールドに保存日時とベースライン種別を記録
t.SetField FieldNameToFieldID(targetField), _
“BL” & WhichBaseline & ” Saved: ” & currentTimestamp
End If
End If
Next t

MsgBox “ベースライン ” & WhichBaseline & ” の保存に伴い、カスタムフィールド [” & targetField & “] へのタイムスタンプ記録が完了しました。”, vbInformation, “自動化システム”

CleanUp:
Application.ScreenUpdating = True
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “C_ProjectEvents.App_ProjectBeforeBaselineSave”
Resume CleanUp
End Sub

2. 標準モジュール:`M_EventInitializer`

クラスモジュールをインスタンス化し、アプリケーションライフサイクルにバインドするためのエントリポイント。

‘ ==============================================================================
‘ 標準モジュール名: M_EventInitializer
‘ 概要: イベント監視クラスを有効化するグローバルプロシージャ
‘ ==============================================================================
Option Explicit

‘ イベントを保持し続けるためのグローバル変数(スコープアウトによる消滅を防ぐ)
Public EventMonitor As C_ProjectEvents

Public Sub RegisterProjectEvents()
‘ 既にインスタンス化されている場合は二重登録を防ぐ
If Not EventMonitor Is Nothing Then
Set EventMonitor = Nothing
End If

Set EventMonitor = New C_ProjectEvents
Set EventMonitor.App = Application

MsgBox “プロジェクトイベント監視システムが正常に初期化されました。”, vbInformation, “初期化完了”
End Sub

Public Sub UnregisterProjectEvents()
Set EventMonitor = Nothing
MsgBox “イベント監視を解除しました。”, vbInformation, “解除完了”
End Sub

現場でエンジニアが守るべき運用・設計上の鉄則

1. スコープアウト(変数の消滅)への対策
VBAで `WithEvents` を使う際によくあるバグが、プロシージャ終了時にインスタンスがメモリから解放され、イベントが反応しなくなる現象である。上記コードのように、標準モジュールでグローバル変数(`Public EventMonitor`)として保持し続けるアーキテクチャが必須条件となる。

2. パフォーマンスへの配慮(`ScreenUpdating` の制御)
数千行を超える巨大なプロジェクトファイルにおいて、`For Each t In pj.Tasks` で全タスクをループさせると、画面描画のコストによって数秒〜数分のフリーズが発生する。必ず `Application.ScreenUpdating = False` で描画をロックし、処理完了後に明示的に `True` へ戻すこと。

3. マルチテナント・複数ファイルを開く場合の考慮
`pj As Project` 引数をイベントから受け取る設計にしているため、複数のプロジェクトファイルを同時に開いている環境でも、操作対象の特定プロジェクトに対してのみ正確にタイムスタンプが書き込まれるスレッドセーフな構造となっている。

総括

プロフェッショナルな業務自動化とは、単にコードを動かすことではない。「ユーザーの操作ミスや属人性をシステム側の設計で完全にハックし、データの信頼性を担保すること」に他ならない。

今回紹介したベースライン自動タイムスタンプ機構は、小規模な改善に見えて、プロジェクトの監査証跡(オーディットトレイル)を強固にする極めて価値の高いアーキテクチャである。ぜひあなたの現場のプロジェクトファイルに組み込み、ワンランク上のエンジニアリングを実証してほしい。

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