序文:Project VBAという「聖域」の制御について
Microsoft ProjectのVBA、特にProject Server/Online(以下、Project Web App: PWA)が絡む環境は、一般的なExcel VBAとは一線を画す。そこは、COMオートメーション、ネットワーク遅延、分散排他制御、そして「チェックアウト」という厳格なステート管理が支配する、泥臭くも崇高なエンジニアリングの戦場だ。
多くの開発者が、単に `FileOpenEx` を叩けば済むと考えて挫折する。サーバーベースのプロジェクトファイルは、単なるバイナリデータではない。それはデータベース上のエンティティであり、チェックアウトという「儀式」を経て初めて、我々のコードに書き込み権限が委譲されるのだ。
本稿では、Project Server環境におけるチェックアウト・チェックイン制御の極致、そしてAPIエラーをねじ伏せるための堅牢な実装哲学を提示する。
—
1. チェックアウト制御の深層:なぜ標準のオープンでは不十分なのか
PWA環境において、プロジェクトをプログラムから制御する際、最も回避すべきは「意図しない読み取り専用オープン」と「ゴースト・チェックアウト」である。
Project Professionalのオブジェクトモデルにおいて、プロジェクトがチェックアウト可能かどうかを判定するのは `Project.Enterprise` プロパティと `Project.CheckedOut` プロパティだが、これらは「開いた後」にしか確定しない。しかし、エンタープライズ環境では「開く前に状態を知り、開いた後に確実にロックを確保する」という二段構えの戦略が必要となる。
ライフサイクル管理の鉄則
1. 先行判定: すでに誰かにチェックアウトされていないか。
2. 排他確保: `CheckoutProject` メソッドの明示的実行。
3. 状態監視: 非同期的なサーバー処理の完了待機。
4. 確実な解放: 異常終了時を含めた `Checkin` または `UndoCheckout` の保証。
—
2. 実践:チェックアウト制御とエラーハンドリングの極限実装
以下のコードは、単なるサンプルの域を超え、本番環境での耐えうる堅牢性を追求したものである。
‘
‘ 業務自動化の極致:Project Server チェックアウト制御モジュール
‘
‘ 概要: サーバー上のプロジェクトを安全にチェックアウトし、処理後にチェックインする。
‘ 考慮事項: ネットワーク遅延、他者によるロック、COM参照の明示的解放
‘
Option Explicit
Public Sub SecureProjectUpdate(ByVal projectName As String)
On Error GoTo ErrorHandler
Dim pjApp As MSProject.Application
Set pjApp = MSProject.Application
‘ 1. アプリケーション状態の最適化
pjApp.ScreenUpdating = False
pjApp.DisplayAlerts = False ‘ サーバーの警告ダイアログを抑制
‘ 2. プロジェクトをサーバーから開く
‘ FileOpenExの引数: Name, ReadOnly, Merge, TaskInformation, Table, Sheet, NoAuto, …
‘ サーバーパスは “<>\ProjectName” の形式
Debug.Print “Opening: ” & projectName
pjApp.FileOpenEx Name:=”<>\” & projectName, ReadOnly:=False
Dim targetPj As MSProject.Project
Set targetPj = pjApp.ActiveProject
‘ 3. エンタープライズ属性の確認
If Not targetPj.Enterprise Then
Err.Raise vbObjectError + 1001, , “対象はエンタープライズプロジェクトではありません。”
End If
‘ 4. チェックアウト状態の制御
‘ すでに自らチェックアウトしているか、あるいはチェックアウトが必要な状態か
If Not IsProjectCheckedOutByMe(targetPj) Then
Debug.Print “Attempting Checkout…”
On Error Resume Next
targetPj.CheckoutProject
If Err.Number <> 0 Then
On Error GoTo ErrorHandler
Err.Raise vbObjectError + 1002, , “チェックアウトに失敗しました。他者が編集中である可能性があります。”
End If
On Error GoTo ErrorHandler
End If
‘ — ここに業務ロジックを記述(ベースライン設定、タスク更新等) —
Debug.Print “Executing business logic…”
‘ 例: targetPj.Baselines(pjBaseline).Save
‘ ————————————————————-
‘ 5. 保存とチェックイン
Debug.Print “Saving and Checking in…”
pjApp.FileSave
targetPj.Checkin
‘ プロジェクトを閉じる(保存済みなのでFalse)
pjApp.FileCloseEx pjDoNotSave
CleanUp:
‘ 6. オブジェクトの明示的解放(メモリリークとゾンビプロセスの防止)
Set targetPj = Nothing
pjApp.ScreenUpdating = True
pjApp.DisplayAlerts = True
Exit Sub
ErrorHandler:
Dim errDesc As String: errDesc = Err.Description
Debug.Print “Critical Error: ” & errDesc
‘ 異常時のリカバリ処理
If Not targetPj Is Nothing Then
‘ チェックアウト状態であれば、変更を破棄して元に戻す(他者の作業を阻害しない)
On Error Resume Next
‘ targetPj.UndoCheckout ‘ 必要に応じて検討
pjApp.FileCloseEx pjDoNotSave
End If
MsgBox “システムエラーが発生しました。処理を中断します。” & vbCrLf & errDesc, vbCritical
Resume CleanUp
End Sub
‘ プロジェクトが自分によってチェックアウトされているかを判定する内部関数
Private Function IsProjectCheckedOutByMe(pj As MSProject.Project) As Boolean
‘ CheckedOutプロパティは、現在のセッションで編集可能かを返す
‘ Project Online環境では、この判定がAPIの挙動を左右する
IsProjectCheckedOutByMe = pj.CheckedOut
End Function
—
3. アーキテクトが語る「エラーハンドリング」の真髄
ネットワーク・レジリエンス
Project OnlineはWebサービス(OData/CSOM)の背後で動作している。VBAからの命令は、Win32 APIを介してサーバーへのリクエストに変換される。ここで最も恐ろしいのは 「サイレント・フェイル」 だ。
コード上では成功したように見えても、サーバー側で保存キューが滞留し、実際には反映されていないケースがある。これを防ぐには、`FileSave` の後に `Project.LastSaveDate` を検証するか、あるいはチェックインの戻り値を厳密に監視するロジックを組み込むべきだ。
メモリ最適化とCOM参照の解放
Project VBAをサーバー連携で回す際、最も多いトラブルは「Project Professionalのプロセスが残る」ことだ。
`Set pjApp = Nothing` や `Set targetPj = Nothing` を怠ると、バックグラウンドで `WINPROJ.EXE` が増殖し、最終的にはPWAのセッション上限に達してシステム全体がロックダウンする。`ErrorHandler` 内でも確実に `Nothing` を代入する設計は、シニアエンジニアとしての「マナー」である。
UI抑制の副作用
`Application.DisplayAlerts = False` は強力だが、サーバー側で「強制的なチェックアウトの競合」が発生した際のダイアログまで消し去ってしまう。この場合、VBAはタイムアウトまで応答なし(ハング)状態になることがある。これを回避するためには、Windows APIの `SendMessageTimeout` を利用した生存監視や、あらかじめ `IsCheckedOut` 状態を別の軽量な手段(REST API等)で確認するハイブリッドアプローチも検討に値する。
—
4. 結言:レガシーを掌握し、次世代へ繋ぐ
Project VBAは、決して枯れた技術ではない。むしろ、PWAという複雑なクラウドインフラを、デスクトップの強力な演算リソースで制御するための、極めて有効なインターフェースである。
チェックアウト一つをとっても、そこにはサーバーとの同期、排他制御の哲学、そして例外系への深い洞察が求められる。本稿で示したコードと設計思想が、あなたの現場における「止まらないシステム」の礎となれば幸いである。
技術は、細部に宿る。そして、その細部を支配する者だけが、真の自動化を成し遂げることができるのだ。
