【テクニカル・上級編】Taskの「実績開始日」と「実績終了日」をVBAで強制的に上書きする際の注意点 – Project VBA解析バイブル

スポンサーリンク

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環境を、モダンなデータハブとして再定義するための唯一の道である。コードは常にシンプルに、しかし内部で起きているメモリの挙動には極めて冷徹であれ。

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