【実務・中級編】初心者向け:タスクの「制約なし」状態をVBAで判定し、デフォルト値へ置換する – Project VBA解析バイブル

スポンサーリンク
スポンサーリンク

スケジュール計算エンジンを支配せよ:MS Project VBAにおける制約条件の精密制御

MS Projectを単なる「高機能なガントチャート・エクセル」だと思っているなら、君の自動化ツールは必ず現場で破綻する。

MS Projectの本質は、入力された日付や制約条件を基に、依存関係(Predecessors)を辿って全タスクの開始・終了日を再計算する「動的なスケジュール計算エンジン」である。

多くの初学者が書くVBAコードが、実行時に数秒、あるいは数分間フリーズするのは、プログラムの書き方が悪いのではない。「計算エンジンの再トリガー(再計算)」を制御できていないからだ。

本記事では、プロジェクト作成時に自動付与される「制約なし(As Soon As Possible)」の状態を検出し、実務で求められる特定のデフォルト値へと一括置換する、堅牢かつ高速な実装手法を伝授する。

1. なぜ「制約(Constraint)」の制御が重要なのか

MS Projectにおいて、タスクには必ず「制約」が付随する。
何も指定しない場合、タスクはデフォルトで `pjTaskConstraintAsSoonAsPossible`(可能な限り早く) という制約を持つ。これは一見「制約がない」ように見えるが、計算エンジンにとっては「ASAPという制約がある」状態なのだ。

実務上の自動化ツールでは、以下の理由からこれを明示的に制御する必要がある。

1. スケジュールの不整合防止: 意図しないASAPが残っていると、先行タスクが動いた際にタスクが連鎖的に動きすぎてしまい、計画の安定性が失われる。
2. 標準化: プロジェクト管理基準に基づき、「開始日指定(Start No Earlier Than)」などの特定の制約へ強制的に統一する必要がある。
3. データクレンジング: 外部システム(ERPや他の工程管理ツール)からインポートした際、不適切な制約が混入しているケースが多いため。

2. 初学者が陥る「致命的な設計ミス」

コードを書く前に、避けるべき「アンチパターン」を理解しておけ。

アンチパターン:逐次計算の地獄

' --- 悪い例:絶対にやってはいけない ---
For Each t In ActiveProject.Tasks
    If Not t Is Nothing Then
        If t.ConstraintType = pjTaskConstraintAsSoonAsPossible Then
            t.ConstraintType = pjTaskConstraintStartNoEarlierThan
            ' ここで、タスクを1つ書き換えるたびに、
            ' MS Projectの計算エンジンがプロジェクト全体の再計算を開始する!
        End If
    End If
Next t

この書き方では、タスクが1,000個あれば、最悪1,000回のフルスケジューリングが走る。計算コストの爆発だ。プロフェッショナルなら、まず計算モードを「手動」に切り替えるのが鉄則だ。

3. プロダクション・グレードの設計指針

堅牢なツールを作るための3つの柱を提示する。

1. 計算制御(Calculation Control): 処理の開始前に `Calculation = pjCalculationManual` を実行し、終了後に `Automatic` に戻す。
2. Nullオブジェクトへの耐性: `Tasks` コレクションには、空行(Nothing)が含まれる。これを無視すると `Run-time error ’91’` で即死する。
3. エラーハンドリングと状態復元: 途中でエラーが発生しても、計算モードを必ず `Automatic` に戻す仕組み(クリーンアップ処理)を組み込む。

4. 実装:制約条件の最適化エンジン

以下に、実務でそのまま使えるレベルのコードを示す。このコードは、全ての「ASAP」制約を検出し、指定したデフォルトの制約(例:開始日指定)へ置換する。

Option Explicit

