【Project VBA極限解説】ベースライン設定時、「設定日時」をカスタムフィールドへ自動焼き付けする実務的アプローチ
開発現場のPMOやプロジェクトリーダー諸君。
スケジュール管理において「ベースラインの管理」は、プロジェクトの生命線だ。計画(Baseline)と実績(Actual)の乖離を正確に捉えなければ、プロジェクトの健康状態を測ることはできない。
しかし、Microsoft Projectの標準機能だけでは、「いつそのベースラインが引かれたのか」というタイムスタンプをタスクレベルでスマートに保持し、視覚化するには少し工夫が必要になる。
今回は、Project VBAを駆使して、ベースラインを設定した瞬間に「設定日時」をタスクのカスタムフィールドへ自動的に焼き付ける、堅牢かつ実務的なソリューションを伝授しよう。
—
1. なぜ標準機能だけでは不十分なのか?
Microsoft Projectには「ベースラインの保存」機能(`Edit -> Set Baseline`)が標準装備されている。プロジェクト全体、あるいは選択したタスクに対して一発でベースラインを引くことが可能だ。
しかし、プロジェクトが長期化し、スコープ変更やリスケジュールが発生すると、「このタスクのベースラインは、第1次計画のものか、それとも先週のリスケ時のものか?」という混乱が生じる。
ここにVBAによる自動化を介在させる。
ベースライン設定の操作をフック(あるいはラッパー)し、プログラム側で「いつベースラインを保存したか」のタイムスタンプを、指定したタスクのテキスト型カスタムフィールド(例: `Text1`)に自動書き込みするのだ。これにより、ガントチャート上でどのタスクがどのタイミングでベースライン化された一目瞭然となる。
—
2. 実務で絶対に守るべき設計思想
稚拙なマクロは、エラーハンドリングを怠り、プロジェクトファイルを破損させる。プロダクションコードとして耐えうるために、以下の設計思想を徹底する。
1. 明示的なオブジェクト修飾(`ActiveProject`の排除)
複数ウィンドウが開いている状況下で`ActiveProject`を信じてはならない。プロジェクトオブジェクトを確実に変数に格納し、スコープを明確にする。
2. エラー時のトランザクション的配慮
処理途中で予期せぬエラーが発生した場合でも、中途半端なデータ書き込みや予期せぬ状態を残さない。
3. パフォーマンスの最適化
数千行に及ぶエンタープライズ規模のプロジェクトファイルにおいて、画面描画(`ScreenUpdating`)や計算モード(`Calculation`)の制御は必須である。
—
3. 実装コード:ベースライン自動記録モジュール
以下のコードを、Microsoft ProjectのVBE(Visual Basic Editor)内の「標準モジュール」に配置してほしい。
Option Explicit
‘ ==============================================================================
‘ 処理名 : SetBaselineWithTimestamp
‘ 概要 : ベースラインを設定しつつ、対象タスクのカスタムフィールドに
‘ 現在日時をタイムスタンプとして自動書き込みするプロダクションコード
‘ ==============================================================================
Public Sub SetBaselineWithTimestamp()
Dim prj As Project
Set prj = ActiveProject
‘ 1. プロジェクトが開かれているか、タスクが存在するかを検証
If prj Is Nothing Then
MsgBox “有効なプロジェクトが開かれていません。”, vbCritical, “エラー”
Exit Sub
End If
If prj.Tasks.Count = 0 Then
MsgBox “対象となるタスクが存在しません。”, vbExclamation, “警告”
Exit Sub
End If
‘ 2. パフォーマンス最適化の呪文(画面描画と自動計算の停止)
‘ ※Project VBAにはApplication.ScreenUpdatingはないため、計算モード等を制御
Dim originalCalc As Long
originalCalc = Application.Calculation
Application.Calculation = pjManual
On Error GoTo ErrorHandler
‘ 3. ユーザーにベースライン番号を選択させる(通常はBaseline 0)
Dim blNum As Long
blNum = 0 ‘ 必要に応じてインプットボックス等で拡張可能
‘ 4. ベースラインの保存実行
‘ ここではプロジェクト全体のベースライン設定を例とする
prj.SaveBaseline Baseline:=blNum, All:=True
‘ 5. カスタムフィールド(Text1)へのタイムスタンプ焼き付け
Dim t As Task
Dim stampText As String
stampText = Format(Now, “yyyy/mm/dd HH:nn”)
Dim targetCount As Long
targetCount = 0
For Each t In prj.Tasks
‘ サマリータスクや削除済みタスクを除外する堅牢な判定
If Not t Is Nothing Then
If Not t.Summary Then ‘ 必要に応じてサマリーも含める場合は条件を変更
‘ まだベースラインが有効な(=工数等が入っている)タスクを対象とする
If t.Duration > 0 Then
t.Text1 = stampText
targetCount = targetCount + 1
End If
End If
End If
Next t
‘ 6. 変更の確定と通知
Application.Calculation = originalCalc
MsgBox “ベースラインの保存およびタイムスタンプの書き込みが完了しました。” & vbCrLf & _
“記録日時: ” & stampText & vbCrLf & _
“対象タスク数: ” & targetCount & “件”, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ 異常系のリカバリ
Application.Calculation = originalCalc
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error Description: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
—
4. コードの解説とチーフアーキテクトからの助言
① `Application.Calculation` の制御
エンタープライズ規模のMS Projectファイルで最も恐ろしいのは、タスクを1つ書き換えるたびに走るネットワーク全体・サマリータスクの再計算コストだ。数千行のループ内でこれをやると、処理が数分間フリーズする。
マクロ実行前に計算を手動モード(`pjManual`)に切り替え、処理後に元に戻すことで、爆速の実行速度を実現している。これがプロの仕事だ。
② サマリータスクと実タスクの分離
プロジェクトマネジメントにおいて、サマリータスク(親タスク)に直接リソースや独自のベースライン日時を刻むのはアンチパターンであることが多い。実作業を行うリーフタスク(子タスク)に絞って `t.Summary` を除外するロジックを入れることで、データの純度を保っている。
③ カスタムフィールド(Text1)の活用
ここで書き込んだ `Text1` を、ビューのガントチャート上に「カスタム列」として配置し、さらに「テキストの色やセル背景色の条件付き書式」と連動させてみせよ。
「直近1週間以内にベースラインが引かれたタスクはハイライト表示される」といった高度な視覚的ダッシュボードが、ノーコストで完成する。
—
5. まとめ
業務自動化の本質は、「ヒューマンエラーの排除」と「情報の透明化」にある。
今回紹介した仕組みを導入すれば、プロジェクトの監査や進捗会議において、「このタスクの計画はいつの時点のものか?」という不毛な議論を永遠に根絶することができる。
あなたの手元にあるProjectファイルを、ただのスケジュール表から「自律的に状態を語るスマートなデータベース」へと進化させてほしい。実装にあたって質問があれば、いつでもアーキテクトルームの扉を叩くがいい。
