Project VBAを掌握する:Task制約一括操作による「計算コスト」の支配術
Project VBAの深淵に足を踏み入れるということは、単なるメソッドの呼び出し以上の意味を持つ。それは、MS Projectの「計算エンジン」という名のブラックボックスと対峙し、その挙動を制御下に置くことに他ならない。
多くのエンジニアが陥る罠は、`Task.ConstraintType`をループで書き換える際、都度発生する再計算コストを軽視することだ。数千行のタスクに対し、無防備にプロパティを書き換えれば、Projectは即座に依存関係を再評価し、IDEはフリーズ寸前の重い沈黙に包まれる。
今日は、大規模プロジェクトの制約変更を、システムに負荷をかけずに「外科手術」のように完遂するための極限のテクニックを伝授する。
—
1. 殺人的な再計算を防ぐ:ScreenUpdatingとCalculationModeの制御
Projectのオブジェクトモデルにおいて、`Application.ScreenUpdating`の停止は基本中の基本だが、真のプロフェッショナルはそれだけでは満足しない。Project特有の「Calculation」の挙動を理解せよ。
制約を一括変更する際、最も賢明なのは「手動再計算モード」へ一時的に退避することだ。
‘ 計算コストを極限まで低減させるためのコンテキスト管理
Public Sub BatchUpdateConstraints(ByVal targetTaskIds As Collection, ByVal newConstraint As PjConstraint)
Dim projApp As Object: Set projApp = Application
‘ プロジェクトの再計算負荷を一時停止
Dim originalCalculation As Long
originalCalculation = projApp.Calculation
projApp.Calculation = pjManual
projApp.ScreenUpdating = False
On Error GoTo Cleanup
Dim t As Task
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ 制約タイプを変更し、指定日をプロジェクト開始日に同期させる(必要に応じて)
t.ConstraintType = newConstraint
If newConstraint <> pjASAP Then
t.ConstraintDate = ActiveProject.ProjectStart
End If
End If
Next t
Cleanup:
‘ 最後に一括で再計算をトリガーする
projApp.Calculation = originalCalculation
projApp.ScreenUpdating = True
‘ メモリ解放の儀式
Set t = Nothing
Set projApp = Nothing
End Sub
2. オブジェクトライフサイクルの管理とメモリ断片化の回避
VBAのガーベッジコレクションを信頼してはならない。特にCOMオブジェクトを大量に扱う場合、暗黙的に保持される参照がメモリリークを招き、長時間のバッチ処理でExcel/Projectがクラッシュする原因となる。
- 明示的なNothing代入: ループ内でのオブジェクト生成は避け、参照変数を再利用する設計を徹底すること。
- Late Bindingの活用: 参照設定(Reference)によるコンパイル依存を避けることで、異なるProjectバージョン間でのバイナリ互換性を確保できる。
3. Windows APIによる「思考停止」の回避
大規模なプロジェクトファイルを操作する際、OS側のメッセージキューが飽和し、Windowsが「応答なし」と誤判定することがある。これを防ぐには、VBA側からWindows APIの`Sleep`を呼び出し、CPUにわずかな猶予を与えるのが「伝説のエンジニア」の嗜みだ。
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
‘ ループ内にSleepを挿入することで、UIスレッドを解放する
‘ DoEventsは計算順序を乱す可能性があるため、極力避けるのが賢明だ
4. なぜ「制約変更」がリスク管理の鍵となるのか
単に`ConstraintType`を`pjMustStartOn`や`pjStartNoEarlierThan`に変更する作業は、事務的な処理ではない。これは「プロジェクトのバッファを強制的に可視化する」行為だ。
- 柔軟性の消失: `pjASAP`(できるだけ早く)を排除することで、本来のクリティカルパスがどこに潜んでいるかが浮き彫りになる。
- シミュレーションの精度: 再計算をマニュアル制御することで、制約変更前後の「工期偏差」をメモリ上の変数としてキャプチャし、ログとして出力することが可能になる。
結びに:コードは「対話」である
VBAを単なるスクリプト言語だと侮るな。Projectのオブジェクトモデルは、数十年の歴史が積み重なった巨大なシステムアーキテクチャそのものだ。
君たちが書く一行のコードが、数億円規模のプロジェクトの命運を左右する可能性がある。常に「計算コスト」「メモリの安全性」「保守性」という三本の柱を意識し、ブラックボックスの中身を透視する感覚を養ってほしい。
もし、さらに深い最適化(例えば、`Project_BeforeTaskChange`イベントのフックによるバリデーション制御など)が必要になったら、また声をかけてくれ。極限の世界で待っている。
