こんにちは!現場でプロジェクト管理ツールの自動化やカスタマイズを担当しているシニアアーキテクトです。
Excelのマクロ(VBA)に慣れてきた方がMicrosoft Project(以下、Project)のVBAに足を踏み入れたとき、ほぼ100%と言っていい確率でハマってしまう「巨大な落とし穴」があります。
それが、「タスクの開始日(Start)や終了日(Finish)をVBAから直接書き換えてしまう問題」 です。
「えっ? スケジュールを自動設定したいんだから、日付を代入するのは当たり前じゃないの?」と思いますよね。実はこれ、Projectが誇る強力なスケジュール計算エンジン(Critical Path Method:CPM)を裏からハンマーで叩き壊す行為なのです。
今回は、なぜ直接日付を代入してはいけないのか、裏で何が起きているのかを図解を交えて紐解き、Projectの真価を引き出す「正しいAPIの書き方」を優しく解説します。ここをクリアすれば、Project VBAの基本はバッチリですよ!
—
1. Projectは「カレンダー付きのExcel」ではない
まず大前提として押さえておきたい本質があります。
- Excel:セルに入力した値がすべて。勝手に書き換わることはない(数式を除く)。
- Project:入力された期間、依存関係、カレンダー、リソースを元に、計算エンジンが常に「最適な日付」を算出し続けるリアルタイム・シミュレーター。
Projectの本質は「表」ではなく「計算エンジン」です。
本来、タスクの日付は「前のタスクが終わったら、できるだけ早く(ASAP:As Soon As Possible)始める」というルールと、所要期間(Duration)の足し算・引き算によって、エンジンが自動的に導き出す結果にすぎません。
—
2. 実験:`Task.Start = “2025/04/01″` と書くと裏で何が起きるのか?
では、初心者が最もよく書いてしまうNGコードを見てみましょう。
‘ 【アンチパターン】初心者がやりがちなコード
Sub BadPractice_SetDate()
Dim t As Task
Set t = ActiveProject.Tasks(1)
‘ Excel感覚で開始日を直接書き込んでしまう
t.Start = “2025/04/01”
End Sub
画面上は、狙った通りの日付にタスクが移動したように見えます。「動いた!完成!」と喜ぶかもしれません。しかし、そのタスクのプロパティを詳しく覗いてみると……恐ろしいことが起きています。
見えない「画鋲」が刺さる(SNETの呪い)
Projectの初期設定タスクは、基本的に制約条件が 「できるだけ早く(pjASAP)」 になっています。川の流れのように、前のタスクが早まれば前へ、遅れれば後ろへと自動で流れる柔軟な状態です。
しかし、`Task.Start` に日付を強制書き込みした瞬間、Projectエンジンは次のように解釈します。
> エンジン:「ユーザーが直接日付を指定してきたぞ! 勝手に動かしたら怒られるから、『指定日以降に開始(Start No Earlier Than: SNET)』 という制約条件をつけて、その日付に画鋲を刺しておこう」
【代入前】 柔軟な状態
[先行タスク] ──(リンク)──> [対象タスク (ASAP)] ※先行タスクが動けば自動追従
【代入後】 画鋲で固定された状態
[先行タスク] ──(リンク)──> [対象タスク (SNET: 4/1)] ※先行タスクが3月に終わっても動けない!
何が危険なのか?
この「見えない画鋲(SNET)」がプロジェクト全体にばら撒かれると、次の悲劇が起きます。
1. 先行タスクを前倒ししても、後続タスクが前に詰まらない(自動短縮されない)。
2. クリティカルパスが途切れる(どれが本当に遅れてはいけないタスクなのか見失う)。
3. プロジェクト全体の進捗シミュレーションが完全に狂う。
つまり、「せっかくProjectを使っているのに、融通の利かない硬直したゴミ箱スケジュールが出来上がる」 のです。
—
3. Project VBAの原則:日付ではなく「期間」と「制約条件」を操る
では、プロはどうやってタスクの日付を制御するのでしょうか?
原則はとてもシンプルです。
1. 日付を直接いじらず、先行タスクとの「リンク(依存関係)」と「期間(Duration)」で計算させる。
2. どうしても日付を固定したい場合のみ、明示的に「制約条件(Constraint)」を設定する。
制約条件プロパティを理解しよう
Projectタスクには、制約を司る2つの重要なプロパティがあります。
- `ConstraintType`:制約の種類(定数で指定)
- `ConstraintDate`:制約の基準日
代表的な制約定数(`PjConstraint` 列挙体)には以下のものがあります。
| 定数 | 意味 | 動作 |
| :— | :— | :— |
| `pjASAP` | できるだけ早く (デフォルト) | 制約なし。リンクに従って最も早い日に配置 |
| `pjALAP` | できるだけ遅く | プロジェクト終了日を基準に最も遅い日に配置 |
| `pjSNET` | 指定日以降に開始 | 指定日より前には開始しない(直接代入で勝手につくやつ) |
| `pjMSO` | 指定日に開始 | 完全にその日に固定(強い制約) |
—
4. 実践コード:安全に日付をコントロールするプロの技
ここからは、現場でそのまま使える実践的なVBAコードを紹介します。
パターンA:日付直接代入の罠からタスクを救出する(ASAPへの初期化)
過去のマクロや手入力で「画鋲(制約)」が刺さりまくったタスクを、柔軟な状態(ASAP)に戻すコードです。
Option Explicit
”’
”’
Public Sub ResetAllConstraintsToASAP()
Dim prj As Project
Set prj = ActiveProject
‘ 大量タスクの処理時は再計算と画面描画を止めて高速化するのが鉄則
Application.ScreenUpdating = False
Application.Calculation = pjManual
Dim t As Task
For Each t In prj.Tasks
‘ 空白行(Nothing)やサマリータスク(手動サマリー以外)はスキップ
If Not (t Is Nothing) Then
If Not t.Summary Then
‘ 固定日付制約(SNET, FNET, MSO, MFOなど)がついている場合
If t.ConstraintType <> pjASAP Then
‘ 制約を「できるだけ早く」にリセット
t.ConstraintType = pjASAP
‘ 制約日をクリア(Nothing相当の “NA” を代入)
t.ConstraintDate = “NA”
End If
End If
End If
Next t
‘ 設定を戻してエンジンに正しく再計算させる
Application.Calculation = pjAutomatic
Application.CalculateAll
Application.ScreenUpdating = True
MsgBox “すべてのタスクを柔軟なASAP状態に再計算しました!”, vbInformation
End Sub
パターンB:意図的に「開始日」を指定したい場合の正しい作法
「外部納期の関係で、どうしてもこの日より前には着手できない」など、明確なビジネス理由がある場合にのみ、APIを使って正しく制約を設定します。
Option Explicit
”’
”’
Public Sub SetSafeConstraint()
Dim t As Task
‘ 例としてID:1のタスクを取得
Set t = ActiveProject.Tasks(1)
If t Is Nothing Then Exit Sub
‘ 1. タスクの期間(工数)を設定する(例: 5日)
‘ ※Durationは「分」単位で保持されるため、pjCharToSys(“5d”)等を使うか直接数値を入れます
t.Duration = 5 8 60 ‘ 5日分 (1日8時間換算の場合:2400分)
‘ 2. Startプロパティを直接いじらず、制約タイプと制約日を【明示的】に指定する
t.ConstraintType = pjSNET
t.ConstraintDate = “2025/04/01”
‘ これにより「意図してSNET制約を付与した」ことがコード上もProject上も明白になります
End Sub
—
5. 先輩からのワンポイント・アドバイス
初心者を脱却して「Project VBAの達人」になるためのチェックリストを授けます。
□ タスクを動かしたいなら、まず「Predecessors(先行タスク)」を繋げないか考える
□ 日付を入れる前に「Duration(期間)」を設定したか確認する
□ どうしても日付を指定する時は「ConstraintType」を明示的に書く
□ ループ処理の前には「Application.Calculation = pjManual」でエンジンの暴走を止める
特に最後の計算エンジンの停止は非常に重要です。
Excel VBAでも `Application.Calculation = xlCalculationManual` を使いますが、Projectの計算エンジンはExcel以上に複雑な依存関係グラフを解くため、ループ内で日付や期間が変わるたびに裏で全力再計算が走り、動作が極端に重くなります。
「止めて、操作して、計算させて、戻す」。このリズムを忘れないでくださいね。
—
まとめ
- `Task.Start` や `Task.Finish` への直接代入は、勝手な制約条件(SNETなど)を発生させてスケジュールを麻痺させる。
- Projectは「表」ではなく「計算エンジン」。タスクの日付はリンクと期間によって自動計算させるのが基本。
- 日付の指定が必須な業務要件のときは、`ConstraintType` と `ConstraintDate` をペアで明示的に指定する。
Project VBAは、エンジンのクセさえ掴んでしまえば、Excelマクロとは比較にならないほどダイナミックで強力な業務効率化を実現できます。
まずは今回紹介した「ASAPに戻すマクロ」をご自身のプロジェクトで動かして、計算エンジンがタスクをキュッと正しい位置に整列させる気持ちよさを体験してみてください。一歩ずつ、マスターしていきましょう!応援しています!
