【テクニカル・上級編】【実務直結】Project VBAで「タスクの重複」を検知し、警告を出す品質管理スクリプト – Project VBA解析バイブル

スポンサーリンク

Project VBAを掌握する極限の知見:タスク重複検知による品質管理エンジニアリング

Microsoft Project(以下、MS Project)におけるVBA開発は、Excel VBAの延長線上で捉えると痛い目を見る。オブジェクトモデルの階層構造、非同期なスケジュール計算エンジン、そしてCOMのメモリ管理の癖。これらを理解せずして、実用に耐えるマクロを書くことはできない。

今回は、大規模プロジェクトにおいて頻発する「同一リソースに対するタスクの重複(ダブルブッキング)」および「論理的なスケジュール矛盾」を自動検知し、データ品質を担保するための実務直結型スクリプトを公開する。

単なるコードの提示ではない。シニアエンジニアが現場で直面するパフォーマンス問題や、MS Project特有の罠を回避するための知見を凝縮した。

1. MS Projectオブジェクトモデルの暗黒面とメモリ管理

Excelであれば `ActiveSheet.Cells` と安易に参照できるが、MS Projectのオブジェクトモデルにおいて、これを無造作に行うことはメモリリークやパフォーマンス低下の直接の原因となる。

圧倒的なパフォーマンスを引き出す鉄則

1. Applicationオブジェクトのスコープ制御: ループ内で `ActiveProject` や `ActiveSelection` を多用してはならない。コンテキストスイッチングのオーバーヘッドが処理速度を殺す。
2. COMオブジェクトの明示的解放: 特に `Task` や `Resource` をループで回す際、変数への代入と解放を意識しないと、VBEの背後でCOMラッパーがメモリを食潰し、最悪の場合ExcelやProjectごとクラッシュする。
3. Calculation(計算モード)の制御: 大量のタスクを一括操作・走査する場合、自動再計算(Calculation)が有効なままだと、1タスク変更するたびにスケジュールエンジンが走り、処理が10倍以上遅くなる。

2. 実装:タスク重複・品質チェックエンジン

以下のコードは、アクティブプロジェクト内の全タスクを走査し、「同一リソースに割り当てられたタスク間で、期間(Start〜Finish)が重複している箇所」を検知してイミディエイトウインドウおよびカスタムログに出力、さらに該当タスクのフラグを立てる実用スクリプトである。

Option Explicit

‘ ==============================================================================
‘ 処理名: Project Data Quality Control – Task Overlap Detector
‘ 概要 : 同一リソースに対するタスクのスケジュール重複を検知し、品質を担保する
‘ 著者 : 伝説のチーフアーキテクト
‘ ==============================================================================
Public Sub DetectTaskOverlaps()
Dim prj As Project
Set prj = ActiveProject

‘ パフォーマンス最適化:画面描画と自動計算を停止
Application.ScreenUpdating = False
Application.Calculation = pjManual

On Error GoTo ErrorHandler

Dim t1 As Task, t2 As Task
Dim r1 As Resource, r2 As Resource
Dim a1 As Assignment, a2 As Assignment
Dim conflictCount As Long
conflictCount = 0

Debug.Print “=== [QUALITY CHECK] タスク重複検知スキャン開始: ” & Now & ” ===”

‘ 1. フラグフィールド(Flag1)の初期化(前回の検知結果クリア)
For Each t1 In prj.Tasks
If Not t1 Is Nothing Then
If Not t1.Summary Then
t1.Flag1 = False
End If
End If
Next t1

‘ 2. O(N^2)の総当たりを効率化するため、リソース視点でアサインメントを解析
Dim r As Resource
For Each r in prj.Resources
If Not r Is Nothing Then
‘ 該当リソースに割り当てられた有効なアサインメント群を取得
Dim assignments As Assignments
Set assignments = r.Assignments

Dim i As Long, j As Long
Dim count As Long
count = assignments.Count

If count > 1 Then
For i = 1 To count – 1
Set a1 = assignments(i)
If Not a1.Task.Summary And Not a1.Task.Milestone Then
For j = i + 1 To count
Set a2 = assignments(j)
If Not a2.Task.Summary And Not a2.Task.Milestone Then

