【テクニカル・上級編】【初心者向け】プロジェクト新規作成時にカレンダーと標準作業時間を自動適用するテンプレート活用術 – Project VBA解析バイブル

スポンサーリンク

プロジェクトの乱れは「初期設定」の欠如から始まる:MS Project VBAによるカレンダー・標準作業時間の強制適用術

長年、数千規模のリソースと複雑な依存関係を持つエンタープライズ・プロジェクトマネジメントシステム(PPM)の構築に立ち会ってきたが、プロジェクト失敗の予兆は、往々にして「新規作成されたプロジェクトファイルの無秩序さ」に現れる。

MS Projectのデフォルト設定は、極めて汎用的な「米国式」の初期値で作られている。これをそのまま日本の現場に投入すれば、カレンダーの不整合(土日祝日の無視)、日量・週当たりの標準作業時間のズレ(8時間稼働と7.5時間稼働の混同)、そしてリソース配分の致命的な誤算が連鎖的に発生する。

「新しいプロジェクトを作るたびに、手作業でベースカレンダーを変更し、稼働時間を合わせる」――このような非人間的かつヒューマンエラー必至のオペレーションを放置している組織は、アーキテクチャの観点からすでに破綻していると言わざるを得ない。

今回は、Project VBAのオブジェクトライフサイクルを完全に掌握し、ファイル新規作成の瞬間に組織標準のカレンダーと稼働時間を原子性(Atomicity)をもって適用する、実戦投入可能なコードと設計思想を解説する。

1. MS Project VBAにおける「初期化」の罠とライフサイクル

多くの初学者が陥る罠は、`FileNew` メソッドを実行した直後のオブジェクトコンテキストの喪失である。
MS ProjectのCOMオートメーションにおいて、アプリケーションインスタンスとアクティブプロジェクト(`ActiveProject`)の関係は動的であり、不適切なタイミングでのプロパティアクセスは、捕捉不可能な実行時エラーやメモリリークを引き起こす。

特に、カレンダー(`Calendar`)オブジェクトやプロジェクト情報の書き換えは、グローバルなスコープに依存するのではなく、明示的にプロジェクトオブジェクトを参照し、トランザクション的な安全性を持たせる必要がある。

さらに、レガシーな環境(Project 2010から最新のデスクトップ版まで)におけるバージョン差異を吸収するため、エラーハンドリングとオブジェクトの解放(`Set … = Nothing`)を徹底したアーキテクチャを構築しなければならない。

2. 実装コード:組織標準適用テンプレート・マクロ

以下のコードは、新規プロジェクト作成時にフックし、組織標準の「日本標準カレンダー(カスタム)」を定義・適用し、1日あたりの標準作業時間を強制的に「7.5時間」に設定するプロシージャである。

Option Explicit

‘ ==============================================================================
‘ 組織標準プロジェクト初期化モジュール
‘ アーキテクチャ設計: チーフアーキテクト
‘ 概要: 新規プロジェクトに対し、日本標準稼働時間とカスタムカレンダーを自動適用する
‘ ==============================================================================

Public Sub InitializeStandardProject()
Dim prjTarget As Project
Dim targetCalendar As Calendar
Dim originalErrorMode As Boolean

‘ 1. エラーハンドリングとパフォーマンス最適化の準備
On Error GoTo ErrorHandler

‘ 画面描画を抑制し、COM通信のオーバーヘッドを極限まで削減
originalErrorMode = Not Application.ScreenUpdating
Application.ScreenUpdating = False

‘ 2. アクティブプロジェクトの厳密な取得
‘ ※新規作成直後、あるいは既存の空き状態のプロジェクトを想定
If ActiveProjects.Count = 0 Then
FileNew Toolbar:=False, Template:=””, CreateNewFrom:=pjNewProject
End If

Set prjTarget = ActiveProject

With prjTarget
‘ 3. プロジェクト基本プロパティの設定(標準作業時間の強制)
‘ MS Project内部では時間は「分」単位で保持される(7.5時間 = 450分)
.MinutesPerDay = 450 ‘ 1日の標準作業時間: 7.5時間
.MinutesPerWeek = 2250 ‘ 1週間の標準作業時間: 37.5時間
.DaysPerMonth = 20 ‘ 月間標準稼働日数: 20日

‘ 4. カレンダーオブジェクトの取得または生成
On Error Resume Next
Set targetCalendar = .Calendars(“組織標準カレンダー”)
On Error GoTo ErrorHandler

