【テクニカル・上級編】計算エンジンを強制的に再起動させる:VBAによるプロジェクト再計算のトリガー実装 – Project VBA解析バイブル

スポンサーリンク

プロジェクトの闇を切り裂く:MS Project VBAにおける計算エンジンの強制再起動とメモリの深淵

MS Projectの計算エンジンは、気まぐれな獣だ。
特に複雑な依存関係を持つ大規模プロジェクトにおいて、ASAP(可能な限り早く)やALAP(可能な限り遅く)の制約条件をVBAで動的に操作した際、エンジンが「更新の機運」を逃すことがある。GUI上の表示と内部データに乖離が生じ、進捗率が狂い、クリティカルパスが霧散する。

多くのアマチュアは`Application.Calculate`を連打して解決を図るが、それは単なる気休めに過ぎない。今日は、計算エンジンを物理的に、かつ確実に再起動させ、プロジェクトの整合性を維持するための「深淵の技法」を伝授する。

—

1. なぜ計算エンジンは「沈黙」するのか

MS Projectの再計算プロセスは、単なる数式の再評価ではない。制約条件の伝播、リソース平準化の再試行、そしてリンク関係のトポロジカルソートを含む重厚な処理だ。

VBAでプロパティを大量更新すると、エンジンは効率化のために更新をキューイング(遅延実行)することがある。しかし、外部連携システムや複雑な計算ロジックが絡む場合、このキューがスタックし、整合性の取れないまま計算が終了する「デッドロック」に陥る。

ここで安易に `Application.CalculateAll` を叩くのは諸刃の剣だ。計算範囲を全プロジェクトに広げることで、メモリ消費が急増し、最悪の場合、OSのメモリマネージャを圧迫してプロセスごとクラッシュする。

—

2. 実装の極意:計算エンジンを制御下に置く

再計算をトリガーする際、最も重要なのは「計算モードの明示的制御」と「オブジェクトの寿命管理」だ。以下のコードは、計算エンジンを強制的にリセットし、整合性を担保するための実装例である。

強制再計算の実装サンプル

‘ 計算エンジンの挙動を掌握するモジュール
Public Sub ForceProjectRecalculate(ByRef proj As Project)
‘ 1. 計算モードを一時的に手動に設定(イベントの暴発を防ぐ)
Dim originalCalcMode As PjCalculation
originalCalcMode = Application.Calculation
Application.Calculation = pjManual

On Error GoTo Cleanup

‘ 2. オブジェクトの明示的なリフレッシュ
‘ CalculateAllは破壊的なので、まずは対象プロジェクトのみを対象とする
proj.Calculate

‘ 3. 特定の制約条件(ASAP/ALAP)の強制更新
‘ 一度プロパティを再設定することでエンジンに再計算を強いる
Dim t As Task
For Each t In proj.Tasks
If Not t Is Nothing Then
‘ 制約条件の再適用により計算エンジンのフラグを強制的に立てる
t.ConstraintDate = t.ConstraintDate
End If
Next t

‘ 4. 最後にグローバルな再計算を実行
Application.CalculateAll

Cleanup:
‘ 5. モードを復元し、メモリを解放
Application.Calculation = originalCalcMode
Set proj = Nothing
End Sub

—

3. メモリとパフォーマンスの境界線

レガシーな環境であればあるほど、VBAのメモリリークは致命的だ。特に `Project` や `Task` オブジェクトをループ内で生成・参照する場合、GC(ガベージコレクション)に頼ってはいけない。

  • Set Nothingの徹底: オブジェクト変数は使用直後に必ず `Set x = Nothing` を実行すること。MS Projectのメモリ管理はCOMコンポーネント経由で行われるため、VBA側の解放を待たずにプロセスが肥大化する。
  • Windows APIによる計算同期: 非常に巨大なプロジェクトで計算が完了する前に次の処理へ進んでしまう場合は、`Sleep` APIを使い、CPU負荷を見ながら計算サイクルの終了を待機するコードを挟むのも一つの手だ。

‘ 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

—

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

計算エンジンの「強制再起動」は、いわば心臓マッサージだ。多用すればプロジェクトファイルという「人体」は疲弊する。

1. イベントハンドラの抑制: `Application.Calculation = pjManual` を行う前に、`Application.EnableEvents = False` を忘れてはならない。再計算中に再計算がトリガーされる無限ループは、VBAエンジニアにとって最大の恥である。
2. ログの可視化: `CalculateAll` を実行する前後で `Now` を記録し、計算に要した時間を計測せよ。数ミリ秒の変動が、システムのアーキテクチャ欠陥を教えてくれる。

このコードは、単に動くものではない。複雑なプロジェクトの制約条件を、貴殿の完全な制御下に置くための「武器」である。現場で戦う諸君、計算エンジンの挙動を支配し、真の自動化を追求せよ。

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