【テクニカル・上級編】「サマリータスク」の依存関係を、配下の全タスクへ再帰的に反映させる一括設定ツール – Project VBA解析バイブル

スポンサーリンク

階層構造の呪縛を解く:Project VBAにおける「依存関係再帰展開」の極意

ProjectのWBS(Work Breakdown Structure)をVBAで制御する際、多くのエンジニアが直面する壁がある。それは、「サマリータスクに対するリンク設定は、配下のタスクに自動的には波及しない」というProjectの仕様だ。

サマリータスクを単なる「入れ物」として扱うか、それとも「プロジェクトの骨格」として動的に制御するか。この判断が、運用の安定性を左右する。今回は、再帰的アルゴリズムとProject Object Modelの深淵に触れ、配下の全タスクへ依存関係を強制同期させる「究極の同期エンジン」を構築する。

1. なぜ「再帰的な解決」が必要なのか

MS ProjectのUI上では、サマリータスクをリンクさせると、その開始日・終了日は配下のタスクの集計結果として自動計算される。しかし、API(VBA)で `Task.LinkPredecessors` を叩いても、その影響はサマリータスク単体に留まる。

大規模なプロジェクトにおいて、WBSの構造が頻繁に変更される環境下では、親のリンクを変更するたびに配下の末端タスク(子タスク)まで手動でメンテナンスするのは、もはや「管理」ではなく「苦行」だ。我々アーキテクトが目指すべきは、親の依存関係を起点とした、整合性の自動伝播である。

2. 実装の核心:再帰的探索とメモリの最適化

この処理において最も恐れるべきは、複雑なWBS構造下での「循環参照」と「メモリリーク」だ。特にVBAの `Task` オブジェクトは、参照するたびにメモリを消費するため、無闇なループはプロジェクトファイルを肥大化させ、動作を重くする。

以下のコードは、対象のサマリータスクを起点に、子タスクを再帰的に探索し、論理的な依存関係を書き込むエンジンだ。

‘ 依存関係再帰展開エンジン
Public Sub SyncDependencyRecursively(ByVal parentTask As Task, ByVal predecessorTask As Task)
Dim child As Task

‘ 1. エラーハンドリングと循環参照対策
On Error Resume Next

‘ 2. 現在の親タスクに先行タスクを設定
parentTask.Predecessors = predecessorTask.UniqueID

‘ 3. 子タスクが存在するか確認
If parentTask.OutlineChildren.Count > 0 Then
For Each child In parentTask.OutlineChildren
‘ 再帰呼出し
SyncDependencyRecursively child, predecessorTask
Next child
End If

‘ 4. オブジェクトの明示的解放(VBAにおけるメモリ管理の鉄則)
Set child = Nothing
End Sub

3. チーフアーキテクトからの忠告:パフォーマンスの最適化

上記のコードをそのまま実行して満足してはならない。大規模なプロジェクト(数千行規模)では、以下のチューニングを怠るとVBAの実行速度は極端に低下する。

  • `CalculationMode` の一時停止: 処理中にProjectの自動計算が走ると、リンクを張るたびに再計算が発生し、計算コストが爆発する。

Application.Calculation = pjManual ‘ 手動計算に切り替え
‘ …処理実行…
Application.Calculation = pjAutomatic ‘ 最後に再計算

  • イベントの抑制: `Application.EnableEvents = False` を活用せよ。不要なイベント発火を抑えるだけで、処理速度は数倍向上する。

4. Windows APIを活用したレガシー環境の堅牢化

もし、外部システム(ExcelやSQL Server)と連携しつつこのタスクを動かすなら、Projectの `DoEvents` だけでは不十分な場合がある。バックグラウンドでの同期が中断されないよう、Windows APIを用いてプロセスの優先度を調整するのも一手だ。

‘ Windows API宣言:プロセスの優先度を一時的に上げる
Private Declare PtrSafe Function SetPriorityClass Lib “kernel32” _
(ByVal hProcess As LongPtr, ByVal dwPriorityClass As Long) As Long
Private Declare PtrSafe Function GetCurrentProcess Lib “kernel32” () As LongPtr

Private Const HIGH_PRIORITY_CLASS = &H80

‘ メイン処理前に呼び出す
Public Sub BoostPerformance()
SetPriorityClass GetCurrentProcess, HIGH_PRIORITY_CLASS
End Sub

結論:自動化の先にあるもの

この再帰的同期エンジンは、ツールに過ぎない。しかし、このツールを組み込むことで、現場のPMが「WBSの整合性」という呪縛から解き放たれ、本来注力すべき「プロジェクトの価値最大化」にリソースを割けるようになる。

VBAは、今なおレガシーの皮を被った強力な武器だ。メモリの断片化を恐れず、オブジェクトのライフサイクルを制御し、Projectの深層を掌握せよ。これこそが、我々が守り続けるべき「自動化の美学」である。


追伸:もし実行時に `Automation Error` が頻発するなら、それはProjectのタスクIDが再割当された後のキャッシュが原因だ。`Project.Task.UniqueID` を常に参照し、タスクのインデックス変動に左右されない堅牢なID体系を維持することを忘れるな。

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