テンプレートの強制同期:Project VBAにおける「定義の整合性」を極める
多くのエンジニアがProjectのカスタムフィールド(ユーザー設定フィールド)管理で躓くのは、単にフィールドを作成するからではない。「既存の汚染されたプロジェクトファイル」に対して、いかにして組織標準の定義を非破壊的に、かつ確実にインポートするか、という点にある。
GUIで「構成のインポート」をポチポチ押しているようでは、全社レベルのPMO業務は回らない。今回は、テンプレートファイル(.mpt)からフィールド定義のみを抽出・強制同期させる、堅牢なVBAアーキテクチャを提示する。
—
1. なぜ「OrganizerCopy」の直接利用は危険か
MS Projectの`OrganizerCopy`メソッドは強力だが、無策に呼び出すと致命的なエラーやメモリリークを招く。特に、プロジェクトがオープン状態にある際、オブジェクトの参照が解放されないままインポートを繰り返すと、Project自体のメモリスタックを圧迫する。
我々が目指すべきは、「ソース(テンプレート)とターゲット(対象ファイル)の完全な分離」と「オブジェクトの明示的な破棄」である。
—
2. 実装:カスタムフィールド定義の強制同期メカニズム
以下のコードは、指定したテンプレートからフィールド定義のみをターゲットへ流し込むためのコアロジックだ。
Option Explicit
‘ 伝説的なエンジニアは、常にスコープを最小化し、メモリを制御下に置く
Public Sub SyncCustomFieldsFromTemplate(ByVal targetProject As Project, ByVal templatePath As String)
Dim srcApp As Object
Dim srcProject As Project
‘ 1. インスタンスの分離とバックグラウンド処理
‘ 非表示でインスタンスを起動し、リソースの競合を回避する
Set srcApp = CreateObject(“MSProject.Application”)
srcApp.Visible = False
On Error GoTo Cleanup
‘ 2. テンプレートを読み取り専用で開く(共有違反回避)
srcApp.FileOpenEx Name:=templatePath, ReadOnly:=True
Set srcProject = srcApp.ActiveProject
‘ 3. フィールド定義の同期 (pjCustomFields)
‘ OrganizerCopyは第4引数をTrueにすることで既存定義を上書き更新する
Application.OrganizerCopy Source:=templatePath, _
Destination:=targetProject.FullName, _
Name:=””, _
Object:=pjCustomFields
Debug.Print “Synchronization Successful: ” & targetProject.Name
Cleanup:
‘ 4. オブジェクトの明示的解放
‘ ここを疎かにするエンジニアは、大規模環境で必ず痛い目を見る
If Not srcProject Is Nothing Then srcProject.Close SaveChanges:=False
If Not srcApp Is Nothing Then srcApp.Quit
Set srcProject = Nothing
Set srcApp = Nothing
If Err.Number <> 0 Then
MsgBox “Critical Error: ” & Err.Description, vbCritical
End If
End Sub
—
3. チーフアーキテクトからの深掘り:知見と教訓
A. メモリ管理の真実
`CreateObject(“MSProject.Application”)` を使用して別プロセスでテンプレートを読み込むのは、単なる「行儀の良さ」ではない。ProjectのCOMコンテナは非常に脆弱であり、同一プロセス内で大量のオブジェクト操作を行うと、ガーベッジコレクションが追いつかず、ProjectのGUIがフリーズしたり、最悪の場合はファイル破損を引き起こす。この分離は必須の安全策だ。
B. レガシーな環境との向き合い方
古いバージョンのProject Serverや、ネットワークドライブ上の不安定なパスが混在する環境では、`FileOpenEx`の際に`ReadOnly`を指定することが不可欠である。排他制御の衝突は、VBAのスタックトレースを破壊する最大の要因となる。
C. パフォーマンスの最適化
今回、`OrganizerCopy`を使用して一括コピーを行っているが、個別のフィールド定義を細かく制御したい場合は、`CustomFieldProperties`オブジェクトを直接イテレーションする手法をとるべきだ。しかし、今回のテーマである「組織標準の整合性」を保つには、テンプレート自体をマスターとして全コピーを行うのが最も堅牢である。
—
4. 最後に:エンジニアが守るべき矜持
システム管理ツールは、ユーザーが意識せずに「正しく」動くことが最大の価値だ。今回紹介した手法は、組織内のプロジェクトファイルが個別にカスタマイズされ、収拾がつかなくなった状況を救うための「外科手術」である。
コードをコピペするだけで満足してはならない。なぜ別プロセスを立ち上げるのか、なぜ`Set = Nothing`が重要なのか。その背後にあるメモリ管理の哲学を理解した者だけが、真の自動化エンジニアとして評価される。
次は、これを「Project Serverのチェックイン・チェックアウト処理」と組み合わせる高度な非同期処理について解説する予定だ。腕に自信がある者は、今のうちにメモリの解放順序を完璧に体に叩き込んでおくように。