If targetCalendar Is Nothing Then
‘ 存在しない場合は「標準」をベースに新規作成
Set targetCalendar = .Calendars.Add(“組織標準カレンダー”, “標準”)
End If

‘ 5. カレンダーのベース適用
.Calendar = targetCalendar.Name

‘ 6. 稼働日詳細の調整(例:土日を非稼働、特定の例外日を追加するなど)
Call ConfigureWorkingTimes(targetCalendar)
End With

‘ 正常終了時の処理
Application.ScreenUpdating = True
MsgBox “組織標準のプロジェクト初期化が正常に完了しました。”, vbInformation, “System Architecture”
GoTo CleanUp

ErrorHandler:
‘ 障害発生時のログ出力とフェイルセーフ
Application.ScreenUpdating = True
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “Error Handler”

CleanUp:
‘ 7. メモリの明示的解放(COMオブジェクトの参照リーク防止)
Set targetCalendar = Nothing
Set prjTarget = Nothing
End Sub

‘ ==============================================================================
‘ 内部プロシージャ: カレンダーの詳細稼働時間・例外日の設定
‘ ==============================================================================
Private Sub ConfigureWorkingTimes(ByRef cal As Calendar)
Dim dayIdx As Long

‘ 例として、土曜日(pjSaturday)と日曜日(pjSunday)を非稼働日に設定
‘ ※環境のロケールやProjectのバージョン依存を排除するため曜日列挙体を使用
With cal
‘ 曜日の設定: 1=日曜日, 2=月曜日 … 7=土曜日
‘ 休日設定 (Working = False)
.WeekDays(pjSunday).Working = False
.WeekDays(pjSaturday).Working = False

‘ 平日の標準稼働時間を厳密に定義 (例: 09:00 – 18:00, 休憩 12:00 – 13:00)
For dayIdx = pjMonday To pjFriday
With .WeekDays(dayIdx)
.Working = True
.WorkTimes.Clear
.WorkTimes.Add From:=TimeSerial(9, 0, 0), To:=TimeSerial(12, 0, 0)
.WorkTimes.Add From:=TimeSerial(13, 0, 0), To:=TimeSerial(18, 0, 0)
End With
Next dayIdx
End With
End Sub

3. コードの極限解説:なぜこの実装が必要なのか

1. メモリ管理とCOMオブジェクトの明示的解放

VBAのガベージコレクションは頼りにならない。特にMS ProjectのCOMインターフェースは参照カウント方式をとっており、スクリプト終了時に `Set prjTarget = Nothing` や `Set targetCalendar = Nothing` を怠ると、バックグラウンドで `WINPROJ.EXE` のプロセスがゾンビ化し、メモリリークやファイルロックの原因となる。生産性を極限まで高めるシステムでは、リソースのライフサイクル管理はエンジニアの義務である。

2. 「分単位」のデータ構造の理解

MS Project内部のエンジンは、時間を「分(Minutes)」で管理している。GUI上では「7.5時間」と表示されていても、APIを叩く際は `MinutesPerDay = 450` と明示的に整数値を渡さなければならない。ここを浮動小数点数や時間型(Date)のまま処理しようとすると、丸め誤差によりスケジュール計算に数分のズレが生じ、数千タスク規模のプロジェクトにおいて致命的なスケジュール破綻を招く。

3. `Application.ScreenUpdating` による描画コストの排除

カレンダーの曜日ごとの `WorkTimes` を書き換える処理は、内部的にGUIの再描画イベントを引き起こす。これを放置すると、マクロの実行速度が著しく低下する。実行前に画面描画を切り、最後に復元するイディオムは、大規模バッチ処理における基本中の基本である。

4. エンタープライズ展開への布石:グローバルテンプレート(GLOBAL.MPT)への統合

このマクロを単体のプロジェクトファイルに閉じ込めておいては意味がない。組織内のすべてのプロジェクトマネージャーに強制力を持たせるためには、このロジックを `GLOBAL.MPT`(グローバルテンプレート) の `Auto_New` またはリボンカスタマイズのイベントプロシージャとして組み込む必要がある。

あるいは、企業のCI/CDパイプラインやSharePointなどのドキュメント管理システムと連携し、新規プロジェクト生成用のマスターテンプレートファイル(`.mpp`)にあらかじめこのVBAモジュールを埋め込んでおき、プロジェクト生成API経由で自動キックするアーキテクチャが望ましい。

規律のない自由は、プロジェクトの遅延という名の負債を産むだけだ。
コードによって環境を支配し、人為的ミスが入り込む余地を完全に排除せよ。それが、真のエンジニアリングである。

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