Project VBAの深淵:ベースライン乖離を可視化する「差分抽出エンジン」の構築
プロジェクトマネジメントにおいて、MS Projectのベースラインは単なる「記録」ではない。それはプロジェクトという生命体が、当初の設計図からどう変異したかを証明する「遺伝子情報」だ。
本稿では、Project VBA(pjAuto)を駆使し、ベースラインと現在値の乖離をミリ秒単位の効率で抽出し、Excelへ出力する堅牢なアーキテクチャについて語る。ただコードを動かすのではない。メモリを制御し、COMインターフェースの寿命を支配する。それが真のエンジニアリングだ。
—
1. アーキテクチャ設計の要諦:COMの生存戦略
VBAでMS Projectを操作する際、多くの者が陥る罠が「暗黙のオブジェクト参照」だ。`ActiveProject`を安易に多用すれば、メモリリークは必至。特にProjectのCOMオブジェクトは複雑で、破棄のタイミングを誤るとバックグラウンドでプロセスがゾンビ化する。
極限の最適化ルール
- Late Bindingの回避: `Project.Application`を明示的に参照し、参照設定を固定する。
- オブジェクトの明示的解放: ループ内でのオブジェクト生成は厳禁。`Nothing`代入のタイミングを計算し尽くせ。
- 描画の抑制: `Application.ScreenUpdating = False` は必須だが、さらに `Calculation = pjManual` を併用し、イベント駆動のオーバーヘッドを殺せ。
—
2. 実装:ベースライン差分抽出エンジン
以下のコードは、Projectのタスクコレクションをメモリ上にロードし、指定したベースラインと現在値を比較するコアロジックだ。
‘ @description: MS Projectからベースライン乖離を抽出する高速プロシージャ
‘ @requirement: Microsoft Project Object Library 16.0
Public Sub ExportBaselineVariance(ByVal targetBaseline As PjBaseline)
Dim proj As MSProject.Project
Dim tsk As MSProject.Task
Dim xlApp As Object, xlWb As Object
‘ プロセス整合性の確保
Set proj = Application.ActiveProject
‘ パフォーマンス向上のための計算抑制
Application.Calculation = pjManual
‘ Excelへの出力準備(Late Bindingによる疎結合)
Set xlApp = CreateObject(“Excel.Application”)
Set xlWb = xlApp.Workbooks.Add
‘ ヘッダー出力
With xlWb.Sheets(1)
.Cells(1, 1).Value = “タスク名”
.Cells(1, 2).Value = “ベースライン開始日”
.Cells(1, 3).Value = “現在開始日”
.Cells(1, 4).Value = “乖離(日)”
End With
‘ タスク走査:パフォーマンスを意識したループ
Dim row As Long: row = 2
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
If Not tsk.Summary Then
‘ ベースラインデータの取得と差分計算
‘ メモリ負荷を避けるため、Variant型を避け明示的に変換
Dim baseDate As Date: baseDate = tsk.BaselineStart(targetBaseline)
If baseDate <> #1/1/1984# Then ‘ 未設定チェック
xlWb.Sheets(1).Cells(row, 1).Value = tsk.Name
xlWb.Sheets(1).Cells(row, 2).Value = baseDate
xlWb.Sheets(1).Cells(row, 3).Value = tsk.Start
xlWb.Sheets(1).Cells(row, 4).Value = DateDiff(“d”, baseDate, tsk.Start)
row = row + 1
End If
End If
End If
Next tsk
‘ クリーンアップ:メモリの解放はエンジニアの義務
xlApp.Visible = True
Application.Calculation = pjAutomatic
Set tsk = Nothing
Set proj = Nothing
Set xlWb = Nothing
Set xlApp = Nothing
End Sub
—
3. レガシー環境とWindows APIの接点
大規模プロジェクトでは、メモリの断片化がボトルネックとなる。Windows APIの `GlobalMemoryStatusEx` を利用し、処理開始前に現在のメモリ負荷を監視するルーチンを実装することをお勧めする。
さらに、ProjectのCOMインターフェースが応答を返さない「ハングアップ」を検知するため、`SendMessageTimeout` を用いた監視スレッド(あるいは別プロセスからのウォッチドッグ)を構築することで、システム全体の堅牢性が劇的に向上する。
安定運用のためのチェックリスト
1. 大容量ファイル対策: タスク数が数千を超える場合は、`Collection` オブジェクトに格納せず、直接Excelのレンジへ書き出す(メモリ消費を最小化するため)。
2. 型変換の厳密化: `BaselineStart` は日付型だが、Project内部では数値として保持されている。日付計算時は `DateValue` でキャストし、ロケール依存のバグを排除せよ。
3. エラーハンドリング: `On Error GoTo 0` で逃げず、`Err.Number` をログに記録する専用のErrorHandler関数を実装すること。
—
結びに代えて
VBAはレガシーではない。現代のクラウドAPI全盛時代においても、ローカルPCのProjectファイルをミリ秒単位で制御できる唯一無二の「特権階級のツール」だ。
あなたが書くコードの一つ一つが、プロジェクトの行く末を決定づける。計算の効率、メモリの管理、そして何より「システムがどう振る舞うべきか」という設計思想。それらを追求した先に、真の自動化エンジニアとしての高みがある。
次の実装では、さらに深く、タスクの階層構造を維持したままのツリー出力に挑戦してほしい。健闘を祈る。
