【テクニカル・上級編】FSOを用いて複数のProjectファイルを横断的に検索し、依存関係を可視化する – Project VBA解析バイブル

スポンサーリンク

巨大プロジェクト群の深淵を覗く:VBAによるMS Project横断的依存関係解析の極致

大規模プロジェクトの管理において、複数の `.mpp` ファイルが複雑に絡み合う「外部タスクリンク(Cross-Project Links)」の追跡は、PMOやシニアエンジニアにとって長年の悪夢である。GUIで一つ一つリンクを確認するなど愚の骨頂だ。

今回は、FileSystemObject(FSO)を駆使してフォルダ内を走査し、MS Projectのオブジェクトモデルを直接叩いて依存関係を抽出する、実戦的なアーキテクチャを解説する。

1. アーキテクチャの核心:Objectモデルのライフサイクル管理

MS Projectのオートメーションはメモリリークを起こしやすい。特に `Application` オブジェクトをループ内でインスタンス化し続けるような実装は、レガシー環境では即座にプロセス停滞を招く。

鉄則:

  • Applicationの共有: 全ファイルを走査する間、一度起動した `MSProject.Application` を使い回す。
  • 明示的解放: `Set obj = Nothing` は儀式ではない。COM参照カウントを確実にデクリメントし、メモリを強制的に開放させる。
  • バックグラウンド実行: UI更新を抑制し、パフォーマンスを極限まで引き上げる。

2. 実装:横断的依存関係抽出エンジン

以下のコードは、指定フォルダ内の全 `.mpp` を走査し、他プロジェクトを参照している `Task` を抽出する心臓部である。

‘ 必要な参照設定: Microsoft Project 16.0 Object Library
‘ 必要な参照設定: Microsoft Scripting Runtime

Option Explicit

Public Sub AnalyzeProjectDependencies(ByVal folderPath As String)
Dim fso As New FileSystemObject
Dim mppFolder As Folder
Dim file As file
Dim projApp As MSProject.Application
Dim proj As MSProject.Project
Dim tsk As MSProject.Task
Dim link As MSProject.TaskDependency

‘ Applicationの初期化(非表示で実行)
Set projApp = New MSProject.Application
projApp.Visible = False

Set mppFolder = fso.GetFolder(folderPath)

For Each file In mppFolder.Files
If LCase(fso.GetExtensionName(file.Path)) = “mpp” Then
‘ プロジェクトを開く(読み取り専用推奨)
Set proj = projApp.Projects.Open(file.Path, ReadOnly:=True)

‘ タスクの依存関係を走査
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
For Each link In tsk.TaskDependencies
‘ 外部リンク(ExternalProjectNameが存在するか)を判定
If link.ExternalProjectName <> “” Then
Debug.Print “Found Link: ” & tsk.Name & _
” -> ” & link.ExternalProjectName & _
” [” & link.ExternalTaskName & “]”
End If
Next link
End If
Next tsk

‘ プロジェクトを閉じる(保存しない)
proj.Close SaveChanges:=pjDoNotSave
End If
Next file

‘ クリーンアップ
projApp.Quit
Set proj = Nothing
Set projApp = Nothing
Set fso = Nothing
End Sub

3. シニアエンジニアが意識すべき「メモリの重み」

このコードには、大規模プロジェクト運用における「枯れた」知見が詰まっている。

1. Read-Onlyの恩恵: ネットワークドライブ上のプロジェクトを扱う際、書き込み権限で開くことはロック競合と予期せぬ更新リスクを生む。常に `ReadOnly:=True` を徹底せよ。
2. ExternalTaskNameの罠: `link.ExternalTaskName` は、リンク先ファイルが開かれていない状態でも、キャッシュされた値を返すことがある。この特性を利用して、ファイルを開かずにリンクを特定する手法もあるが、整合性確保のためには一度 `Open` するのが最も安全かつ確実である。
3. エラーハンドリングの重要性: 壊れた `.mpp` ファイルが存在する場合、ループが停止する。個別のファイル解析ごとに `On Error Resume Next` を配し、ログに吐き出して次へ進むフォールトトレラントな設計が求められる。

4. さらなる高みへ:Windows APIによるプロセス監視

さらに高度な制御を行う場合、`TaskKill` をVBAから呼び出すのではなく、Windows APIを使用してプロセスIDを特定し、異常終了したMS Projectプロセスを確実にKillするラッパーを実装することをお勧めする。

レガシーなVBA環境であっても、現代的なメモリ管理とリソースのライフサイクルを意識するだけで、システムは劇的に堅牢になる。GUIに頼らず、コードでプロジェクトの全貌を支配せよ。

それが、我々エンジニアが「管理される側」から「管理する側」へ回るための唯一の道である。

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