Project VBAを掌握する極限の知見:プロジェクト開始日を基準とした全タスクASAP一括変換エンジン
開発現場において、Microsoft Project(MSP)のスケジュール計算エンジンを制御することは、プロジェクトマネジメントの成否を握る核心である。
実務で最も頻発する悪夢の一つが、前任者が場当たり的に設定した「MFO(Mandatory Finish On)」や「SNET(Start No Earlier Than)」などの多様な制約条件が入り交じり、計画変更のたびにスケジュールが崩壊する現象だ。このカオスを浄化するため、プロジェクト開始日を基点として、すべてのタスクをASAP(できる限り早く:As Soon As Possible)制約へ強制かつ安全に統一するクレンジングツールをVBAで構築する。
本稿では、表面的なオブジェクト操作の解説にとどまらず、MSPのスケジューリングの挙動、COMインターフェースの重み、そしてプロダクション環境で耐えうる堅牢な設計思想を叩き込む。
—
1. なぜ「力技の全タスク変換」はバグを生むのか
素朴な開発者は、次のようなコードを書く。
‘ 【アンチパターン】思考停止の全タスク一括変換
Dim t As Task
For Each t In ActiveProject.Tasks
t.ConstraintType = pjConstraintASAP
Next t
このコードは実務では使い物にならない。 理由を挙げよう。
1. サマリータスク(Summary Task)の存在:
MSPにおいて、サマリータスクは子タスクの集計値であり、手動で制約を設定すべきではない(あるいは読み取り専用に近い挙動を示す)。ここに制約を強制するとエラー、または予期せぬスケジュールの歪みが発生する。
2. マイルストーン(Milestone)の保護:
意図的な「Fnet(Finish No Earlier Than)」などが設定されている重要マイルストーンまでASAPに丸めてしまうと、納期のコミットメントがスコープから外れる。
3. 計算エンジンの多重発火(パフォーマンスの劣化):
タスクを1つ変更するたびにMSPのスケジュール計算エンジンが走る。数千行のプロジェクトでこれをやると、画面がフリーズするか、途中でCOM例外(Error 1100など)でクラッシュする。
したがって、プロダクションコードでは「対象外の除外フィルタリング」「計算エンジンの一時停止(またはバッチ処理的アプローチ)」を完璧に実装する必要がある。
—
2. 堅牢な設計のためのアーキテクチャ方針
今回のクレンジングエンジンが満たすべき要件を定義する。
- 安全性の担保: サマリータスク、外部タスク、および特定フラグ(例: ユーザー定義フィールドでロックされたタスク)を自動除外する。
- 基点日の整合性: プロジェクトの開始日(ProjectStart)を取得し、それを論理的な基準として整合性を保つ。
- トランザクション的思考: 処理中の画面描画を停止し、計算コストを極限まで削減する。
—
3. プロダクションコード:ASAP一括変換クレンジングエンジン
以下のコードは、エラーハンドリング、オブジェクトのライフサイクル管理、MSP特有の罠を回避するための実践的なVBAモジュールである。
Option Explicit
‘ =========================================================================
‘ 模块名: clsASAPConverter (または標準モジュールとしての記述)
‘ 概要: プロジェクト内の全有効タスクの制約をASAPに安全に一括変換する
‘ =========================================================================
Public Sub ConvertAllTasksToASAP()
Dim prj As Project
Set prj = ActiveProject
‘ 1. 事前検証:プロジェクトが有効か
If prj.Tasks.Count = 0 Then
MsgBox “対象となるタスクが存在しません。”, vbExclamation, “処理中断”
Exit Sub
End If
‘ 2. ユーザー確認(不可逆な変更を伴うため)
Dim confirmMsg As String
confirmMsg = “警告: この操作はプロジェクト内の全通常タスクの制約条件を” & vbCrLf & _
“「できる限り早く (ASAP)」に強制変更します。” & vbCrLf & _
“プロジェクト開始日: ” & prj.ProjectStart & vbCrLf & vbCrLf & _
“実行しますか?”
If VbMsgBoxResult.vbYes <> MsgBox(confirmMsg, vbYesNo + vbExclamation, “ASAP一括クレンジング”) Then
Exit Sub
End If
‘ 3. パフォーマンスと安定性のための環境設定
‘ ※MS Projectでは ScreenUpdating のようなグローバルプロパティはないが、
‘ 大規模データ処理時はエラートラップとイベント制御が鍵となる。
On Error GoTo ErrorHandler
Dim t As Task
Dim processedCount As Long
Dim skippedCount As Long
processedCount = 0
skippedCount = 0
‘ 処理の高速化のため、ステータスバーにメッセージを表示
Application.StatusBar = “ASAP制約への変換処理を実行中…”
‘ 4. メインループ
For Each t In prj.Tasks
‘ 存在しないタスク(削除されたインデックス等)のスキップ
If Not t Is Nothing Then
‘ 除外条件の判定:
‘ ① サマリータスク (Summary = True)
‘ ② 外部プロジェクトのタスク (ExternalTask = True)
‘ ③ 既に削除されている、またはマイルストーンで固定すべきもの(必要に応じて拡張)
If t.Summary Then
‘ サマリータスクはスケジュールエンジンが自動管理するため除外
skippedCount = skippedCount + 1
ElseIf t.ExternalTask Then
‘ 外部タスクは編集不可のため除外
skippedCount = skippedCount + 1
Else
‘ 制約条件をASAPに変更
‘ ※MSPのVBAでは pjConstraintASAP を指定
On Error Resume Next
t.ConstraintType = pjConstraintASAP
If Err.Number = 0 Then
processedCount = processedCount + 1
Else
‘ 個別タスクの書込み保護エラー等はスキップしてログに残す等の処理
skippedCount = skippedCount + 1
Err.Clear
End If
On Error GoTo ErrorHandler
End If
End If
Next t
‘ 後処理
Application.StatusBar = “”
MsgBox “クレンジングが完了しました。” & vbCrLf & _
“・変換成功タスク数: ” & processedCount & vbCrLf & _
“・除外/スキップ数: ” & skippedCount, _
vbInformation, “処理完了”
Exit Sub
ErrorHandler:
Application.StatusBar = “”
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error: ” & Err.Description & ” (Code: ” & Err.Number & “)”, _
vbCritical, “致命的なエラー”
End Sub
—
4. 実務運用上の注意点:データベース連携とファイル管理
このスクリプトを組織の標準ツールとして組み込む場合、単体での動作確認だけでは不十分である。以下のインフラ的制約に注意せよ。
① Project Server / Project Online(PWA)環境での権限とチェックアウト
Enterprise環境(Server/Online)において、全タスクの書き換えは「チェックアウト(Checkout)」が必須となる。また、Globalテンプレートに干渉するようなマクロ配置は避け、ローカルアドイン( `.bas` や `.ppam` / 専用エンタープライズアドイン)として配布し、実行時に対象プロジェクトが排他制御されていることを確認させるべきだ。
② 計算モード(Calculation Mode)の制御
大規模なスケジュールデータに対し、デフォルトで自動計算(Automatic Calculation)が有効な状態でプロパティを書き換えると、タスク1行ごとにクリティカルパスの再計算が走り、極端なパフォーマンス劣化を招く。
必要に応じて、処理の冒頭で `Application.Calculation = pjManual` に切り替え、処理終了後に `pjAutomatic` に戻して手動で再計算 (`CalculateProject`) を走らせるアーキテクチャを採用すると、実行速度を何倍にも跳ね上げることができる。
—
最後に:VBAエンジニアとしての誇り
「動けばいい」という妥協の産物は、複雑なプロジェクト計画の現場において必ず巨大なバグとなってしっぺい返しを食らう。タスクのライフサイクル、スケジューリングエンジンの挙動、そして例外処理の網羅性。これらを深く理解した上でコードを書く者だけが、現場の信頼を勝ち得ることができる。
あなたの書いたそのスクリプトは、単なるコード片ではない。プロジェクトの未来のスケジュールを美しく整える、精緻なエンジニアリングそのなのだ。
