Project VBAを掌握する:タスク階層操作における「安全」と「高速」の境界線
Project VBA(MS ProjectのVBAオブジェクトモデル)を扱う際、多くのエンジニアが陥る罠がある。`OutlineIndent` や `OutlineOutdent` を安易にループ内で実行し、プロジェクトファイルの破損や、予期せぬ依存関係の崩壊を招く事態だ。
MS Projectのタスク構造は、単なる階層ではない。それは「タスクの順序と先行関係が複雑に絡み合ったメモリ上のグラフ構造」である。これを操作することは、構造の整合性を維持しながらポインタを書き換える外科手術と同義だ。
本稿では、レガシー環境においても安定稼働する、階層操作の極限パターンを伝授する。
—
1. 階層操作の最大の敵:再計算のオーバーヘッド
MS Projectのエンジンは、階層を変更するたびに「タスクの再スケジュール」と「依存関係の検証」を走らせる。これを1タスクずつ実行すれば、数千行のプロジェクトで数分の時間を浪費し、メモリリークを誘発する。
鉄則: 操作時は `Application.Calculation = pjManual` に設定し、自動計算を完全に殺すこと。これがパフォーマンスの第一歩である。
—
2. 安全な階層移動:実装パターン
階層の昇格(Outdent)や降格(Indent)を安全に行うには、単にメソッドを叩くのではなく、「対象タスクのID」と「親タスクの整合性」を厳密に管理する必要がある。
以下は、メモリリークを防ぎつつ、堅牢に動作する実装例だ。
Option Explicit
‘ 階層変更を安全に実行するためのラッパーメソッド
‘ 成功を保証するためにオブジェクトの整合性を厳密に検証する
Public Sub SafeOutlineUpdate(ByRef targetTask As Task, ByVal isIndent As Boolean)
Dim app As MSProject.Application
Set app = targetTask.Application
‘ プロセスが計算負荷でフリーズするのを防ぐため、計算モードを退避
Dim originalCalc As Long
originalCalc = app.Calculation
app.Calculation = pjManual
On Error GoTo ErrorHandler
If isIndent Then
‘ 階層の降格:親タスクの下位に移動
targetTask.OutlineIndent
Else
‘ 階層の昇格:親から脱出
targetTask.OutlineOutdent
End If
‘ 終了後の整合性チェック(必要に応じて)
‘ Debug.Print “Task ” & targetTask.ID & ” moved successfully.”
Cleanup:
app.Calculation = originalCalc
Set app = Nothing
Exit Sub
ErrorHandler:
‘ 致命的なエラー時はログを吐き出し、整合性を守る
MsgBox “階層操作中にエラーが発生しました: ” & Err.Description, vbCritical
Resume Cleanup
End Sub
—
3. シニアエンジニアが意識すべき「隠れた仕様」
依存関係の暗黙的追従
タスクを降格させると、そのタスクが持つ「サマリータスクとしての属性」と「先行・後続タスクのリンク」が再評価される。特に `Finish-to-Start` のリンクが階層移動を跨ぐ場合、MS Projectはプロジェクト全体のクリティカルパスを即座に再計算しようとする。
大規模なWBS再編を行う際は、以下のステップを踏むのがアーキテクトの作法だ。
1. バックアップ作成: `ActiveProject.SaveAs` を実行し、メモリ上の整合性が崩れた場合に備えてチェックポイントを作る。
2. 計算モードの無効化: 前述の通り `pjManual` への切り替えは必須。
3. バッチ処理: 階層操作をリスト化し、一括適用後に `Application.CalculateAll` で一度だけ再計算を走らせる。
—
4. プロジェクト間連携における「Windows API」の役割
MS ProjectのVBAは、大規模なファイル処理時にCOMインターフェースがハングアップすることがある。これを回避するためには、`Sleep` API を用いたポーリングや、`DoEvents` の適切な配置が重要だ。
If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If
‘ 巨大なプロジェクトで階層を一気に操作する際のバッファ
Public Sub BatchIndent(targetTasks As Collection)
Dim t As Task
For Each t In targetTasks
SafeOutlineUpdate t, True
‘ メインスレッドを過負荷にさせないためのインターバル
Sleep 10
DoEvents
Next t
End Sub
—
結論:コードは「構造」を理解して初めて輝く
Project VBAを扱うエンジニアにとって、コードは単なる命令の羅列ではない。MS Projectという巨大なエンジンの内部状態を制御するための、精密なコントロールレバーだ。
今回紹介した「計算モードの制御」「エラーハンドリングの徹底」「APIによるスレッド管理」は、いかなる巨大なプロジェクトにおいてもあなたの資産を守る防波堤となる。
「動くコード」ではなく、「壊れない構造」を書くこと。それが、伝説的な自動化エンジニアへの唯一の道である。
