【Project VBAを掌握する極限の知見】新規プロジェクト自動初期化:標準カレンダー強制適用のアーキテクチャ
MS Projectの標準動作は、時として我々エンジニアの設計思想に正面から逆行する。
新規プロジェクトを作成した瞬間、システムは米国式標準カレンダー(週40時間、土日休業、8:00始業など)を勝手に割り当てる。日本の祝祭日、独自の三六協定に基づく残業規定、あるいは現場ごとのシフト制を採用する組織において、このデフォルト挙動はすべてのスケジュール計算を狂わせる「毒」に他ならない。
手動で「変更」ボタンを押し、稼働時間を再定義する作業は、ヒューマンエラーの温床であり、全社的なガバナンスの欠如を意味する。
今回は、Project VBAのライフサイクル、そしてCOMオブジェクトの隠れた挙動を熟知した者だけが実装できる、「新規プロジェクト生成フックと標準カレンダー強制適用エンジン」の全貌を解説する。
—
1. MS Projectにおけるカレンダー管理の構造的罠
初心者向けの解説では「`FileNew`イベントを使えばよい」と安易に語られるが、実務の現場はそんなに甘くない。
MS Projectのオブジェクトモデルにおいて、カレンダー(`Calendar`オブジェクト)はグローバル(Organizer)またはプロジェクト固有のコレクションとして存在する。
ここで重要なのは、「ベースカレンダー(Base Calendar)」と「タスク/リソースカレンダー」の分離である。
新規プロジェクト作成時、プロジェクト自体の基本カレンダー(Project Calendar)を自社標準(例:「日本標準カレンダー」)に書き換えるには、単に名前を指定するだけでは不十分だ。テンプレートファイル(`.mpt`)の読込順序、あるいはCOMメモリ空間でのインスタンス生成タイミングを厳密に制御しなければならない。
アーキテクチャの要件
1. イベントの非同期捕捉: `NewProject`イベントを確実に捉え、空っぽのプロジェクトインスタンスがメモリ上に展開された瞬間を狙い撃つ。
2. マスターカレンダーの存在確認・同期: 組織の標準カレンダーがローカルまたはグローバル(Global.mpt)に存在しない場合のエラーハンドリング。
3. メモリ最適化: COMオブジェクトの参照リークを防ぎ、複数プロジェクト同時オープン時のメモリ肥大化を完全阻止する。
—
2. 実装コード:堅牢性を極めた自動適用エンジン
以下のコードは、MS ProjectのThisProject(またはアドイン)に実装し、新規作成イベントをフックして強制的に自社標準カレンダーをバインドするプロダクションコードである。
Option Explicit
‘ ==============================================================================
‘ Module: clsProjectInitializer
‘ Description: 新規プロジェクト作成時に自社標準カレンダーを強制適用するイベントクラス
‘ ==============================================================================
Private WithEvents AppEvents As MSProject.Application
‘ 定数定義:自社の標準カレンダー名称
Private Const TARGET_CALENDAR_NAME As String = “日本標準カレンダー_2024”
Private Const DEFAULT_HOURS_PER_DAY As Double = 8#
Private Const DEFAULT_HOURS_PER_WEEK As Double = 40#
‘ イニシャライザー
Public Sub Initialize(ByVal appInstance As MSProject.Application)
Set AppEvents = appInstance
End Sub
‘ 新規プロジェクト作成イベントの捕捉
Private Sub AppEvents_NewProject(ByVal pj As MSProject.Project)
Dim targetCal As MSProject.Calendar
Dim isCalendarFound As Boolean
On Error GoTo ErrorHandler
‘ プロジェクトが正常にロードされているか検証
If pj Is Nothing Then Exit Sub
‘ 1. 対象プロジェクトの基本設定を上書き(稼働時間等の標準化)
With pj
.WorkWeeks.Add ‘ 必要に応じたカスタム週設定の初期化
End With
‘ 2. グローバルまたはプロジェクト内のカレンダーコレクションを走査
isCalendarFound = False
For Each targetCal In pj.Calendars
If targetCal.Name = TARGET_CALENDAR_NAME Then
isCalendarFound = True
Exit For
End If
Next targetCal
‘ 3. 標準カレンダーが存在しない場合のフォールバック(またはOrganizer経由のインポート)
If Not isCalendarFound Then
‘ ※実務ではここで外部テンプレートやGlobal.mptからカレンダーをインポートする処理を記述
MsgBox “警告: 指定された標準カレンダー ‘” & TARGET_CALENDAR_NAME & “‘ が見つかりません。”, vbCritical, “カレンダー適用エラー”
GoTo CleanUp
End If
‘ 4. プロジェクトの標準カレンダーとして強制適用
‘ ※ProjectオブジェクトのCalendarプロパティはベースカレンダー名を要求する
pj.Calendar = TARGET_CALENDAR_NAME
‘ 5. デフォルトの稼働時間(日・週)を明示的に再設定し、計算エンジンの齟齬を防ぐ
‘ (MS Project内部のバグ回避のため、明示的な数値代入が不可欠)
ActiveProject.HoursPerDay = DEFAULT_HOURS_PER_DAY
ActiveProject.HoursPerWeek = DEFAULT_HOURS_PER_WEEK
‘ ログ出力(システム管理者向け)
Debug.Print “[” & Now & “] SUCCESS: Project ‘” & pj.Name & “‘ に標準カレンダーを適用しました。”
CleanUp:
‘ COMオブジェクトの明示的解放(メモリ最適化の極意)
Set targetCal = Nothing
Exit Sub
ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “ProjectInitializer Engine”
Resume CleanUp
End Sub
—
3. チーフアーキテクトが教える「現場の知見」とパフォーマンス最適化
初心者は「動けばいい」と考えがちだが、シニアエンジニアは「リソースのライフサイクル」と「環境依存の罠」に目を光らせる。今回の実装における極限の知見を授けよう。
① COMオブジェクトのデリファレンスとメモリリーク対策
VBAのガベージコレクションは頼りにならない。特に`For Each`ループ内で取得した`Calendar`などのCOMオブジェクトは、参照カウンタがインクリメントされたままメモリ上に残留しやすい。
上記のコードで `Set targetCal = Nothing` をループ外のクリーンアップブロックに記述しているのは、複数回生成・破棄されるアドイン環境下でのメモリリーク(HRESULT: 0x80010108 等のオートメーションエラー)を物理的に根絶するためである。
② イベントハンドラの多重登録を防ぐライフサイクル管理
`WithEvents`を使用する場合、アドインやアドホックなマクロ実行時にイベントクラスのインスタンスが複数生成されると、1回の新規作成に対してイベントが重複発火する「イベントの多重実行地獄」に陥る。
これを防ぐため、必ずアドインのロード時(`Auto_Open` または `AddIn_Startup`)にシングルトンパターンに近い形でイベントクラスを初期化すること。
‘ 標準モジュールでのインスタンス保持例
Public G_Initializer As clsProjectInitializer
Sub Auto_Open()
Set G_Initializer = New clsProjectInitializer
G_Initializer.Initialize Application
End Sub
Sub Auto_Close()
Set G_Initializer = Nothing
End Sub
③ システム間連携(ERP/PPMとの統合)におけるカレンダーの重要性
このマクロによって「すべての新規プロジェクトが同一の標準カレンダーを持つこと」が担保されると、後続のシステム間連携(例:SAPや独自基幹システムへのWBS・工数データのエクスポート)において、「稼働日数の計算ズレによる予実管理の破綻」を100%予防できるようになる。
APIやバッチ連携の成否は、入口である「プロジェクト作成の瞬間」のデータ整合性で決まるのだ。
—
結び
テンプレート活用とは、単なるファイルのコピーではない。組織のルールをコードによって物理法則レベルで強制することを指す。
属人化を排除し、誰もが規準化されたスケジュール空間でプロジェクトを立ち上げられる環境を作るこそこそが、真のシステム管理者・アーキテクチャ設計者の使命である。
妥協なきコードで、レガシーなプロジェクト管理を次のステージへ引き上げよ。