‘ 重複判定ロジック: (StartA < EndB) And (StartB < EndA) If (a1.Task.Start < a2.Task.Finish) And (a2.Task.Start < a1.Task.Finish) Then conflictCount = conflictCount + 1 ' 視覚的警告としてFlag1をTrueに設定(カスタムビューで赤色表示等に利用可能) a1.Task.Flag1 = True a2.Task.Flag1 = True Debug.Print "[重複検出 #" & conflictCount & "] " & _ "リソース: [" & r.Name & "] | " & _ "タスクA: '" & a1.Task.Name & "' (" & a1.Task.Start & " - " & a1.Task.Finish & ") と " & _ "タスクB: '" & a2.Task.Name & "' (" & a2.Task.Start & " - " & a2.Task.Finish & ") が重複" End If End If Set a2 = Nothing Next j End If Set a1 = Nothing Next i End If Set assignments = Nothing End If Next r Debug.Print "=== [QUALITY CHECK] スキャン完了. 検出件数: " & conflictCount & "件 ===" If conflictCount > 0 Then
MsgBox “品質チェック完了: ” & conflictCount & “件のスケジュール重複が検出されました。” & vbCrLf & _
“詳細はイミディエイトウインドウおよび Flag1 を確認してください。”, vbExclamation, “品質管理アラート”
Else
MsgBox “品質チェック完了: 重複は検出されませんでした。”, vbInformation, “品質管理正常”
End If

CleanUp:
‘ パフォーマンス設定の復元(必ず実行)
Application.Calculation = pjAutomatic
Application.ScreenUpdating = True
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Sub

3. シニアエンジニアが押さえるべきアーキテクチャ上のポイント

1. サマリータスクとマイルストーンの除外

上記のコードでは `Not t1.Summary And Not t1.Milestone` という条件を厳格に入れている。サマリータスクは子タスクの集計期間を持つため、これをリソース重複判定の対象に含めると、実態のない「偽の重複アラート」が大量発生し、現場の担当者がマクロを無視(バイパス)するようになる。ツールが使われなくなる最大の原因は「ノイズの多さ」である。

2. 計算モード(Calculation)の物理的制御

MS Projectはプロジェクトファイルが巨大(数万行)になると、タスクのプロパティ(`Start`, `Finish`, `Flag1`など)を変更するたびにPERT計算やCPM(クリティカルパス法)の再計算走査走る。
`Application.Calculation = pjManual` を挟むことで、VBA実行中の無駄な再計算を完全に殺し、実行速度を劇的に向上させている。エラー発生時や正常終了時にも必ず `pjAutomatic` に戻す例外処理構造(`On Error GoTo ErrorHandler`)は絶対に削ってはならない。

3. オブジェクトの明示的破棄(メモリリーク対策)

VBAはガベージコレクタの挙動がブラックボックスである。特にMS ProjectのCOMオブジェクトは参照カウンタが複雑に絡み合う。ループ内で生成される `Assignment` や `Task` などの参照変数に対し、処理の終端で `Set a1 = Nothing` を明示的に行うことで、長時間のバッチ処理におけるメモリリークを根絶している。

4. システム間連携を見据えた拡張性

このスクリプト単体でもローカルでの品質担保には十分だが、真のシニアエンジニアであれば、これを「CI/CDパイプライン」や「PMO向けダッシュボード」の一部として組み込む視点を持つべきだ。

例えば、検知された `conflictCount` が 0 より大きい場合、VBAからWindows Script Host (WSH) や標準Outを経由してTeams/Slack WebhookへJSONペイロードを飛ばす、あるいはProject Server / Project Onlineのカスタムフィールドにステータスを書き戻すといった拡張が考えられる。

‘ ※応用スニペット: 外部API(Teams等)への通知連携イメージ
Private Sub SendWebhookAlert(ByVal message As String)
‘ WinHttpRequestを用いたモダンなHTTP POST処理
Dim http As Object
Set http = CreateObject(“MSXML2.XMLHTTP.6.0”)

Dim url As String
url = “https://your-org.webhook.office.com/webhookb2/…” ‘ 実際のWebhook URL

http.Open “POST”, url, False
http.setRequestHeader “Content-Type”, “application/json”

Dim payload As String
payload = “{“”text””: “”【MS Project 品質アラート】” & message & “””}”

http.send payload
Set http = Nothing
End Sub

レガシーな技術と侮られがちなProject VBAであるが、背後にあるオブジェクトモデルの挙動を完全に掌握し、メモリとパフォーマンスの限界まで最適化されたコードを書くとき、それは単なるマクロから「堅牢なエンタープライズ品質管理システム」へと昇華する。

現場のデータ品質を守るのは、いつだって妥協のないエンジニアのコードだ。

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