【テクニカル・上級編】リソースの「カレンダー」を個別のプロジェクトファイルから一括削除するクリーンアップ – Project VBA解析バイブル

スポンサーリンク

Project VBAを掌握する極限の知見:肥大化したリソースカレンダーの外科的クリーンアップ

Microsoft ProjectのVBA開発において、避けて通れないのが「リソースとカレンダーの肥大化」という構造的な呪縛である。
プロジェクトが長期化し、リソースの追加・削除、組織変更、外部リソースのインポートを繰り返すうちに、Projectファイル(.mpp)の内部データベースには「幽霊のような」未使用の例外日、不要なベースカレンダー、そして孤立したリソース割り当てデータが蓄積されていく。

これらはファイルサイズを膨らませるだけでなく、計算エンジンのパフォーマンスを著しく低下させ、最悪の場合はファイル破損(XML破損や内部ポインタの不整合)を引き起こす。

本稿では、Project VBAのオブジェクトモデルの深層に切り込み、メモリのリークを防ぎながら、個別プロジェクトファイルから不要なリソースカレンダーおよび例外日をプログラムによって一括削除・浄化する、極限のクリーンアップ手法を解説する。

—

1. Projectオブジェクトモデルの闇:カレンダーとリソースのライフサイクル

多くの初学者は、`Project.Resources` や `Project.Calendars` をループさせ、単純に `.Delete` メソッドを叩けばクリーンアップできると錯覚する。しかし、ProjectのCOMインターフェースはそれほど単純ではない。

参照整合性の壁

リソースカレンダーは、単体で存在しているわけではない。
1. ベースカレンダー (Base Calendar): すべてのカレンダーの基礎。
2. リソースカレンダー (Resource Calendar): 個別のリソースに紐付くベースカレンダーの派生、または独自の上書き(例外日など)。
3. タスクの制約・割り当て: リソースがタスクにアサインされている場合、カレンダーを強制削除するとProjectのスケジュールエンジンが例外(Run-time error)を吐くか、最悪の場合、内部ポインタが宙ぶらりんになる。

したがって、クリーンアップのアルゴリズムは以下の順序を厳守しなければならない。
1. 未使用判定: どのタスクにもアサインされておらず、かつ特定の基準日以降の稼働実績を持たないリソースの特定。
2. 例外日のパージ: 削除できないリソースであっても、過去の過剰な例外日(Exception)をプログラムで剥ぎ取る。
3. 安全な削除: 依存関係を断ち切った上でのオブジェクトの明示的解放。

—

2. 実装:リソースカレンダー一括クリーンアップ・エンジン

以下のコードは、実務の現場で耐えうる堅牢性を持たせたVBAモジュールである。メモリの無駄な消費を防ぐため、オブジェクト変数は適切に解放し、エラーハンドリングを徹底している。

Option Explicit

‘ ==============================================================================
‘ プロジェクト名: Project Calendar & Resource Cleaner
‘ 概要 : 未使用リソースおよび肥大化した例外日をパージし、mppを軽量化する
‘ アーキテクト: 伝説のチーフアーキテクト
‘ ==============================================================================
Sub PurgeUnusedResourceCalendars()
Dim prj As Project
Set prj = ActiveProject

Dim res As Resource
Dim cal As Calendar
Dim exc As Exception
Dim i As Long, j As Long

‘ パフォーマンス向上のためのUI描画停止(トランザクション処理の思想)
Application.ScreenUpdating = False
On Error GoTo ErrorHandler

Debug.Print “=== クリーンアップ開始: ” & prj.Name & ” ===”

‘ 1. リソースに紐付く不要な例外日のパージ(カレンダー自体の削除ではなく軽量化)
For Each res In prj.Resources
If Not res Is Nothing Then
‘ リソース固有のカレンダーが存在するか確認
On Error Resume Next
Set cal = res.Calendar
On Error GoTo ErrorHandler

