Project VBAを掌握する極限の知見:プロジェクトを完全ASAP化する「制約条件一括リセットエンジン」の設計
開発現場でMS Project(Project VBA)を扱っていると、幾重にも張り巡らされた「制約条件(Constraint)」の呪縛に頭を抱える瞬間が訪れる。
「タスクAの遅延が全体のクリティカルパスを歪めているのに、どこに固定的な制約(「指定日以降に開始」や「完了期日」など)が隠れているのか分からない」
「スケジュールを再構築したいのに、過去の担当者がバラバラに設定した制約が邪魔をして、ASAP(できる限り早く)に倒せない」
凡百のエンジニアであれば、ガントチャート上で一つずつタスクプロパティを開き、制約の種類を「できる限り早く(ASAP)」に変更するという不毛な手作業に走るだろう。だが、我々は違う。数千件のタスクを持つ巨大プロジェクトであっても、一瞬で全ての制約を剥ぎ取り、プロジェクトの血流を最速化させる「一括リセットエンジン」をコードで瞬時に組み上げるべきだ。
今回は、Project VBAのオブジェクトモデルの深淵に踏み込み、バグを一切許容しない堅牢な「完全ASAP化ツール」の設計と実装を授けよう。
—
1. なぜ「力技のループ」は破綻するのか?(VBA設計の罠)
まず、素人が書きがちなアンチパターンを見てほしい。
‘ 【アンチパターン】これだから処理が重く、エラーが頻発する
Dim t As Task
For Each t In ActiveProject.Tasks
t.ConstraintType = pjConstraintStartAsSoonAsPossible
Next t
一見すると動くように見えるこのコードは、実務の現場では致命的なバグを引き起こす。
なぜか?理由は主に3点ある。
1. サマリータスク(概要タスク)の存在: Projectにおいて、サマリータスク(親タスク)やマイルストーン、外部タスクには変更してはならない制約、あるいは変更するとエラー(エラー番号:1100等)を吐く特殊な状態が存在する。これらを無差別に変更しようとすると容赦なくマクロがクラッシュする。
2. 計算エンジンの負荷(パフォーマンスの劣化): タスクのプロパティを1件書き換えるたびに、Projectのスケジュールエンジンが再計算を走らせようとする。数千件のタスクに対してこれをやると、画面がフリーズしたかのような重さに陥る。
3. エラーハンドリングの欠如: 読み取り専用プロジェクトや、リソースプールとの排他制御を無視しているため、実務環境では確実に例外で落ちる。
プロのアーキテクトが書くべきコードは、「不純物を正確にフィルタリングし、計算エンジンの挙動をコントロールし、トランザクション的に処理を完結させる」ものでなければならない。
—
2. 堅牢な完全ASAP化エンジンのアーキテクチャ
今回提供するプロダクションコードでは、以下の設計思想を実装している。
- 画面描画と自動計算の一時停止 (`ScreenUpdating`, `Calculation`): VBA側で一括処理を行っている間、Projectのバックグラウンド計算を止め、処理速度を限界まで引き上げる。
- 安全性担保のフィルタリング: サマリータスク(`Summary`)、マイルストーン、外部プロジェクトのリンクタスクを除外し、純粋に操作すべき「実タスク(Leaf Task)」のみを正確に撃ち抜く。
- エラーの完全捕捉: 万が一の例外発生時でも、必ずアプリケーションの状態(画面描画や計算モード)を元の正常な状態に復元する「Try-Finally構造(VBA風イディオム)」の採用。
—
3. 【コピペ即実戦投入可】完全ASAP化エンジン・プロダクションコード
以下のコードをProjectの標準モジュールに貼り付けて実行してほしい。
Option Explicit
‘ ==============================================================================
‘ @Title: Project完全ASAP化 & 制約一括リセットエンジン
‘ @Description: プロジェクト内の全有効タスクの制約を「できる限り早く(ASAP)」に強制統一する
‘ @Author: World-Class Automation Architect
‘ ==============================================================================
Public Sub ExecuteCompleteASAPReset()
‘ 1. 宣言と初期状態の退避
Dim prj As Project
Set prj = ActiveProject
‘ プロジェクトが開かれていない、またはタスクが存在しない場合のガード節
If prj.Tasks.Count = 0 Then
MsgBox “対象となるタスクが存在しません。”, vbExclamation, “ASAP化エンジン”
Exit Sub
End If
‘ 実行確認(破壊的な一括変更を伴うため、実務では必須)
Dim confirmResult As VbMsgBoxResult
confirmResult = MsgBox(“この操作は、プロジェクト内の全タスクの制約条件を強制的に「できる限り早く (ASAP)」に書き換えます。” & vbCrLf & _
“本当によろしいですか?”, _
vbYesNo + vbCritical + vbDefaultButton2, “【警告】完全ASAP化の実行”)
If confirmResult = vbNo Then Exit Sub
‘ 2. パフォーマンス最大化とイベント抑制のための環境設定
‘ ※MS Project VBAではApplicationオブジェクトのプロパティで制御
On Error GoTo ErrorHandler
Dim originalCalcMode As Long
originalCalcMode = Application.Calculation
‘ 自動計算を一時停止(パフォーマンス劇的向上)
Application.Calculation = pjCalcManual
‘ ステータスバーに処理中を表示
Application.StatusBar = “プロジェクトの完全ASAP化を実行中…”
Dim t As Task
Dim targetCount As Long
Dim skippedCount As Long
targetCount = 0
skippedCount = 0
‘ 3. メインループ:タスクの精査と制約の上書き
For Each t In prj.Tasks
‘ Nothing判定(削除されたタスクのスキップ)
If Not t Is Nothing Then
‘ 【重要】以下の条件に該当するタスクは制御対象外として安全にスキップ
‘ – サマリータスク (Summary = True)
‘ – 外部プロジェクトのタスク (ExternalTask = True)
‘ – 削除済み、あるいはマイルストーン等で制約変更が許されない特殊ケース
If Not t.Summary And Not t.ExternalTask Then
‘ すでにASAPかつ日付固定等がない場合は無駄な書き込みを避けることも可能だが、
‘ 今回は「完全リセット」が目的なので強制代入する
On Error Resume Next
t.ConstraintType = pjConstraintStartAsSoonAsPossible
If Err.Number = 0 Then
targetCount = targetCount + 1
Else
‘ 個別タスクでエラーが出た場合はスキップしてログ蓄積等の処置へ
skippedCount = skippedCount + 1
Err.Clear
End If
On Error GoTo ErrorHandler
Else
skippedCount = skippedCount + 1
End If
End If
Next t
‘ 4. 変更を確定させるための手動再計算の実行
Application.Calculation = originalCalcMode
prj.Calculate
‘ 5. 正常終了処理
Application.StatusBar = “”
MsgBox “完全ASAP化が完了しました。” & vbCrLf & _
“・更新成功タスク数: ” & targetCount & ” 件” & vbCrLf & _
“・除外/スキップ数: ” & skippedCount & ” 件”, _
vbInformation, “処理成功”
Exit Sub
ErrorHandler:
‘ 異常終了時も必ず環境を復元する(ゾンビプロセスの防止)
Application.Calculation = originalCalcMode
Application.StatusBar = “”
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, _
vbCritical, “致命的エラー”
End Sub
—
4. 現場で運用する上での高度な注意点(DB連携・ファイル管理)
このツールを組織内の定常業務やサーバーサイド(Excel等からのマクロ経由、あるいはVBScriptからの遠隔操作)に組み込む場合、以下のアーキテクチャ上の罠に注意してほしい。
① 排他制御(File Share / Server環境)
Projectファイル(`.mpp`)がMicrosoft Project ServerやProject Online、あるいは共有サーバー上に存在する場合、他のユーザーがファイルを開いている状態でこのVBAを実行すると、「書き込みロック(Read-Only衝突)」が発生する。
ツールを実行する前に、必ず対象ファイルが排他ロックされていないか、あるいはローカルのワークスペースにチェックアウトされている状態であることを保証するロジックを前段に挟むべきだ。
② スケジュールエンジンの「非同期計算」の罠
Project VBAの `prj.Calculate` やタスクプロパティの変更は、内部のCOMコンポーネントを通じてC++ベースのスケジュールエンジンを叩く。
そのため、コードの行数以上に裏でのエンジン側の演算負荷が高い。巨大なプロジェクト(1万行以上)を扱う場合は、処理の合間に `DoEvents` を挟むか、あるいはタスクのバッチ分割処理(トランザクションの分割)を検討する必要がある。
—
5. 総括
スケジュール管理ツールにおける「制約条件」とは、本来、どうしても動かせない外部要因(顧客の納品期日や資材の搬入日など)のために用意された例外的なスパイスであるべきだ。それが現場の混乱によって全タスクに乱用され、プロジェクトの自律的な最適化を阻害しているケースがあまりにも多い。
今回紹介した「完全ASAP化エンジン」は、単なる便利マクロではない。
複雑怪奇に絡み合ったスケジュールの因果関係を一度すべてリセットし、プロジェクトを「あるべき姿(最速のフロー)」へと強制的に引き戻すための外科的手術メスである。
あなたの現場のプロジェクト管理を、このコードで真の「自律駆動型」へと進化させてほしい。
