「計算待ち」のまま保存していませんか? Project VBAの心臓部、計算エンジンを制御する極限の守護術
こんにちは。現場で数々のプロジェクト管理自動化を指揮してきた、あなたの「技術的な先輩」です。
マクロの記録機能を使って「タスクの日付を動かす」「リソースを割り当てる」といった操作ができるようになった。それは素晴らしい第一歩です。でも、もしあなたが「マクロを実行した直後に保存したら、なぜかスケジュールがズレていた」「計算が終わる前に次の処理が走ってエラーになった」という経験をしたことがあるなら、それはあなたが「Projectの心臓部」――すなわち計算エンジン(Calculation Engine)の挙動をまだ制御できていない証拠です。
今日は、初級者を卒業し、プロフェッショナルな自動化エンジニアへとステップアップするための「計算エンジンの監視と制御」について、魂を込めて解説します。
1. なぜ「再計算」がプロジェクトを破壊するのか
Microsoft Projectは、単なる「表計算ソフト」ではありません。タスク間の依存関係(FS、SS、FFなど)や、ASAP(できるだけ早く)/ ALAP(できるだけ遅く)といった制約条件を、複雑なアルゴリズムで解き明かす「高度な計算エンジン」を搭載したシステムです。
ここで、初心者が陥りやすい「致命的なシナリオ」を想像してみてください。
1. VBAで1,000個のタスクの制約条件を一括変更する。
2. Projectの計算エンジンが「うわ、計算が大変だ!」と裏側で必死に計算を開始する。
3. 計算が終わる前(=計算中)に、マクロが次の処理(保存やレポート出力)に進んでしまう。
4. 結果として、計算途中の「不完全なスケジュール」がファイルに書き込まれる。
これが、現場で最も恐れられる「データの不整合」です。計算エンジンが「保留(Pending)」状態にあるときに保存することは、設計図が書きかけの状態で工場に流すようなものです。
2. 武器を手に入れよう:`CalculationMode` の理解
プロのエンジニアは、Projectの状態を「感覚」ではなく「プロパティ」で判断します。
今回、私たちが監視の対象とするのは `Application.CalculationMode` です。
| 定数 (Enum) | 状態 | プロの視点 |
|---|---|---|
| `pjCalculationManual` | 手動計算 | エンジンは止まっている。制御下にある。 |
| `pjCalculationAutomatic` | 自動計算 | エンジンは常に動こうとしている。油断禁物。 |
実は、Project VBAにおいて「計算中であるかどうか」を直接示す「Calculating = True」のような単純なプロパティは存在しません。そのため、私たちは「計算モードを適切に制御し、計算が完了したことを保証する仕組み」を自作する必要があるのです。
3. 実践:計算エンジンを監視する「防衛システム」の実装
では、実際に「保存しようとしたときに、計算が適切に行われているかチェックする」仕組みを作っていきましょう。
ここで重要なのが、「クラスモジュール」という概念です。マクロの記録では決して出てこないこの仕組みを使うことで、アプリケーション全体(Projectそのもの)のイベントを待ち構える「監視役」を配置できます。
ステップ1:監視役(クラスモジュール)の作成
まず、VBAエディタで `挿入` → `クラスモジュール` を選択し、プロパティウィンドウで名前を `clsAppEvent` に変更してください。
' --- クラスモジュール: clsAppEvent ---
Option Explicit
' Projectアプリケーションのイベントをキャッチするための宣言
Public WithEvents App As MSProject.Application
' 保存(Save)が実行される直前に呼び出されるイベント
Private Sub App_ProjectBeforeSave(ByVal pj As MSProject.Project)
' 計算モードをチェック
' プロの判断:もし計算が「自動」かつ、何らかの理由で計算が保留されているリスクがある場合、
' ここでユーザーに警告を出す、あるいは計算を強制させるロジックを組み込む
Debug.Print "保存前チェックを開始します..."
' 簡易的な判定ロジック:
' 本来は、計算が完了しているかを確認するためのフラグ管理を自作するのが理想的です。
' ここでは、計算モードが Manual になっていないか、あるいは計算が走る必要がある状態かを確認します。
If App.CalculationMode = pjCalculationManual Then
' 手動計算モードの場合、ユーザーが計算を忘れている可能性がある
Dim response As VbMsgBoxResult
response = MsgBox("現在、計算モードが【手動】になっています。" & vbCrLf & _
"計算を実行せずに保存すると、スケジュールが不正確になる可能性があります。" & vbCrLf & _
"計算を実行してから保存しますか?", vbYesNo + vbExclamation, "計算保留の警告")
If response = vbYes Then
' 計算を実行させる
App.Calculate
Debug.Print "計算を実行しました。"
Else
' 保存をキャンセルする
MsgBox "保存を中止しました。計算を実行してください。", vbCritical
' ※ ProjectのBeforeSaveイベントで保存を止めるには、
' 実は少し特殊なテクニック(エラーを発生させる等)が必要ですが、
' ここでは「論理的な警告」の仕組みを学びましょう。
End If
End If
End Sub
ステップ2:監視役を起動させる(標準モジュール)
次に、作成したクラスモジュールを実際に動かすための「起動スイッチ」を、標準モジュールに記述します。
' --- 標準モジュール ---
Option Explicit
' 監視役(クラスインスタンス)を保持するための変数
' これをモジュールレベルで宣言しないと、マクロ終了時に監視役が消滅してしまいます!
Dim myAppEvent As New clsAppEvent
' 監視システムを開始するプロシージャ
Sub StartMonitoring()
Set myAppEvent.App = MSProject.Application
MsgBox "計算エンジンの監視を開始しました。保存時のチェックが有効になります。", vbInformation
End Sub
' 監視システムを停止するプロシージャ
Sub StopMonitoring()
Set myAppEvent = Nothing
MsgBox "監視を停止しました。", vbInformation
End Sub
' 【テスト用】あえて計算を保留させるような動きをシミュレートする
Sub TestCalculationControl()
' 1. 計算モードを手動にする(これで「計算が止まった状態」を作る)
Application.CalculationMode = pjCalculationManual
MsgBox "計算モードを手動にしました。この状態で『保存』ボタンを押してみてください。"
End Sub
4. プロの知見:陥りやすいエラーと回避策
この仕組みを実装する際、以下の3点に注意してください。ここをクリアすれば、あなたのコードの信頼性は格段に上がります。
① インスタンスの消失(生存期間の管理)
クラスモジュールで `WithEvents` を使った場合、その変数が「プロシージャ内」で宣言されていると、そのプロシージャが終わった瞬間に監視役が消えてしまいます。必ず標準モジュールの先頭(宣言セクション)で `Dim` してください。
② 再帰呼び出しのループ
`App_ProjectBeforeSave` の中で `App.Calculate` を実行すると、計算によって再びプロジェクトの状態が変わり、予期せぬイベントが連鎖することがあります。複雑な処理を行う場合は、`Application.EnableEvents = False`(※Project VBAでは直接使えない場合があるため、フラグ変数での管理を推奨)のような、二重動作を防ぐロジックを検討してください。
③ 計算コストの考慮
大規模なプロジェクトでは、`App.Calculate` は非常に重い処理です。ユーザーに「計算しますか?」と聞くのは親切ですが、業務フローによっては「自動的に計算を完了させてから保存を許可する」という、よりシームレスな設計が求められます。
まとめ:ここをクリアすれば、Project VBAの基本はバッチリですよ
「マクロの記録」は、単なる「操作のコピー」です。
しかし、今回学んだ「イベントの監視」や「クラスモジュールによる制御」は、「システムの挙動の設計」です。
1. 計算エンジンは、裏側で動いている。
2. 計算が終わる前に保存することは、データの自殺行為である。
3. クラスモジュールを使って、アプリケーションのイベントを「待ち構える」。
この3点を意識するだけで、あなたの作るツールは「動けばいいツール」から「現場で信頼されるプロフェッショナルなツール」へと進化します。
さあ、次は自分でこのコードをカスタマイズして、独自の「プロジェクト・ガーディアン(守護神)」を作ってみてください。応援していますよ!
