【テクニカル・上級編】初心者向け:手動タスクと自動タスクの判別ロジックとUIへの反映 – Project VBA解析バイブル

スポンサーリンク

Project VBAを掌握する極限の知見

スケジュール計算エンジンの制御とUI同期:手動・自動タスクの動的判別とメモリ最適化の極意

Microsoft ProjectのVBA開発において、多くのエンジニアが直面する最初の壁であり、かつ終着点の一つが「スケジュール計算エンジンの制御」である。

Projectは、デフォルトではProject 2010以降「手動タスク(Manually Scheduled)」という強力な例外レイヤーを導入した。これにより、ユーザーは制約条件や依存関係の縛りを受けずに自由な日付を入力できるようになったが、エンタープライズ環境の厳密なCPM(クリティカルパス法)エンジンにとっては、まさに「計算のブラックボックス化」を引き起こす最大の要因となっている。

今回は、`Task.Manual`プロパティを軸に、スケジュールエンジンの挙動をプログラムから完全に掌握し、さらに大規模プロジェクトにおけるUI(ガントチャート)の描画パフォーマンスを極限まで引き上げるための実用コードと知見を共有する。

—

1. スケジュール計算エンジンの内部挙動と `Task.Manual` の罠

まず理解すべきは、ProjectのCOMオブジェクトモデルにおけるタスクのライフサイクルだ。
`Task.Manual = True` が設定されたタスクは、Projectのエンジン(Calculation Engine)による自動スケジュール計算の対象外となる。つまり、先行タスクが遅延しても、このタスクの日付は連動して再計算されない。

一見すると「ユーザーフレンドリー」だが、システム連携や一括インポートを行う際、これが悪夢を生む。外部システムから流し込んだWBSが意図せず「手動タスク」として取り込まれ、全体のクリティカルパスが崩壊するインシデントが後を絶たない。

エンジニアとして、インポート時やバッチ処理時には、必ずこのプロパティを明示的に制御しなければならない。

‘ 【コードブロック1】タスクの手動/自動の強制制御とエンジン再計算
Sub ForceAutoScheduleEngine(ByRef prj As Project)
Dim t As Task
Dim lngCounter As Long

‘ 画面描画とイベントを完全に停止し、エンジンをサイレントモードに移行
Application.ScreenUpdating = False
Application.Calculation = pjCalculationManual

lngCounter = 0

‘ COMオブジェクトの参照リークを防ぐため、For Eachを適切に運用
For Each t In prj.Tasks
If Not t Is Nothing Then
If t.Summary = False And t.Milestone = False Then
‘ 手動タスクになっているものを強制的に自動タスク(ASAP/ALAPのエンジン対象)へ変換
If t.Manual = True Then
t.Manual = False
lngCounter = lngCounter + 1
End If
End If
End If
Next t

‘ 計算モードを復旧し、エンジンに一括再計算を命令
Application.Calculation = pjCalculationAutomatic
Application.ScreenUpdating = True

MsgBox lngCounter & ” 件のタスクを自動スケジュールエンジンに接続しました。”, vbInformation

‘ メモリ解放の作法
Set t = Nothing
End Sub

—

2. UIの視覚的同期:手動・自動タスクの動的色分け

プロジェクトマネージャーや現場のリーダー層にとって、どのタスクが「エンジンの支配下(自動)」にあり、どのタスクが「野良状態(手動)」にあるのかを視覚的に即座に判別できるUI環境は、リスク管理上、極めて重要である。

ここでは、単に色を塗るだけでなく、大規模案件(数万行クラス)でのパフォーマンス劣化を防ぐための「UI描画負荷の極限削減テクニック」を実装する。

ガントチャートのバーの色(CellColorやBarStyles)を1行ずつ変更するコードは、VBAとCOMの往復回数が増大し、フリーズの原因となる。そのため、プロジェクトの「照会(Highlight)」機能や、カスタムフィールドを利用した一括セロハンテープ的アプローチを用いるのがプロの選択だ。

