Project VBAを掌握せよ:ベースライン同期から読み解く「進捗可視化」の極意
Project VBA(Microsoft Project Object Model)を触る際、多くの初学者が陥る罠がある。それは「GUIでできる操作をそのままコードに翻訳しようとする」ことだ。
プロジェクト管理において、ベースラインは「聖域」である。ベースラインを設定した瞬間のタスク状況をExcelへ吐き出し、進捗を追跡する仕組み。これは単なる転記作業ではない。プロジェクトの健全性を守るための「監視システム」の構築である。
本稿では、堅牢かつ保守性の高いプロダクションレベルのコードを提示し、なぜその設計が必要なのか、その思想を授ける。
—
1. 守るべき設計思想:疎結合とエラーハンドリング
VBAでProjectからExcelへデータを流し込む際、もっとも避けるべきは「ProjectのタスクIDとExcelの行を強引に紐付ける」ことだ。
- UIDの活用: タスクIDは並び替えや挿入で容易に変化する。必ず「UniqueID」を使用すること。これが唯一の正解だ。
- 早期バインディングの回避: `Dim projApp As MSProject.Application` と書くのはやめよう。環境差異による参照設定の崩壊を防ぐため、`Object`型による遅延バインディングを採用し、実行時に制御する。
- Excelのインスタンス管理: Projectの中からExcelを起動する際、既存のExcelが開いているのか、新規で生成すべきかを厳密に判定せよ。
—
2. 実装:ベースライン比較・エクスポート・モジュール
以下のコードは、現在アクティブなProjectファイルから「開始日」「終了日」「完了率(%)」を抽出し、Excelへ転記するプロシージャだ。
‘ Project VBAモジュールに記述
Option Explicit
Public Sub ExportBaselineToExcel()
Dim prjApp As Object
Dim xlApp As Object
Dim xlBook As Object
Dim xlSheet As Object
Dim tsk As Object
Dim rowIdx As Long
‘ 1. Excelアプリケーションの制御(起動済みか新規か)
On Error Resume Next
Set xlApp = GetObject(, “Excel.Application”)
If xlApp Is Nothing Then
Set xlApp = CreateObject(“Excel.Application”)
End If
On Error GoTo 0
‘ 2. ワークブックとシートの初期化
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook.Sheets(1)
‘ ヘッダーの設定
xlSheet.Range(“A1:D1”).Value = Array(“UniqueID”, “タスク名”, “ベースライン開始”, “進捗率(%)”)
rowIdx = 2
‘ 3. タスクループ処理(Projectオブジェクトのトラバース)
‘ Application.ActiveProjectにアクセスし、全タスクを走査
For Each tsk In Application.ActiveProject.Tasks
If Not tsk Is Nothing Then
‘ サマリータスクを除外したい場合はここで制御
If Not tsk.Summary Then
xlSheet.Cells(rowIdx, 1).Value = tsk.UniqueID
xlSheet.Cells(rowIdx, 2).Value = tsk.Name
‘ ベースライン設定値を取得(BaselineStart)
xlSheet.Cells(rowIdx, 3).Value = tsk.BaselineStart
xlSheet.Cells(rowIdx, 4).Value = tsk.PercentComplete
rowIdx = rowIdx + 1
End If
End If
Next tsk
‘ 4. 後処理
xlApp.Visible = True
MsgBox “進捗レポートの生成が完了しました。”, vbInformation
End Sub
—
3. プロフェッショナルへの道:ここが重要だ
「なぜこのコードなのか」の論理的根拠
- `If Not tsk Is Nothing` の徹底: Projectのタスクコレクションには「空の行」が存在する場合がある。これを無視するとNull参照で即座にクラッシュする。堅牢なシステムは、予期せぬ「空」を許容する設計から生まれる。
- `Summary` タスクのフィルタリング: プロジェクトの進捗報告において、サマリータスク(親タスク)の進捗率は子タスクの計算結果に依存する。生データとして分析する際は、子タスク(詳細タスク)のみを抽出するロジックを必ず挟むこと。
さらなる高みへ(パフォーマンスと保守性)
もしタスク数が数千を超える大規模プロジェクトであれば、`xlSheet.Cells` への逐次書き込みはボトルネックとなる。その場合は、一度2次元配列にデータを格納し、最後に `Range.Value = Array` で一括出力する手法へ切り替えてほしい。これが、我々エンジニアが「速度」を制御する方法だ。
—
結びに代えて
自動化とは、単に楽をすることではない。「人間が介在するとミスが起きるポイント」をコードによって排除するプロセスである。
ベースラインのデータをExcelに吐き出す。この些細な作業を自動化することで、あなたは「転記作業」という低付加価値な時間から解放される。その浮いた時間で、プロジェクトのクリティカルパスの精査や、リスクの予測に頭を使うことこそが、真の自動化エンジニアの務めだ。
コードをコピペして満足するな。その裏側にある「なぜそのオブジェクトが必要なのか」というアーキテクチャの意図を汲み取り、自身の現場に最適化せよ。健闘を祈る。
