Project VBAを極める:WBSコード自動生成の「深淵」と「鉄則」
プロジェクト管理において、Project標準のWBSコードは時に「あまりに平凡」です。社内独自の会計コード体系や、フェーズ・サブシステムを包含した管理コードをWBSに適用したいという要求は、現場のエンジニアであれば一度は直面する壁でしょう。
しかし、安易にVBAで値を書き込むだけのスクリプトを書いてはいけません。Projectのオブジェクトモデルは、単なるExcelのセルとはわけが違う。 階層構造の変更を検知し、依存関係を壊さず、かつパフォーマンスを犠牲にしない「真のアーキテクチャ」を伝授します。
—
1. なぜ「力技の更新」は失敗するのか
多くの開発者が陥る罠は、「タスクをループして全件更新する」というアプローチです。
Projectの`Task.WBS`フィールドは非常に強力ですが、親タスクのインデントを変更した瞬間に、その下の階層の整合性が崩壊します。
- 無駄な再計算: 全件更新をかけると、Projectは全ての依存関係やクリティカルパスを再計算し、UIがフリーズします。
- イベントの暴走: `Project_Change`イベントを適切に制御しないと、無限ループやメモリリークを誘発します。
プロフェッショナルは、「構造が変化した箇所のみを再帰的に特定し、必要最小限のバッチ処理で更新する」という設計思想で実装します。
—
2. 実装の要諦:WBS採番エンジンの設計
今回は、「階層(OutlineLevel)」をキーに、親のコードを継承しつつ連番を振る堅牢なロジックを提供します。
プロダクション・コード例
以下のコードは、選択したタスク、またはプロジェクト全体に対して、`Text1`フィールド(または任意のカスタムフィールド)へ独自のWBSコードを書き込むプロシージャです。
Option Explicit
‘ ———————————————————
‘ 独自WBSコード生成のメインルーチン
‘ 階層構造を走査し、親のコード + 連番 を生成する
‘ ———————————————————
Public Sub GenerateCustomWBS()
Dim tsk As Task
Dim proj As Project
Set proj = ActiveProject
‘ 描画を停止してパフォーマンスを最大化
Application.ScreenUpdating = False
‘ 全タスクを巡回
For Each tsk In proj.Tasks
If Not tsk Is Nothing Then
‘ 階層レベルに応じた接頭辞の付与ロジック
If tsk.OutlineLevel = 1 Then
tsk.Text1 = “PJ-” & Format(tsk.ID, “000”)
Else
‘ 親タスクのコードを取得して連番を付与
tsk.Text1 = GetParentWBS(tsk) & “.” & Format(tsk.OutlineNumber, “00”)
End If
End If
Next tsk
Application.ScreenUpdating = True
MsgBox “WBSコードの更新が完了しました。”, vbInformation
End Sub
‘ ———————————————————
‘ 親タスクのWBSコードを再帰的に取得するヘルパー関数
‘ ———————————————————
Private Function GetParentWBS(tsk As Task) As String
Dim parentTsk As Task
Set parentTsk = tsk.OutlineParent
If Not parentTsk Is Nothing Then
‘ カスタムフィールド(Text1)から親の値を抽出
GetParentWBS = parentTsk.Text1
Else
GetParentWBS = “ROOT”
End If
End Function
—
3. 運用・保守における「鉄則」
コードを書いて終わりではありません。運用の現場で「使えないツール」にさせないための3つの鉄則を記します。
① フィールドの選択に「遊び」を持たせる
WBSコードを格納するフィールドは、`Text1`~`Text30`のいずれかを使用しますが、ハードコードせず、モジュールの先頭で定数として定義してください。後で「別プロジェクトでText5を使いたい」と言われた際に、一行の変更で済むようにしておくのがエンジニアの矜持です。
② データベース連携の注意点
ProjectのデータをSQL Server等と同期させる場合、このWBSコードを「主キー」にしてはいけません。Project内部の`UniqueID`こそが唯一の正解です。カスタムWBSはあくまで「表示用メタデータ」として扱い、外部システムとの結合キーには`UniqueID`を必ず保持させてください。
③ エラーハンドリングの極意
`tsk.OutlineParent`は、ルートレベルのタスクに対してはエラー(またはNothing)を返します。上記のコードのように、`If Not … Is Nothing`によるチェックを怠ると、大規模なプロジェクトで必ずランタイムエラーが発生します。
—
最後に:自動化の先にあるもの
WBSコードの自動採番は、単なる「作業の効率化」ではありません。プロジェクトの構造を可視化し、チーム全員が同じ言語でタスクを語れるようにするための「言語形成」です。
VBAはレガシーと言われますが、Microsoft Projectという巨大なエンジンの深部に触れられるのは、VBAの特権です。このコードをベースに、あなたのプロジェクトがより強固な階層構造を持ち、管理の負荷から解放されることを願っています。
不明点があれば、常にオブジェクトブラウザを友とし、Projectのメタデータがどう流れているかを想像してください。それが、伝説のアーキテクトへの第一歩です。
