Project VBAの深淵:リソースカレンダーをCSVで支配する極限の最適化
VBAでProjectを操作する際、多くのエンジニアが「オブジェクトの墓場」に足を踏み入れ、メモリリークという名の亡霊に悩まされる。特にリソースカレンダーの例外日管理は、数千件のタスクとリソースが絡み合うプロジェクトにおいて、一歩間違えればアプリケーションを死に至らしめる「重い」操作だ。
今日は、FSO(FileSystemObject)を用いた高速読み込みと、Projectオブジェクトモデルの脆弱性を回避するメモリ管理手法を伝授する。これは、小手先のテクニックではない。大規模プロジェクトを安定稼働させるための「防衛的アーキテクチャ」だ。
—
1. なぜ「力技」がプロジェクトを殺すのか
Project VBAでリソースカレンダー(`ResourceCalendar`)を操作する際、UI上の更新を逐次行えば、描画エンジンは悲鳴を上げる。`Application.ScreenUpdating = False` は基本だが、それだけでは足りない。
- オブジェクトのキャッシュ: カレンダーオブジェクトをループ内で何度も参照するな。一度変数に格納し、操作後は明示的に `Nothing` を代入せよ。
- 例外日追加のコスト: `CalendarException` を追加する際、無駄な再計算をトリガーさせるコードは死を招く。一括処理の際は、必ずカレンダーの境界条件を精査してから投入する。
2. 実装:高速インポートエンジンの設計
以下に、FSOを用いた堅牢かつ高速なインポート処理の雛形を提示する。エラーハンドリングを省略するのは、この領域においては「罪」である。
‘ 必要な参照設定: Microsoft Scripting Runtime, Microsoft Project Object Library
Option Explicit
Public Sub ImportResourceExceptions(ByVal csvPath As String)
Dim fso As Object
Dim ts As Object
Dim line As String
Dim res As Resource
Dim cal As Calendar
Dim exc As CalendarException
Dim parts() As String
‘ プロジェクト更新の停止(パフォーマンスの劇的向上)
Application.ScreenUpdating = False
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set ts = fso.OpenTextFile(csvPath, 1) ‘ ForReading
On Error GoTo Cleanup
Do Until ts.AtEndOfStream
line = ts.ReadLine
parts = Split(line, “,”) ‘ CSV: ResourceName,StartDate,EndDate
‘ リソースの存在確認とカレンダーへのアクセス
Set res = ActiveProject.Resources(parts(0))
Set cal = res.Calendar
‘ 例外日の追加: StartとFinishを明示的に指定
Set exc = cal.Exceptions.Add(Type:=pjExceptionTypeWorking, _
Start:=CDate(parts(1)), _
Finish:=CDate(parts(2)))
exc.Name = “Imported Holiday”
Loop
Cleanup:
‘ 明示的なオブジェクト解放(メモリリーク防止の絶対原則)
If Not ts Is Nothing Then ts.Close
Set ts = Nothing
Set fso = Nothing
Set res = Nothing
Set cal = Nothing
Set exc = Nothing
Application.ScreenUpdating = True
If Err.Number <> 0 Then
MsgBox “Critical Error: ” & Err.Description, vbCritical
End If
End Sub
3. レガシー環境を生き抜くための極限の知見
Windows APIによる「強制的な解放」の検討
VBAがメモリを解放しないケース(特にCOMオブジェクトの参照カウントが残る場合)は、稀に `CoFreeUnusedLibraries` APIを呼び出す必要がある。大規模なCSVインポートでProjectが重くなった場合、一度プロセスをクリーンに保つ設計が求められる。
ファイルロックと競合制御
もし社内システムが共有フォルダ上のファイルを対象とするなら、`OpenTextFile` の代わりにWindows APIの `CreateFile` を使い、`FILE_SHARE_READ` モードで排他制御を行え。VBAの標準機能だけに頼ると、ネットワーク切断や他者による同時アクセスでシステムがクラッシュする。
バリデーションの徹底
外部CSVは「悪意ある入力」の温床だ。
1. 日付形式の整合性: `IsDate()` でのチェックは必須。
2. リソース名の一致: `On Error Resume Next` でリソース検索をラップし、該当なしの場合はログを残してスキップする、といったフォールトトレランスを組み込め。
終わりに:アーキテクトとしての矜持
VBAは、現代の言語と比較すれば原始的かもしれない。しかし、その分、エンジニアの「制御能力」がダイレクトに実行性能に直結する。
オブジェクトを生成し、操作し、そして確実に消滅させる。この静かなるライフサイクル管理こそが、レガシーシステムを10年先まで現役で動かし続ける唯一の道だ。今日提示したコードを基に、君のプロジェクトに合わせた「最強のインポーター」を構築してほしい。
システムは、書いたコードの通りの挙動しか示さない。その責任を引き受けるのが、我々エンジニアの仕事だ。