''' <summary>
''' プロジェクト内の全タスクを走査し、"可能な限り早く(ASAP)"の制約を
''' 指定されたデフォルトの制約タイプに一括置換する。
''' </summary>
Public Sub StandardizeTaskConstraints()
    Dim t As Task
    Dim targetConstraint As PjTaskConstraint
    Dim processedCount As Long
    
    ' --- 設定領域 ---
    ' 置換後の制約タイプを指定(例: pjTaskConstraintStartNoEarlierThan = 開始日指定)
    targetConstraint = pjTaskConstraintStartNoEarlierThan
    ' ----------------
    
    ' 1. 高速化のための準備
    On Error GoTo ErrorHandler
    Application.ScreenUpdating = False
    ' 計算モードを手動に設定(再計算の連鎖を阻止)
    Application.Calculation = pjCalculationManual
    
    processedCount = 0
    
    ' 2. ループ処理
    ' ActiveProject.Tasks を直接回す際は、Nothingチェックが必須
    For Each t In ActiveProject.Tasks
        ' タスクが存在しない(空行)場合はスキップ
        If Not t Is Nothing Then
            ' 制約タイプが "As Soon As Possible" かどうかを判定
            If t.ConstraintType = pjTaskConstraintAsSoonAsPossible Then
                
                ' 制約の書き換え
                t.ConstraintType = targetConstraint
                
                ' 統計用
                processedCount = processedCount + 1
                
            End If
        End If
    Next t

    ' 3. 正常終了時の後処理
    Application.Calculation = pjCalculationAutomatic
    Application.ScreenUpdating = True
    
    MsgBox "処理が完了しました。" & vbCrLf & _
           "置換されたタスク数: " & processedCount, vbInformation, "完了"
    
    Exit Sub

ErrorHandler:
    ' 4. エラー発生時のリカバリ
    ' エラーが起きても、計算モードを「自動」に戻さないと、
    ' ユーザーは「MS Projectが動かない!」とパニックになる。
    Application.Calculation = pjCalculationAutomatic
    Application.ScreenUpdating = True
    
    MsgBox "致命的なエラーが発生しました。" & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "内容: " & Err.Description, vbCritical, "システムエラー"
End Sub

コードの解説(アーキテクトの視点)

  • `Option Explicit`: 変数の宣言を強制する。これは基本中の基本だが、これがないコードは「動いているように見えるだけのゴミ」だ。
  • `Application.Calculation = pjCalculationManual`: これがパフォーマンスの鍵だ。計算エンジンを眠らせた状態でデータを一気に書き換え、最後に一括で起こす。
  • `If Not t Is Nothing Then`: MS Projectのオブジェクトモデルにおける「守護神」だ。これがないと、ユーザーが途中でタスクを削除したり、空行があったりするだけでツールは死ぬ。
  • `ErrorHandler` の設計: プロフェッショナルの仕事は「成功させること」だけでなく、「失敗した時にシステムを安全な状態に戻すこと」にある。計算モードを `Automatic` に戻す処理を `ErrorHandler` に書くのは、ユーザー体験(UX)への配慮だ。

5. さらなる高みへ:データベース連携への注意点

もし君が、この処理の結果を外部のSQL ServerやAccessなどのデータベースに書き戻す設計を考えているなら、さらに注意が必要だ。

1. トランザクションの意識: VBA側で一括置換した後にDBへ書き込む場合、VBA側でエラーが起きたらDB側もロールバック(取り消し)しなければならない。
2. 一括更新(Bulk Update)の検討: タスク一つずつをDBに `UPDATE` 文で飛ばすのは愚策だ。メモリ上に変更リストを保持し、最後に一括でDBに流し込む設計にせよ。
3. IDの不一致: MS Projectの `ID` はユーザーがタスクを並べ替えると変わる。DB連携には必ず不変の `Unique ID` を使用すること。

結論

MS Project VBAにおける自動化とは、単なる「値の書き換え」ではない。「計算エンジンの挙動をいかにコントロールし、計算リソースを最適化するか」という、エンジニアリングの戦いである。

今回学んだ「計算モードの制御」と「堅牢なエラーハンドリング」をマスターすれば、君の作るツールは現場のプロフェッショナルから絶大な信頼を得るだろう。

次に進め。計算エンジンは、君の制御を待っている。

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