If Not cal Is Nothing Then
‘ 過去の過剰な例外日(例: 1年以上前のもの)を削除して軽量化
For j = cal.Exceptions.Count To 1 Step -1
Set exc = cal.Exceptions(j)
‘ 例: 過去ログとしての価値がない古い例外日を削除対象とする
If exc.Finish < DateAdd("yyyy", -1, Date) Then exc.Delete End If Next j End If End If Next res ' 2. アサインメントが存在しない「幽霊リソース」の検出と削除 ' 逆順ループによる安全なコレクション操作 For i = prj.Resources.Count To 1 Step -1 Set res = prj.Resources(i) If Not res Is Nothing Then ' コストや氏名が空、かつタスクアサインがゼロの完全なゴーストリソース If res.Assignments.Count = 0 And (res.Name = "" Or res.StandardRate = 0) Then Debug.Print "ゴーストリソースを削除: ID=" & res.ID & ", Name=" & res.Name res.Delete End If End If Next i Debug.Print "=== クリーンアップ正常終了 ===" MsgBox "リソースカレンダーのクリーンアップが完了しました。", vbInformation, "システム最適化" CleanUp: ' オブジェクト変数の明示的解放(メモリリーク防止) Set exc = Nothing Set cal = Nothing Set res = Nothing Set prj = Nothing Application.ScreenUpdating = True Exit Sub ErrorHandler: MsgBox "予期せぬエラーが発生しました: " & Err.Description, vbCritical, "致命的エラー" Resume CleanUp End Sub ---

3. チーフアーキテクトの知見:メモリ最適化とパフォーマンスの極意

オブジェクトの明示的解放 (`Set … = Nothing`)

VBAのガベージコレクションは頼りにならない。特にMicrosoft ProjectのCOMラッパーは、`For Each` ループ内で暗黙的に参照が保持され続け、プロシージャを抜けてもメモリ上に残存するケース(メモリリーク)が多々発生する。
上記のコードでは、処理の最後に必ずすべてのオブジェクト変数に `Nothing` を明示的に代入し、COMコンポーネントの参照カウントを強制的にデクリメントしている。

逆順ループ (`Step -1`) の鉄則

コレクションの要素(`Resources`, `Exceptions` など)を削除する場合、先頭からループを回すとインデックスがズレて致命的な実行時エラー(インデックスが範囲外です)を引き起こす。
「コレクションの破壊的変更は必ず末尾から逆順で行う」。これはVBAに限らず、すべてのマネージド・アンマネージド開発における不変の鉄則である。

画面描画の抑制 (`Application.ScreenUpdating = False`)

数千行に及ぶリソースやタスクを持つ大規模プロジェクトにおいて、VBAからオブジェクトを操作するたびにProjectのGUIエンジンが再描画を行っていると、処理時間が何倍にも跳ね上がる。
処理の冒頭で描画を切り、最後に復元することで、I/Oのオーバーヘッドを極限まで削減する。

—

4. システム間連携を見据えたレガシー保守の心得

企業内の基幹システム(SAPやP6、独自ERPなど)とMicrosoft Projectを連携させる際、XMLインポート/エクスポート機能やODBC経由でのデータ同期が頻繁に行われる。
この時、外部システムからゴミのようなカスタムカレンダーや重複したリソースIDが持ち込まれ、プロジェクトファイルが「メタデータの肥大化」を起こす。

定期的に上記のVBAスクリプトをアドイン(.global または .ppa)として組み込み、プロジェクトオープン時(`Open` イベント)あるいはクローズ時(`BeforeClose` イベント)にバックグラウンドで走らせるアーキテクチャを構築すること。それこそが、何年もの間メンテナンスされ続けるレガシーシステムを破綻から守る唯一の防壁となる。

妥協のないコードとアーキテクチャ設計こそが、プロフェッショナルなエンジニアリングの証である。

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