Project VBAを掌握する:Task実績値「強制上書き」の深淵と最適化戦略
Microsoft Project(MSP)の自動スケジューリングエンジンは、一見すると便利だが、大規模プロジェクトのインポートやシステム間連携においては「制御不能な暴走」の元凶となる。特に、Taskの `ActualStart` や `ActualFinish` をプログラムで強引に叩き込む際、標準的なコードを書けば、Projectのロジックが即座に再計算を開始し、予期せぬ日付のズレやガントチャートの崩壊を招く。
本稿では、MSPの心臓部をハックし、整合性を保ったまま実績値を流し込むための「極限の知見」を共有する。
—
1. 破壊的な自動再計算を封じ込める「防壁」
`Task.ActualStart` を代入した瞬間にProjectの計算エンジンが走り出すのを防ぐには、単に `Calculation = pjManual` にするだけでは不十分だ。我々が対峙すべきは、オブジェクトモデルの背後で駆動するイベントの連鎖である。
推奨される更新シーケンス
1. CalculationModeの強制分離: `Application.Calculation = pjManual` を明示的にセットする。
2. 実績値の投入順序: `ActualStart` -> `ActualFinish` -> `ActualDuration` の順で書き込む。
3. ステータス更新の強制: `Task.PercentComplete` を最後に更新し、内部状態を同期させる。
—
2. 実装の要諦:オブジェクトの整合性を担保するコード
以下は、Projectの自動計算ロジックに干渉させず、メモリリークを排除した堅牢な更新コードの雛形である。
‘ @description 実績開始日/終了日を安全に更新するモジュール
‘ @author Chief Architect
Public Sub ForceUpdateActualDates(ByRef tsk As MSProject.Task, ByVal actStart As Date, ByVal actFinish As Date)
Dim app As MSProject.Application
Set app = tsk.Application
‘ 1. 自動計算の無効化(パフォーマンスと整合性の保持)
Dim originalCalc As Long
originalCalc = app.Calculation
app.Calculation = pjManual
On Error GoTo Cleanup
‘ 2. 実績値の投入
‘ 注意: ActualStartを設定する前にActualFinishが存在すると
‘ 内部的なバリデーションエラーが発生する場合があるため順序を厳守
tsk.ActualStart = actStart
tsk.ActualFinish = actFinish
‘ 3. 実績工数の整合性確保
‘ 日付だけ変えても実工数(ActualWork)が未更新だとデータ不整合の温床になる
‘ 必要に応じて Work / ActualWork を再計算して同期させること
Cleanup:
‘ 4. 状態の復帰とリソースの明示的解放
app.Calculation = originalCalc
Set app = Nothing
If Err.Number <> 0 Then
Err.Raise Err.Number, “ForceUpdateActualDates”, “Critical Error: ” & Err.Description
End If
End Sub
—
3. シニアエンジニアが押さえるべき「隠れた罠」
① ActualDurationとActualWorkの不整合
`ActualStart` と `ActualFinish` を強制的に上書きしても、MSP内部で計算される `ActualDuration` との間に齟齬が生じることがある。特にリソースが割り当てられている場合、`ActualWork` との関係性が崩れ、プロジェクト全体のコスト計算が狂う。
極意: 日付を書き換えた後は、必ず `Task.ActualDuration` を明示的に計算し直すか、Project側に再計算を許可する前に「手動で調整済みの値」として確定させること。
② Windows APIによる描画抑制(パフォーマンスチューニング)
数千件規模のタスクを一括更新する場合、`Application.ScreenUpdating = False` だけでは不足することがある。Windows APIの `LockWindowUpdate` を併用し、親ウィンドウのハンドルをロックすることで、再描画コストを極限まで排除できる。
‘ 描画ロック用API定義
Private Declare PtrSafe Function LockWindowUpdate Lib “user32” (ByVal hWndLock As LongPtr) As Long
‘ 使用例
LockWindowUpdate Application.hWnd
‘ … 大量更新処理 …
LockWindowUpdate 0 ‘ 解除
③ オブジェクト解放の作法
VBAはガベージコレクションが脆弱である。ループ内で `Task` オブジェクトを走査する際は、必ず `Set tsk = Nothing` を明示的に行い、参照カウントを即座に解放せよ。これを怠ると、Projectプロセスが肥大化し、大規模プロジェクトでの実行時に「メモリ不足」でクラッシュする。
—
結論:自動化は「制御」から始まる
Project VBAにおける最大の敵は、「便利さ」を信じきったエンジニアの慢心である。MSPの自動スケジューラは強力だが、システム連携の際には「我々が主導権を握る」という姿勢が不可欠だ。
- CalculationModeの制御
- 更新順序の厳格化
- 描画プロセスの物理的ロック
これら三位一体の戦術こそが、レガシーなProject環境を、モダンなデータハブとして再定義するための唯一の道である。コードは常にシンプルに、しかし内部で起きているメモリの挙動には極めて冷徹であれ。
