Project VBAの深淵:リソース稼働率ヒートマップの極限実装
多くのVBAエンジニアは、`Project.Application`オブジェクトを安易に叩き、`For Each`ループでリソースを舐めるような稚拙なコードでシステムを破綻させる。プロジェクトの規模が数千タスクを超えた瞬間、彼らのアプリケーションは「応答なし」の墓標を立てる。
真のアーキテクトは、Projectのデータモデルを「メモリ上の多次元配列」として抽象化し、Excelの再描画コストを極限まで排除する。今日は、Projectリソースの稼働負荷をヒートマップとしてExcelに展開する、エンジニアリングの真髄を説く。
—
1. アーキテクチャの鉄則:オブジェクト・オーバーヘッドの撲滅
Projectの`Resource.Assignments`を直接走査するのは自殺行為だ。COM経由のプロパティアクセスは、その一回一回が重厚なIPC(プロセス間通信)を伴う。
極意: 必要なデータは、一度のバッチ処理でVariant配列に吸い上げ、メモリ空間内で完結させる。
‘ メモリ空間への一括転送用構造体
Private Type ResourceLoad
Name As String
Workload As Double
Dates As Variant ‘ 日次負荷配列
End Type
‘ 伝説的なチーフの設計:COM呼び出しを最小化するイテレータ
Public Sub ExtractResourceData(ByRef projApp As Object)
Dim res As Object
Dim rCount As Long
‘ プロセス間通信回数を減らすため、あらかじめ範囲を絞る
With projApp.ActiveProject
rCount = .Resources.Count
‘ ここでメモリを確保する。ReDim Preserveの乱用はメモリの断片化を招くため禁忌
Dim dataMap() As ResourceLoad
ReDim dataMap(1 To rCount)
‘ 処理の詳細は割愛するが、ここで一気に配列へ格納し、
‘ ループ内での.Rangeや.Cellsアクセスは一切行わない
End With
End Sub
—
2. ヒートマップ描画の最適化:計算と描画の分離
Excelでヒートマップを描画する際、`Range.Interior.Color`を一つずつ変更する愚行は今すぐやめるべきだ。1000セルあれば1000回の再描画イベントが発生し、UIスレッドを殺す。
戦術: Excelの「条件付き書式」を数式で適用せよ。VBAの役割は、値をセルに流し込み、条件付き書式のルールを一度だけ書き換えることだ。
‘ 条件付き書式の動的適用(パフォーマンスの極致)
Sub ApplyHeatMap(targetRange As Range)
With targetRange.FormatConditions.AddColorScale(ColorScaleType:=3)
‘ 低負荷(緑)から高負荷(赤)へのグラデーションを定義
.ColorScaleCriteria(1).FormatColor.Color = RGB(0, 255, 0)
.ColorScaleCriteria(2).FormatColor.Color = RGB(255, 255, 0)
.ColorScaleCriteria(3).FormatColor.Color = RGB(255, 0, 0)
End With
End Sub
—
3. Windows APIによる「応答なし」の回避
VBAの実行中、特にProjectからのデータ抽出が重い場合、Windowsはアプリがフリーズしたと判断する。これを防ぐには、`DoEvents`という安易な魔法に頼らず、`User32.dll`の`PeekMessage`を叩き、イベントキューを適切に処理するのがプロの流儀だ。
‘ メッセージポンプの制御(高度なUI制御)
Private Declare PtrSafe Function PeekMessage Lib “user32” Alias “PeekMessageA” _
(lpMsg As Any, ByVal hwnd As LongPtr, ByVal wMsgFilterMin As Long, _
ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Sub SafeWait()
‘ DoEventsの副作用(再帰呼び出しによるスタックオーバーフロー)を回避し、
‘ UIスレッドの最低限の息継ぎを強制する
Dim msg As Any
If PeekMessage(msg, 0, 0, 0, 1) Then
‘ イベント処理をハンドリング
End If
End Sub
—
4. ライフサイクル管理:メモリリークを許すな
VBAにおいて、`Set obj = Nothing`を書き忘れるのは素人だ。しかし、真のアーキテクトは「エラーハンドリングのスコープ内での確実な解放」を徹底する。`On Error GoTo Cleanup`は、プロジェクトの安定性を担保する最後の砦である。
Public Sub MasterProcess()
Dim projApp As Object
On Error GoTo Cleanup
Set projApp = GetObject(, “MSProject.Application”)
‘ … 処理本体 …
Cleanup:
‘ 予期せぬエラー発生時も、メモリリークを許さない
If Not projApp Is Nothing Then Set projApp = Nothing
‘ オブジェクトの完全な破棄を確実にする
End Sub
—
結び:エンジニアリングは「制約」との対話である
Project VBAというレガシーな枠組みは、現代の技術スタックから見れば不自由極まりない。しかし、その制約こそが、エンジニアの腕を磨く砥石となる。
ヒートマップがExcel上で軽快に描き出されるとき、それは単なる可視化ではない。君の書いたロジックが、プロジェクトの複雑性を完全に掌握したという証拠だ。
次回の講義では、このデータをJSON化し、Web APIを介してダッシュボードへリアルタイム同期するアーキテクチャについて深掘りする。それまでに、今日のコードを自らのシステムに移植し、ボトルネックを徹底的に排除しておけ。
「動く」ことは最低条件だ。「速く、美しく、壊れない」ことこそが、伝説への入り口である。
