序文:Project VBAという「聖域」の解体と再構築
Microsoft Project(以下、Project)のVBA開発は、ExcelやAccessのそれとは一線を画す。WBS(Work Breakdown Structure)という厳密なデータ構造、動的なスケジュール計算エンジン、そしてCOMオブジェクトの複雑な依存関係。これらが絡み合うProject VBAの現場において、多くの開発者が「コードの属人化」と「バイナリ管理の限界」という壁にぶち当たる。
MS Projectのファイル(.mpp)はバイナリ形式であり、VBAコードはその内部に密結合されている。Gitでの差分管理は不可能であり、複数人での同時開発は、往々にしてコードの先祖返りや不整合を招く。
本稿では、Project VBAのライフサイクルを知り尽くしたアーキテクトの視点から、WBS自動設定ツールの保守性を極限まで高めるための「バージョン管理の自動化」と「グローバルテンプレート(Global.mpt)を用いた配布戦略」について解説する。
—
1. コードの脱獄:バイナリからの解放とGit管理の実現
Project VBAのコードをGitで管理するためには、.mppファイルからモジュールをテキスト形式(.bas, .cls, .frm)で抽出し、同期させる仕組みが不可欠だ。
以下のコードは、Projectの保存イベントを利用して、プロジェクト内のすべてのコンポーネントを自動的に外部フォルダへエクスポートする。これにより、バイナリファイルでありながら、実質的なテキストベースのバージョン管理を可能にする。
実装:自動エクスポート・プロシージャ
‘ — Standard Module: mod_VersionControl —
Option Explicit
‘ Windows API: パス生成の精度を高めるために使用
Private Declare PtrSafe Function MakeSureDirectoryPathExists Lib “imagehlp.dll” (ByVal DirPath As String) As Long
”’
”’
Public Sub ExportVBAComponents()
Dim vbc As Object
Dim exportPath As String
Dim extension As String
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ エクスポート先は.mppファイルと同階層の “src” フォルダ
exportPath = ActiveProject.Path & “\src\”
‘ ディレクトリが存在しない場合は作成 (APIを使用)
If MakeSureDirectoryPathExists(exportPath) = 0 Then
Err.Raise 513, “ExportVBAComponents”, “ディレクトリの作成に失敗しました。”
End If
For Each vbc In ActiveProject.VBProject.VBComponents
Select Case vbc.Type
Case 1: extension = “.bas” ‘ 標準モジュール
Case 2: extension = “.cls” ‘ クラスモジュール
Case 3: extension = “.frm” ‘ ユーザーフォーム
Case Else: extension = “.txt”
End Select
‘ 既存ファイルはオーバーライト。COM参照を意識し、確実に解放する。
On Error Resume Next
vbc.Export exportPath & vbc.Name & extension
On Error GoTo 0
Next vbc
Set fso = Nothing
Debug.Print “Export Completed: ” & Now
End Sub
このスクリプトを `Project_BeforeSave` イベントにフックすることで、開発者が意識することなく、最新のソースコードがGitの管理対象(srcフォルダ)に同期される。
—
2. グローバルテンプレート (Global.mpt) の戦略的活用
開発したWBS自動設定ツールをチーム全体に配布する際、各プロジェクトファイル(.mpp)にコードをコピーするのは三流の仕事だ。保守性の観点からは、Global.mpt または アドイン形式(.mppを読み取り専用で共有) を採用すべきである。
Global.mpt への配布リスクと回避策
Global.mptはユーザー個別の設定ファイルであり、不用意に上書きするとユーザー固有のビューやカレンダーを破壊する恐れがある。これを防ぐため、我々は `Organizer` オブジェクトを操作し、特定のモジュールだけを動的にインポート/更新する「インストーラー」を配布する。
”’
”’
Public Sub UpdateGlobalTemplate()
Dim sourcePath As String
sourcePath = “\\NetworkShare\ProjectTools\Master_Tool.mpp”
On Error Resume Next
‘ Organizerを利用してモジュールを強制コピー
‘ 引数: Type, Source, Target, Name
Application.OrganizerMoveItem Type:=pjModules, _
FileName:=sourcePath, _
TargetName:=”Global.mpt”, _
Name:=”mod_WBS_Engine”
If Err.Number <> 0 Then
MsgBox “アップデートに失敗しました。Master_Tool.mppが閉じているか確認してください。”, vbCritical
Else
MsgBox “WBSエンジンを最新版に更新しました。”, vbInformation
End If
On Error GoTo 0
End Sub
—
3. 極限の最適化:WBS階層構造の自動設定ロジック
Project VBAにおいて最もパフォーマンスが要求されるのは、数千タスクに及ぶWBSの再構築と依存関係(Predecessors)の設定だ。
Projectのエンジンは、タスクの変更が発生するたびにスケジュールを再計算しようとする。これを抑制せずに大量のタスクを操作するのは、サイドブレーキを引いたままアクセルを踏むに等しい。
高速WBSエンジンの実装例
”’
”’
Public Sub RebuildWBSHierarchy()
Dim tsk As Task
Dim app As MSProject.Application
Set app = MSProject.Application
‘ 1. スケジュール計算の停止(パフォーマンスの肝)
app.Calculation = pjManual
app.ScreenUpdating = False
Try
‘ プロジェクト全体のタスクを走査
For Each tsk In ActiveProject.Tasks
If Not tsk Is Nothing Then
‘ メモリリーク回避のため、複雑な階層操作時は
‘ オブジェクトへの直接参照を最小限にする
ProcessTaskLogic tsk
End If
Next tsk
Catch:
‘ エラーハンドリング
Finally:
‘ 2. 計算の再開と強制再計算
app.Calculation = pjAutomatic
app.ScreenUpdating = True
app.CalculateAll
‘ COMオブジェクトの明示的解放
Set tsk = Nothing
Set app = Nothing
End Try
End Sub
Private Sub ProcessTaskLogic(ByRef tsk As Task)
‘ 依存関係設定の例:WBSレベルに基づき先行タスクを自動結合
‘ ここにWindows API等を用いた高速な文字列処理や条件判定を実装する
‘ ProjectのTaskオブジェクトは非常に重いため、極力プロパティへのアクセス回数を減らすこと
End Sub
—
4. シニアエンジニアが守るべき「鉄則」
COM参照カウンタの意識
Project VBAは内部でCOM(Component Object Model)を使用している。ループ内で `Task` オブジェクトを生成し、明示的に `Nothing` を代入せずにスコープを抜けると、メモリリークやProject終了時のプロセス残存の原因となる。特に外部アプリケーション(Excel等)からProjectを操作する場合は、この傾向が顕著だ。
非同期処理の壁
Project VBAは本質的にシングルスレッドである。しかし、Windows APIの `SetTimer` 等を利用した擬似的な非同期処理を組み込むことで、重い処理の実行中にプログレスバーを更新し、ユーザー体験を向上させることが可能だ。ただし、Projectの再計算エンジンと競合しないよう、排他制御には細心の注意を払わなければならない。
—
結論:システム管理者への提言
Project VBAの開発は、単なる自動化ではない。それは「不確実なスケジュール」という動的なデータを、いかに堅牢な構造に落とし込むかというエンジニアリングである。
1. ソースコードはバイナリから切り離せ。
2. 配布はGlobal.mptへの差分インポートを自動化せよ。
3. パフォーマンスのために再計算エンジンを制御せよ。
この三原則を遵守することで、Project VBAは「壊れやすいマクロ」から「信頼に足るエンタープライズシステム」へと昇華する。レガシーを恐れるな。その構造を理解し、現代のエンジニアリング手法を適用すること。それが、我々チーフアーキテクトの使命である。
