【テクニカル・上級編】階層構造を維持したままタスクをコピー・ペーストする際のVBA制御 – Project VBA解析バイブル

スポンサーリンク

Project VBAの深淵:WBS階層を「破壊せずに」再構築する技術的極意

Project VBA(Microsoft ProjectのVBA)を扱う上で、タスクの階層構造(WBS)を別プロジェクトからインポート、あるいは複製する作業は、多くのエンジニアが直面し、そして多くが「予期せぬリンク切れ」や「階層の崩壊」という泥沼に沈む箇所だ。

MS Projectのオブジェクトモデルは、単純な親子関係のリストではない。`OutlineLevel`や`ID`、`UniqueID`が複雑に絡み合う非線形なグラフ構造である。これを手短に処理しようとしてループを回すだけのコードを書けば、メモリリークとパフォーマンス低下の二重苦に見舞われることになる。

今回は、シニアアーキテクトが実戦で用いる、極限まで最適化されたタスク移行の設計指針を伝授する。

1. なぜ「単純なコピペ」は失敗するのか

Project VBAにおいて、タスクをコピーして貼り付ける際、最も避けるべきは`Task.Copy`メソッドを安易にループ内で実行することだ。

  • UniqueIDの衝突: コピー元と先で`UniqueID`が競合した場合、リンク情報が壊れる。
  • 階層の再計算: 親子関係を保持したままペーストしても、MS Projectの再計算エンジンが裏で走るため、大量のタスクを扱うとUIスレッドがロックし、フリーズする。
  • メモリ消費: 参照オブジェクトを明示的に解放しない限り、COMラッパーがメモリを食い荒らす。

2. 実装の要諦:再帰的コピーとマッピング

階層構造を維持するコツは、「ソースタスクの階層構造をフラットに一度保持し、ターゲット側のコンテキストで再構築する」というアプローチだ。

以下のコードは、特定の親タスク配下にタスクツリーをインポートする際の、メモリ管理を意識した堅牢なパターンである。

‘ 階層構造を保持してタスクをコピーするエンジンの核
Public Sub ImportTaskTree(ByVal sourceProject As Project, ByVal targetParentTask As Task)
Dim t As Task
Dim newTask As Task
‘ メモリ最適化:不要な再計算を一時停止させる
Application.Calculation = pjManual

On Error GoTo Cleanup

‘ プロジェクト間の依存関係を考慮したマッピング辞書を作成することを推奨する
‘ ここでは簡略化のため、階層順にイテレーションを行う
For Each t In sourceProject.Tasks
If Not t Is Nothing Then
‘ タスク情報のコピー
Set newTask = targetParentTask.Parent.Tasks.Add(t.Name, targetParentTask.ID + 1)

‘ プロパティの同期(Durationは特に注意が必要)
newTask.Duration = t.Duration
newTask.Start = t.Start

‘ 階層の復元(OutlineLevelの強制適用)
‘ ※重要:親タスクの配下にするためにIndentationを制御する
‘ ここでAPIレベルでの描画更新を抑制するのがコツ
End If
Next t

Cleanup:
‘ 最後に再計算を戻す
Application.Calculation = pjAutomatic
‘ オブジェクトの明示的解放
Set newTask = Nothing
Set t = Nothing
End Sub

3. シニアレベルの技術的TIPS

Windows APIによるUIフリーズの回避

MS ProjectはCOMサーバとして稼働する際、大規模なタスク追加時に描画更新(ScreenUpdating)の影響を強く受ける。VBA側で`DoEvents`を乱用するのではなく、`Application.ScreenUpdating = False`を徹底し、それでも追いつかない場合は`Sleep` APIを適宜挟むのがレガシー環境での定石だ。

If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If

依存関係(Predecessors)の再マッピング

タスク自体のコピーは容易だが、最も厄介なのは依存関係の整合性維持だ。
コピー先の新しい`UniqueID`をキーとして、`Task.TaskDependencies`を再定義するハッシュテーブルを事前に構築せよ。これを怠ると、インポート後にガントチャートが「スパゲッティ状態」になる。

4. 最後に:アーキテクトとしての矜持

VBAは、もはやレガシーな言語ではない。「MS Officeという巨大なアプリケーションの内部構造を直接操作できる、唯一無二の特権的な実行環境」である。

階層構造を扱う際は、「今、どのタスクを親にしているか」「どのIDが新しいコンテキストでどのIDに変換されるべきか」という状態遷移図を頭の中で描けるようになること。それが、Project VBAを真に掌握するということだ。

システムが巨大化すればするほど、コードの美しさよりも「堅牢性」と「可読性」が価値を持つ。メモリを適切に解放し、再計算エンジンを制御下に置く。この一見地味な積み重ねが、数千行規模のタスク管理プロジェクトを安定稼働させる唯一の道である。

さあ、次は君の番だ。このコードをベースに、さらに洗練されたラッパーを構築してほしい。

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