【テクニカル・上級編】【中級者向け】大規模WBSの特定階層を別ファイルへ切り出し、依存関係を維持したまま保存するモジュール – Project VBA解析バイブル

スポンサーリンク

巨大なWBSを解体せよ:VBAによる「プロジェクト階層・依存関係」の動的抽出と外部参照の呪縛

大規模なProjectファイルは、それ自体が爆弾だ。
数千行のタスク、複雑に絡み合う前提条件、そして肥大化したメモリ消費。ある一点を超えた瞬間、MS Projectのパフォーマンスは崩壊し、ファイル破損の悪夢が始まる。

現場のシニアエンジニアなら知っているはずだ。巨大なプロジェクトを単一ファイルで管理しようとするのは、エンジニアリングの敗北であると。

今日は、Project VBAを駆使し、「特定階層を別ファイルへ切り出し、依存関係(Predecessors)を破壊せずに抽出する」という、極めて実戦的なアーキテクチャを解説する。

—

1. 依存関係(Dependency)の正体を暴く

MS Projectにおいて、タスク間の依存関係は `Task.TaskDependencies` コレクションで管理されている。これを単純に値としてコピーするだけでは不十分だ。

なぜなら、タスクID(Unique IDではない)は切り出し先で変わる可能性があるからだ。ここで重要なのは、「Unique ID」をキーとしたマッピングテーブルをメモリ上に構築し、参照先を動的に解決するというプロセスだ。

2. メモリ最適化とオブジェクトライフサイクルの管理

VBAで大規模なタスクコレクションをループさせると、GC(ガベージコレクション)が追いつかず、メモリリークやオートメーションエラーが頻発する。

  • 明示的解放: `Set obj = Nothing` は儀式ではない。スコープを抜ける前に確実にメモリを解放せよ。
  • イベント抑止: `Application.ScreenUpdating = False` だけでなく、`Application.Calculation = pjManual` に設定し、再計算プロセスを遮断せよ。

3. 実装:タスク抽出モジュールの核

以下に、対象タスク群を新規プロジェクトへコピーし、外部依存関係を再構築するコアロジックを示す。

‘ プロジェクト切り出し・依存関係保持モジュール
Option Explicit

Sub ExtractSubProject(sourceProj As Project, targetFolder As String, targetOutlineLevel As Integer)
Dim srcTask As Task
Dim newProj As Project
Dim taskMap As Object
Set taskMap = CreateObject(“Scripting.Dictionary”)

‘ パフォーマンス最適化
Application.Calculation = pjManual

‘ 新規プロジェクト生成
Set newProj = Application.Projects.Add(False)

‘ 1. タスクのコピーとUnique IDのマッピング
For Each srcTask In sourceProj.Tasks
If Not srcTask Is Nothing Then
If srcTask.OutlineLevel <= targetOutlineLevel Then Dim newTask As Task Set newTask = newProj.Tasks.Add(srcTask.Name) ' Unique IDをキーにして新旧のマッピングを保持 taskMap.Add srcTask.UniqueID, newTask.UniqueID End If End If Next ' 2. 依存関係の再構築 Dim dep As TaskDependency For Each srcTask In sourceProj.Tasks If taskMap.Exists(srcTask.UniqueID) Then For Each dep In srcTask.TaskDependencies ' 依存先も切り出し対象に含まれている場合のみリンクを張る If taskMap.Exists(dep.From.UniqueID) Then newProj.Tasks.UniqueID(taskMap(srcTask.UniqueID)).TaskDependencies.Add _ From:=newProj.Tasks.UniqueID(taskMap(dep.From.UniqueID)), _ Type:=dep.Type End If Next End If Next ' 3. 後始末 Application.Calculation = pjAutomatic Set taskMap = Nothing ' ※保存処理は必要に応じてFileSystemObject等でパス生成 ' newProj.SaveAs targetFolder & "\Extracted_WBS.mpp" End Sub ---

4. チーフアーキテクトからの忠告

レガシー環境における「Windows API」の活用

もし、切り出したファイルをネットワークドライブ上の共有フォルダへ保存する場合、VBAのネイティブな `SaveAs` メソッドは同期処理ゆえに、I/O待ちでフリーズすることがある。
この場合、`kernel32.dll` の `CopyFileEx` を用いて非同期に近いI/O制御を行うか、あるいはファイルI/Oの完了を監視するシグナル処理を実装するのがプロの流儀だ。

外部参照リンクの罠

上記コードは「同一ファイル内」の依存関係を維持する設計だが、現実には「別のMPPファイル」を参照するケースも多い。その場合、`Task.ExternalTask` プロパティを走査し、`Project.Subprojects` コレクションを通じてリンクを再マッピングする必要がある。これは複雑なツリー走査になるため、再帰関数(Recursive Function)を用いて、スタックオーバーフローを回避しつつ深さ優先探索を行うこと。

結論:自動化の本質とは

自動化とは、単に「手作業を減らすこと」ではない。
「プロジェクトという巨大な生命体が持つ整合性を、システム的な強制力によって維持し続けること」だ。

WBSの分割は、単なるファイルの切り出しではなく、責任分界点の明確化そのものである。このコードをベースに、各社の固有環境に合わせて「エラーハンドリング(`On Error Resume Next` の乱用は厳禁)」を組み込み、堅牢なシステムを作り上げてもらいたい。

コードは嘘をつかない。論理的に組まれたプログラムは、必ず期待通りの挙動を返す。健闘を祈る。

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