【テクニカル・上級編】【中級者向け】巨大なプロジェクトファイルを開く際の「計算モード」を制御して高速化する手法 – Project VBA解析バイブル

スポンサーリンク

巨大なProject VBAを掌握せよ:計算モード制御による起動の極限最適化

プロジェクトマネジメントの世界で、MS ProjectのVBAを扱うことは「巨大な海図を解読する」ことに似ている。数千行のタスク、複雑な依存関係、そして無数のカスタムフィールド。これらを抱えた巨大な `.mpp` ファイルを開く際、VBAエンジニアを絶望させるのは「自動計算」のオーバーヘッドだ。

ファイルを開くたびにProjectエンジンが全タスクの依存関係を再計算し、数分間、画面がフリーズする。これは業務効率の問題ではなく、エンジニアとしての怠慢だ。

今日は、Project VBAのライフサイクルを深く理解し、計算モードを制御することで、この不毛な待機時間を「一瞬」に変える極限の手法を伝授する。

なぜ「自動計算」がボトルネックになるのか

Projectの `Calculation` プロパティが `pjAutomatic` に設定されている状態でファイルを開くと、アプリケーションは読み込み完了直後に全スケジュールの再計算を開始する。

巨大なプロジェクトにおいて、この処理はメモリとCPUを著しく浪費する。我々が制御すべきは「開く瞬間の状態」だ。ファイルを開く前に計算モードを強制的に `pjManual`(手動)へ切り替え、必要なデータロードが完了してから計算をキックする。このプロセスを自動化の定石として組み込む必要がある。

計算モードを制御する実装コード

以下のコードは、単にファイルを開くだけではなく、アプリケーションの計算状態をバイパスして、起動のオーバーヘッドを最小化する設計となっている。

‘ プロジェクトを開く際の最適化ラッパー
Public Sub OptimizedOpenProject(ByVal filePath As String)
Dim pjApp As Object
Set pjApp = Application

‘ 1. 現在の計算モードを退避(後で戻すため)
Dim originalCalcMode As Long
originalCalcMode = pjApp.Calculation

‘ 2. 計算モードを手動に強制変更し、無駄な再計算を抑止
pjApp.Calculation = pjManual

On Error GoTo Cleanup

‘ 3. ファイルを開く
‘ 読み込み専用かつバックグラウンドでの影響を排除
FileOpenEx Name:=filePath, ReadOnly:=True

‘ — ここで必要なデータ取得や操作を行う —
Debug.Print “データ処理中…”

‘ 4. 処理完了後に計算を実行
pjApp.CalculateProject

Cleanup:
‘ 5. 計算モードを元に戻す(重要:永続的な設定変更を避けるため)
pjApp.Calculation = originalCalcMode

‘ オブジェクトの明示的解放(メモリリーク防止)
Set pjApp = Nothing
End Sub

シニアエンジニアが意識すべき「メモリの深淵」

この手法には、さらに踏み込んだ注意点が二つある。

1. アプリケーションスコープの汚染を防ぐ

VBAにおいて、`Application.Calculation` の変更は、そのセッション全体に影響を及ぼす。もし他のアドインや並行して動いているプロセスが「自動計算」を前提としている場合、予期せぬ不整合を引き起こす。必ず `originalCalcMode` を退避し、`Finally` 句に相当する `Cleanup` ラベルで確実に復元すること。

2. Windows APIによる「強制的な解放」

数万行規模のファイルを扱う際、VBAのガベージコレクションだけではメモリが解放されないケースがある。特にCOMオブジェクトを多用する場合、`Set = Nothing` だけでは不十分だ。
極限の環境では、必要に応じて以下のAPIを併用し、メモリの強制フラッシュを検討せよ。

‘ メモリ解放のためのAPI定義(極端なメモリ不足時に使用)
Private Declare PtrSafe Function SetProcessWorkingSetSize Lib “kernel32” ( _
ByVal hProcess As LongPtr, _
ByVal dwMinimumWorkingSetSize As LongPtr, _
ByVal dwMaximumWorkingSetSize As LongPtr) As Long

Private Declare PtrSafe Function GetCurrentProcess Lib “kernel32” () As LongPtr

Public Sub ForceMemoryCleanup()
‘ メモリのワーキングセットを最小化し、OSに返却を促す
SetProcessWorkingSetSize GetCurrentProcess(), -1, -1
End Sub

極限の知見:なぜ「自動計算の無効化」が勝つのか

プロジェクトの計算エンジンは「ツリー構造の再帰的な走査」を行う。タスクが1,000を超えると、この走査は指数関数的に複雑化する。起動時に一度だけこれを実行するのと、データのロードと同時に断続的に実行するのでは、後者の方がキャッシュミスが多発し、パフォーマンスが著しく低下する。

「ロード」と「計算」を分離せよ。 これが、巨大なプロジェクトを扱うための唯一の鉄則だ。

最後に:レガシーとの対峙

あなたが保守しているシステムが、10年前の設計だとしても諦める必要はない。計算モードの制御は、Projectのバージョンに依存しない原始的かつ強力なフックポイントだ。APIやメモリ制御を組み合わせ、Projectの「重さ」という概念そのものをコードで支配してほしい。

システムは、書いた通りの速度でしか動かない。そして、その速度を決めるのは常にエンジニアの深い洞察である。

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