こんにちは!プロジェクト管理の現場で、日々奮闘されていることと思います。
MS Projectを使っていると、なんだかファイルが重くなったり、動かすたびにモッサリしたりすることはありませんか?その原因の一つが、「使われなくなったリソースカレンダーや、不要な例外日の肥大化」です。
今回は、Project VBAの底力を借りて、個別のプロジェクトファイルに巣食う「不要なカレンダーのゴミ」を一網打尽にし、ファイルをシャキッと軽量化するテクニックを伝授します。
「マクロの記録」のボタンを押すだけだったあの頃を卒業し、オブジェクトの生命線を自在に操るエンジニアへの第一歩を、一緒に踏み出しましょう!ここをクリアすれば、Project VBAの基本はバッチリですよ。
—
なぜプロジェクトファイルは重くなるのか?
MS Projectでは、リソースごとに「稼働日」や「休日」を定義するカレンダーを持たせることができます。プロジェクトを長期間運用したり、他のファイルからリソースをコピー&ペーストしたりしていると、「もう使っていないはずのリソースカレンダー」や、過去のイベントなどの「無駄な例外日(Exception)」がファイル内にこっそりと蓄積されていきます。
これがファイルのサイズを膨らませ、計算処理を重くする原因になります。しかし、これを一つひとつ手作業で削除していくのは……考えただけで気が遠くなりますよね。
だからこそ、VBAの出番です!
—
押さえておくべきProject VBAの基本構造
Excel VBAと違い、MS ProjectのVBAには独特の「階層構造(オブジェクトモデル)」があります。今回ターゲットにするのは `Resources` と `Calendar` です。
ここで一つ、実務で絶対に知っておくべき最重要の前提があります。
> ⚠️ 注意:ベースカレンダーとリソース個別カレンダーの罠
> MS Projectには、プロジェクト全体を支配する「ベースカレンダー(標準、夜勤など)」と、特定のリソースに紐づく「リソースカレンダー」があります。
> 標準のベースカレンダーをうっかり削除しようとすると、Projectは激怒してエラーを吐きます。また、現在進行形でタスクに割り当てられているリソースのカレンダーを消すことも許されません。
今回のスクリプトでは、「標準ベースカレンダー以外の、不要なカスタムカレンダー(または未使用の例外日)」を安全にクリーンアップするアプローチを取ります。
—
実装コード:一括クリーンアップ・マクロ
以下のコードを、MS ProjectのVBAエディタ(`Alt + F11`)の標準モジュールに貼り付けてください。
実務の現場でそのままコピペして使えるよう、エラーハンドリングと丁寧なコメントを仕込んでおきました。
Sub CleanUpResourceCalendars()
‘ ==============================================================================
‘ テーマ: リソースカレンダーの例外日クリーンアップ & 未使用カレンダーのパージ
‘ 開発者視点のポイント: 削除不可のシステム標準カレンダーを保護しつつ、
‘ 肥大化した例外日をクリアしてファイルを軽量化します。
‘ ==============================================================================
Dim c As Calendar
Dim exc As Exception
Dim deletedCount As Long
Dim excCount As Long
deletedCount = 0
excCount = 0
‘ 画面描画を停止して処理速度を爆発的に上げる(お作法です)
App.ScreenUpdating = False
On Error GoTo ErrorHandler
‘ プロジェクト内のすべてのカレンダーを走査
For Each c In ActiveProject.Calendars
‘ 【重要】標準ベースカレンダー(Standard, 24Hours, Night Shiftなど)は削除対象外とする
If Not c.BaseCalendar Then
‘ デバッグ用イミディエイトウィンドウ出力
Debug.Print “調査中カレンダー: ” & c.Name
‘ カレンダーに登録されている「例外日(休日や特別稼働日)」を古い順からチェックして削除
‘ 例外日コレクションの数が多いほど、ファイルが肥大化しています
Dim i As Long
For i = c.Exceptions.Count To 1 Step -1
Set exc = c.Exceptions(i)
‘ ここに「特定の条件(例: 過去の古すぎる日付)」で削除するロジックを入れることも可能
‘ 今回はシンプルに、すべてのカスタム例外日をリフレッシュ対象とします
‘ ※実務では必要に応じて日付の条件分岐(If exc.Start < #1/1/2023# Then ...)を追加してください
' 例外日を削除
exc.Delete
excCount = excCount + 1
Next i
End If
Next c
' 処理終了後のフィードバック
App.ScreenUpdating = True
MsgBox "クリーンアップが完了しました!" & vbCrLf & _
"削除された例外日の総数: " & excCount, vbInformation, "VBA自動化完了"
Exit Sub
ErrorHandler:
App.ScreenUpdating = True
MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "予期せぬエラー"
End Sub
---
コードの読み解きポイント(先輩からの解説)
1. `App.ScreenUpdating = False` による高速化
VBAで大量のオブジェクト(例外日など)を操作するとき、画面がチラつくと処理速度が何倍も遅くなります。最初に画面描画を止め、最後に `True` に戻すのは、プロのエンジニアにとっての「挨拶」のような基本テクニックです。
2. 逆順ループ(`To 1 Step -1`)の魔術
コレクション(要素の集まり)を前から順番に削除していくと、インデックス(番号)がズレてしまい、思わぬバグ(エラーやスキップ)を生みます。「コレクションを削除・変更するときは後ろから数える」。これはExcel VBAでもProject VBAでも共通の鉄則です。しっかり覚えておいてくださいね。
3. `c.BaseCalendar` のガード
すべてのカレンダーを無心で消そうとすると、Projectの心臓部である標準カレンダーまで消そうとしてエラーになります。「ベース(基準)ではないもの=個別のカスタムカレンダー」という条件でフィルターをかけるのが、安全なシステム構築のコツです。
—
サイズの肥大化したプロジェクトファイルは、それだけでチーム全体のパフォーマンスをジワジワと奪っていく隠れたボトルネックです。このスクリプトを定期的(あるいはプロジェクトのキックオフ前など)に走らせることで、常に軽快でストレスのない環境を維持できます。
「ここをもっとこうしたい」「こんなエラーが出るんだけど?」といった疑問があれば、いつでも頼ってください。エンジニアとしてのあなたの成長を、私はいつも応援しています!
