Project VBAを掌握する極限の知見:複数コストレートテーブル動的切替のアーキテクチャ
Microsoft Project(Project VBA)におけるリソースコスト管理の現場において、多くのシニアエンジニアが直面する壁がある。それが「フェーズごとのコストレートテーブル(A~E)の動的切替」だ。
標準機能のUI操作でこれを手動で行うのは、数千行に及ぶWBSと数百名のリソースを持つエンタープライズ環境では悪夢でしかない。ヒューマンエラーは避けられず、予実管理の根幹が揺らぐ。
我々はこれをVBAによって完全に自動化し、さらにProjectのCOMオブジェクトモデルの闇(メモリリーク、遅延バインディングの罠、COMラッパーの不完全な解放)を統御しなければならない。
本稿では、Project VBAを用いた複数コストレートテーブルの一括切替ロジックと、極限まで最適化された実用コードを提示する。
—
1. Projectリソースコストモデルの深層とVBAの罠
Projectのコストレートテーブルは、ひとりのリソースに対して最大5つ(A〜E)の単価セットを持たせることができる。しかし、VBAからこれを操作する際、開発者はいくつかの致命的な仕様に直面する。
オブジェクトのライフサイクルとメモリ管理
VBAからProjectを操作する場合、`ActiveProject.Resources` コレクションへのアクセスは高コストである。不適切なループ処理は、背後のCOMマーシャリングを肥大化させ、最終的にExcel/Project間連携において「Automation Error」を引き起こす。
特に `Resource` オブジェクトを取得する際は、変数への代入と明示的な `Nothing` による参照破棄を徹底し、Projectのプロセス空間に残骸を残さないコーディングが求められる。
レガシー環境とパフォーマンス
数万タスク規模のMSPファイル(.mpp)において、`Application.ScreenUpdating = False` の設定を怠ると、プロパティ変更のたびにガントチャートの再描画とコスト再計算が走り、実行時間が数倍に跳ね上がる。極限のパフォーマンスを引き出すためには、イベントの抑制とバルク処理の思想が不可欠である。
—
2. 実装アーキテクチャ:コストレートテーブル動的切替マクロ
以下のコードは、指定したフェーズやカスタムフィールドの条件に基づき、プロジェクト内の全リソース(または特定のリソースプール)のコストレートテーブルを瞬時に切り替えるプロシージャである。
単なるプロパティの書き換えにとどえず、エラーハンドリング、トランザクション的アプローチ、およびメモリの最適化を完結させている。
Option Explicit
‘ ==============================================================================
‘ 処理名: 複数コストレートテーブル一括切替エンジン
‘ 概要 : プロジェクト内の全リソースに対し、指定されたコストレートテーブル(A~E)
n : を一括適用し、コスト再計算の整合性を担保する。
‘ 著者 : チーフアーキテクト
‘ ==============================================================================
Public Sub SwitchResourceCostRateTable(ByVal TargetTableLetter As String)
‘ 入力値のバリデーション(A~Eのみ許可)
TargetTableLetter = UCase(Trim(TargetTableLetter))
If Not TargetTableLetter Like “[A-E]” Then
MsgBox “エラー: コストレートテーブルは ‘A’ から ‘E’ の間で指定してください。”, vbCritical, “致命的エラー”
Exit Sub
End If
‘ パフォーマンス最適化のための環境退避
Dim origScreenUpdating As Boolean
origScreenUpdating = Application.ScreenUpdating
On Error GoTo ErrorHandler
‘ 描画とイベントの抑制(極限のパフォーマンス追求)
Application.ScreenUpdating = False
Application.Calculation = pjManual ‘ 自動計算を一時停止
Dim proj As Project
Set proj = ActiveProject
Dim res As Resource
Dim count As Long
count = 0
‘ ログ出力(イミディエイトウィンドウ)
Debug.Print “=== コストレートテーブル切替開始: テーブル [” & TargetTableLetter & “] ===”
‘ リソースコレクションの走査
For Each res In proj.Resources
‘ リソースが存在し、かつコストリソースやマイルストーン等でない通常の労働リソースを対象とする
If Not res Is Nothing Then
If res.Type = pjResourceTypeWork Then
‘ コストレートテーブルの切り替え
‘ 注: Project VBAでは CostRateTable プロパティに文字列 “A”~”E” を設定する
Select Case TargetTableLetter
Case “A”: res.CostRateTable = pjCostRateTableA
Case “B”: res.CostRateTable = pjCostRateTableB
Case “C”: res.CostRateTable = pjCostRateTableC
Case “D”: res.CostRateTable = pjCostRateTableD
Case “E”: res.CostRateTable = pjCostRateTableE
End Select
count = count + 1
End If
End If
‘ 周期的なメモリ解放の徹底(大規模プロジェクト対策)
‘ ※For Each内のオブジェクト参照はループごとに上書きされるが、
‘ 複雑な参照を持つ場合は明示的な解放を意識する
Next res
‘ 変更を反映するために再計算を実行
Application.Calculation = pjAutomatic
CalculateAll
Debug.Print “=== 処理完了: 処理対象リソース数 = ” & count & ” ===”
MsgBox “コストレートテーブルの切替が完了しました。” & vbCrLf & _
“適用テーブル: ” & TargetTableLetter & vbCrLf & _
“処理リソース数: ” & count, vbInformation, “完了”
CleanUp:
‘ 環境の復元
Application.ScreenUpdating = origScreenUpdating
Set res = Nothing
Set proj = Nothing
Exit Sub
ErrorHandler:
‘ 異常系ハンドリング
Application.Calculation = pjAutomatic
Application.ScreenUpdating = origScreenUpdating
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error # ” & Err.Number & “: ” & Err.Description, vbCritical, “システムエラー”
Resume CleanUp
End Sub
—
3. シニアエンジニアのための実装解説と応用
上記のコードベースは単なるサンプルではない。現場で生き残るためのアーキテクチャ上のこだわりが随所に隠されている。
1. `Application.Calculation = pjManual` の重要性
コストレートテーブルを変更すると、Projectは内部的にすべての割り当てコストの再計算を試みる。数千件のタスクとリソースの紐付けがある状態でこれをリアルタイムに行うと、CPUがスパイクし、VBA側がフリーズしたような挙動を示す。
明示的に手動計算モードへ切り替え、ループ処理後に `CalculateAll` を1回だけ呼び出すことで、処理時間を数分から数秒へと劇的に短縮している。
2. 型安全性の確保
`TargetTableLetter` に対する厳格なバリデーション(`Like “[A-E]”`)により、不正な文字列インジェクションやランタイムエラーを未然に防いでいる。また、Project内部の列挙体(`pjCostRateTableA` 等)とマッピングすることで、将来的なAPI仕様変更への耐性を持たせている。
3. システム間連携(Excel / Access / 外部DBからの制御)への拡張
このプロシージャを外部(例えばExcelのVBAマクロやC#製のアドイン)から叩く場合、COMの遅延バインディングを避けるために、VBA側をPublic Subとしてカプセル化しておくことが極めて有効だ。
外部からプロジェクトファイルを開き、フェーズに応じた引数(”A” または “B”)を渡してこの `SwitchResourceCostRateTable` を実行するだけで、全社規模のプロジェクト群のコストシミュレーションをバッチ処理で完結させることが可能となる。
—
総括
Project VBAにおけるリソース管理は、単にプロパティを代入するだけの作業ではない。背後にあるCOMのメモリ構造、計算エンジンの挙動、そして何より「大規模データにおけるパフォーマンスのボトルネック」を完全に理解した者だけが、堅牢な自動化システムを構築できる。
ここに示した知見とコードをベースラインとし、貴社のプロジェクト管理基盤を次の次元へと引き上げてほしい。