‘ 【コードブロック2】タスクの属性に応じたカスタムフィールドへのフラグ立てとビュー制御
Sub SyncTaskEngineUIState()
Dim t As Task
Dim tskField As String

‘ 処理速度最優先:描画とイベントの遮断
Application.ScreenUpdating = False

‘ 例として [Text1] をフラグ格納庫として使用
‘ 実際の本番環境ではエンタープライズカスタムフィールド(Text30等)を推奨
For Each t In prj.Tasks
If Not t Is Nothing Then
If t.Manual Then
‘ 手動タスクの視覚化用コード
t.Text1 = “【手動】要確認”
‘ ※実際のUI色変更は、Projectの「ハイライト」機能や
‘ ガントチャートのスタイルルールをText1に連動させることで
‘ VBA側の描画コストをゼロに抑えるのがシニアの常道。
Else
t.Text1 = “【自動】エンジン稼働中”
End If
End If
Next t

Application.ScreenUpdating = True
Set t = Nothing

MsgBox “UI同期用のメタデータ更新が完了しました。”, vbInformation
End Sub

—

3. チーフアーキテクトからの教訓:オブジェクトのライフサイクル管理

Project VBAの開発において、もっとも恐ろしいのは「COMオブジェクトの解放漏れによるメモリリークとExcel/Projectプロセスのゾンビ化」である。

特に `Application.ActiveProject.Tasks` のようなコレクションをループ処理する際、変数のスコープ管理や、処理終了時の `Set obj = Nothing` を怠ると、バックグラウンドでCOMコンポーネントがメモリ上に残留し、ファイルロックやメモリ枯渇を引き起こす。

シニアエンジニアが守るべき3大鉄則:

1. `ScreenUpdating = False` と `Calculation = pjCalculationManual` のセット運用

  • タスク数が5,000を超えたあたりから、スケジュールエンジンの都度計算とUI描画が処理時間を何十倍にも膨れ上がらせる。バッチ処理時は必ずエンジンを止めよ。

2. Nothing代による参照の即時破棄

  • ループ内で生成・取得したオブジェクト参照は、ブロック抜けのタイミングで必ず `Set variable = Nothing` を実行し、参照カウンタを即座にデクリメントする。

3. エラーハンドリング(`On Error GoTo`)の徹底

  • 処理途中でエラー落ちした場合に、`ScreenUpdating = False` や `Calculation = Manual` が解除されないままになると、ユーザーのUIが完全にフリーズしたように見え、ヘルプデスクへの問い合わせが殺到する。必ず `Finally` 相当のエラー抜け構文を実装すること。

‘ 【コードブロック3】堅牢なエラーハンドリングを備えた安全なエンジン制御テンプレート
Sub SafeTaskEngineExecution()
Dim prj As Project
Set prj = ActiveProject

‘ エラーハンドラの設定
On Error GoTo ErrorHandler

‘ 環境のロック
Application.ScreenUpdating = False
Application.Calculation = pjCalculationManual

‘ — メイン処理 —
Call ForceAutoScheduleEngine(prj)
Call SyncTaskEngineUIState()
‘ ——————

CleanUp:
‘ 確実に環境を復旧させる(成功・失敗を問わず実行)
Application.Calculation = pjCalculationAutomatic
Application.ScreenUpdating = True
Set prj = Nothing
Exit Sub

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

—

結び

Project VBAは、単なるマクロの記録の延長線上にはない。背後で稼働するCPMスケジュール計算エンジンと、COMオブジェクトモデルのメモリライフサイクルを完全に理解した者だけが、数万行の巨大プロジェクトデータを意図通りに、かつ高速に制御する特権を得られる。

手動タスクと自動タスクの境界線をコードで完全に支配し、破綻のないエンタープライズスケジュール管理基盤を構築してほしい。

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