Project VBAを掌握せよ:手動・自動タスク混在環境における計算エンジン排他制御の極致
Project VBAの計算エンジンは、気難しい暴れ馬だ。一度「再計算」のトリガーを引けば、依存関係の連鎖反応(Dependency Chain)がメモリを喰らい尽くし、予期せぬ再帰ループでシステムを停止させる。
特に、`Task.Manual` を動的に切り替える環境では、計算エンジンの「推論」と「強制設定」が衝突し、データ整合性が崩壊することが多い。今回は、計算モードを全域停止させる愚を犯さず、特定タスクのみを制御下に置き、エンジンを暴走させずに排他制御を行うための、現場の最終解法を伝授する。
—
1. なぜ「計算モードの切り替え」は悪手なのか
`Application.Calculation` を手動で制御するのは、外科手術中に患者の心臓を止めるようなものだ。再計算を止めることで、依存関係の解決がスタックし、後続のAPI呼び出しが「スタックオーバーフロー」または「計算不整合」を引き起こす。
我々が目指すべきは、「エンジンの挙動を制御する」のではなく、「エンジンの計算対象から特定のタスクを論理的に隔離する」ことである。
—
2. 実装の指針:Manualプロパティの排他制御パターン
Taskの `Manual` プロパティを操作する際、最も重要なのは「計算イベントの発生を最小化すること」だ。以下のコードは、オブジェクト生成コストを極限まで抑制し、メモリリークを回避する設計としている。
推奨される実装パターン
‘ プロジェクトの安定稼働を担保するための排他制御ラッパー
Public Sub SetTaskManualMode(ByRef targetTask As Task, ByVal isManual As Boolean)
‘ 1. オブジェクトの有効性チェック(メモリ保護)
If targetTask Is Nothing Then Exit Sub
‘ 2. 状態変化の抑制(不要な計算イベントの発生を防ぐ)
If targetTask.Manual = isManual Then Exit Sub
‘ 3. 計算エンジンの暴走を防ぐための排他ブロック
‘ Windows APIのSendMessageを併用して描画を停止させるのも有効だが、
‘ VBAレベルではApplication.ScreenUpdatingとCalculationの連動を最小限に留める
On Error GoTo ErrorHandler
‘ 設定変更
targetTask.Manual = isManual
‘ 4. 変更後の明示的な依存再計算
‘ ここで全体再計算を走らせず、必要最小限の依存ツリーのみを更新する
‘ Project Object Modelでは、この後のAPI呼び出しで整合性が取れる
Exit Sub
ErrorHandler:
Debug.Print “Critical Error: Task ID ” & targetTask.ID & ” – ” & Err.Description
‘ 必要に応じてログを残し、ロールバック処理を記述する
End Sub
—
3. メモリ最適化とオブジェクトライフサイクルの管理
VBAにおいて、Projectのタスクオブジェクトをループ内で何度も取得するのは「自殺行為」だ。オブジェクトの参照(`Task`)は、必要最小限のスコープで破棄しなければならない。
シニアエンジニアが守るべき鉄則
- Set = Nothing の徹底: 大規模プロジェクトでは、タスクの走査が終わるごとに参照を解放せよ。さもなくば、ガベージコレクションが追いつかず、Projectの動作が徐々に重くなる。
- APIによるウィンドウメッセージの抑制: `User32.dll` の `LockWindowUpdate` を呼び出し、再計算時のUI描画を物理的にシャットアウトすることで、処理速度が劇的に向上する。
‘ API宣言(モジュール先頭に配置)
If VBA7 Then
Private Declare PtrSafe Function LockWindowUpdate Lib “user32” (ByVal hwndLock As LongPtr) As Long
Else
Private Declare Function LockWindowUpdate Lib “user32” (ByVal hwndLock As Long) As Long
End If
‘ 実行時の最適化
Public Sub OptimizedBatchUpdate()
LockWindowUpdate Application.hWnd
‘ ここでタスクの大量更新処理を実施
‘ …
LockWindowUpdate 0 ‘ 解放
End Sub
—
4. 結論:システム間連携における「防波堤」を作る
外部システムからProject VBAへデータを流し込む際、もっとも警戒すべきは「トリガーの過剰反応」である。
1. Manual属性を事前に設定: データを書き込む前に、対象タスクを `Manual = True` にし、計算エンジンから切り離す。
2. バルクアップデート: 全ての値を書き込んだ後に、一度だけ `Manual = False` に戻し、その直後に `Project.Calculate` を実行する。
この「隔離・一括更新・再結合」のサイクルこそが、Project VBAを使いこなす唯一の生存戦略だ。レガシーな環境であればあるほど、コードの行数よりも「エンジンの負荷をどう逃がすか」というアーキテクチャ設計に魂を込めよ。
計算エンジンは、君の敵ではなく、正しく調教すれば最強の計算リソースとなる。その制御権を、決して手放してはならない。
