【実務・中級編】【上級プロ】Taskの「ConstraintType」を動的に変更した際のスケジュール再計算をVBAで制御する – Project VBA解析バイブル

スポンサーリンク

【上級プロ】Taskの「ConstraintType`」を動的に変更した際のスケジュール再計算をVBAで制御する

開発プロジェクトの現場で、MS ProjectのVBAを用いた大規模なスケジュール一括更新ツールを構築した際、多くのエンジニアが一度は泥沼にはまるポイントがある。それが `Task.ConstraintType`(制約の種類)の動的変更とスケジュール再計算のコントロール だ。

「コードを書いたのにタスクの日付が意図通りに動かない」
「一括変更の途中で計算が走り、処理が重くてフリーズする」
「制約を外した瞬間にクリティカルパスが崩壊した」

これらは、MS Projectのオブジェクトモデルのライフサイクルと、計算エンジン(Calculation Engine)の挙動を無視して単にプロパティを書き換えていることが原因である。

今回は、数万行規模の工程表を自在に操る開発リーダーに向けて、MS Project VBAの深層メカニズムを紐解きながら、バグを1ミリも生み出さない堅牢なスケジュール制御アーキテクチャを伝授する。

1. なぜ「制約の動的変更」は一筋縄ではいかないのか?

MS Projectの内部エンジンは、タスクのプロパティ(`Start`, `Finish`, `ConstraintType`, `ConstraintDate`など)が変更されるたびに、依存関係(Predecessors/Successors)を辿ってネットワーク全体の再計算をバックグラウンドで走らせようとする。

これを「自動計算モード(Automatic Calculation)」のままVBAからループ処理でガリガリ書き換えると、以下の致命的な問題が発生する。

1. パフォーマンスの著しい劣化:1回の代入ごとに全体再計算が走るため、O(N^2)に近いオーダーで処理時間が爆発的に増大する。
2. 予期せぬ日付の固定(意図しない制約の競合):例えば、「できるだけ早く(ASAP)」に変えようとした瞬間、先行タスクの制約との兼ね合いで一時的に矛盾が生じ、Projectが勝手に日付を丸めてしまう。
3. UNDOスタックの肥大化とメモリリーク:トランザクションを意識しない操作は、最悪の場合ファイル破損を招く。

究極の解決アプローチ

この課題を突破する鉄則は、以下の3ステップに集約される。

1. 計算エンジンの完全掌握:一括処理の間は、アプリケーションレベルで計算を一時停止(または手動モードへ移行)する。
2. トランザクション的アプローチ:依存関係の深いタスク群に対して、適切な順序(通常はWBSの階層順、あるいは依存関係の上流から下流)でプロパティを流し込む。
3. 明示的な再計算と整合性チェック:処理の最後に一度だけ計算を走らせ、エラーがないか検証する。

2. 実務で使える堅牢なプロダクションコード

以下のコードは、プロジェクト内の特定条件に合致するタスク群の制約を一括して変更し、スケジュールが崩壊しないよう安全に再計算をコントロールする実用プロシージャである。

エラーハンドリング、トランザクション、アプリケーションの描画・計算制御を完璧に網羅したプロ仕様のコードだ。

Option Explicit

‘ ==============================================================================
‘ 処理名: 堅牢なタスク制約変更とスケジュール再計算制御エンジン
‘ 概要 : 画面描画と自動計算を完全にロックした状態で制約を一括変更し、
整合性を保ったまま再計算を実行する。
‘ ==============================================================================
Sub ApplyConstraintSafely()
‘ 1. 宣言フェーズ
Dim prj As Project
Set prj = ActiveProject

Dim tsk As Task
Dim targetConstraint As Long

‘ 例として「できるだけ早く (ASAP)」を設定する場合
‘ pjAsap = 0, pjAlap = 1, pjMustStartOn = 2, pjMustFinishOn = 3,
‘ pjSnet = 4, pjSneat = 5, pjFnet = 6, pjFneat = 7
targetConstraint = pjAsap

‘ 2. パフォーマンス&計算エンジンの保護(環境退避)
Dim originalCalc As Boolean
originalCalc = Application.Calculation

On Error GoTo ErrorHandler

‘ 画面描画と自動計算を停止(これがプロの常識)
ScreenUpdating False
Application.Calculation = pjCalculationManual

‘ 3. トランザクション処理(データ操作)
Dim modifiedCount As Long
modifiedCount = 0

For Each tsk In prj.Tasks
‘ 念のためNULLタスク(削除済み等)をスキップ
If Not tsk Is Nothing Then
‘ サマリータスク(要約タスク)は制約変更の対象外とする場合
If Not tsk.Summary Then

‘ 特定の条件(例: リソースがアサインされている等)を満たす場合のみ変更
If tsk.ResourceNames <> “” Then

‘ 制約タイプの変更
tsk.ConstraintType = targetConstraint

‘ 必要に応じて制約日付をクリア(ASAP/ALAPの場合は日付が不要なため)
If targetConstraint = pjAsap Or targetConstraint = pjAlap Then
‘ 注: ConstraintDateにNAを設定する場合はVariant型で渡す
tsk.ConstraintDate = “NA”
End If

modifiedCount = modifiedCount + 1
End If

End If
End If
Next tsk

‘ 4. 計算エンジンの復旧と強制再計算
Application.Calculation = originalCalc

‘ プロジェクト全体の再計算を実行
CalculateAll

‘ 5. 正常終了処理
ScreenUpdating True
MsgBox “制約の変更が完了しました。” & vbCrLf & _
“処理対象タスク数: ” & modifiedCount & ” 件”, vbInformation, “完了”
Exit Sub

ErrorHandler:
‘ 異常終了時のフェイルセーフ
ScreenUpdating True
Application.Calculation = originalCalc ‘ 必ず計算モードを戻す

MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “致命的エラー”

End Sub

3. コードのキモ:プロが解説するアーキテクチャの解説

① `Application.Calculation = pjCalculationManual` の重要性

ループ内で `tsk.ConstraintType` を変更するたびにProjectは「この変更が後続にどう影響するか」を計算しようとする。これを手動モード(Manual)に落とすことで、メモリ上のデータ書き換えだけに専念させ、処理速度を数十倍〜数百倍に跳ね上げる。

② `CalculateAll` による一括評価

手動モードで一連の書き換えを行った後、最後に `CalculateAll` を呼び出す。これにより、トポロジカル・ソート(依存関係の順序解決)に基づいたネットワーク全体のクリティカルパス計算が一度だけ走るため、矛盾のないクリーンなスケジュールが生成される。

③ `ScreenUpdating False` との組み合わせ

UIの描画更新も同時に止めることで、Windowsメッセージキューの溢れを防ぎ、数万件規模のタスクを扱う巨大なEnterprise Project (Project Server / Project Online連携案件含む) でも安定した動作を実現する。

4. ファイル・データベース連携における実務上の注意点

この手の自動化ツールを実際の業務(Excel連携、SQL Serverからのインポート、ERPとのバッチ連携など)に組み込む場合、以下の罠に注意せよ。

  • マイルストーンと制約の衝突

マイルストーンタスクに対して無理な制約(例: `pjMustFinishOn`)をプログラムから流し込むと、実績工数(Actuals)や進捗状況(% Complete)とコンフリクトを起こし、Project側でエラーフラグが立つ。データベースから値を流し込む際は、タスクの種別(通常タスクかマイルストーンか)に応じたバリデーションをVBA側で必ず挟むこと。

  • Server/Online環境でのチェックアウト状態

Project ServerやProject Online(Project Web App)環境でこのマクロを動かす場合、ローカルキャッシュとの同期ズレが起きやすい。必ず `FileCheckOut` メソッド等で明示的にロックを取得した状態でトランザクションを回し、処理後に適切なチェックインを行わせる設計にすること。

総括

VBAにおけるMS Project制御は、単なる「Excelマクロの延長」ではない。プロジェクトマネジメントの数理モデル(CPM: クリティカルパス法)を理解した上で、「いつ計算させ、いつ計算を止めるか」をエンジニアが完全にコントロールしなければならない。

今回伝授した知見を実装に組み込めば、どれほど複雑な大規模工程表であっても、エラーなく一瞬で正確なスケジュールを再計算する極めて堅牢な自動化ツールが完成するはずだ。現場の信頼を勝ち取るプロフェッショナルとして、ぜひ活用してほしい。

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