【テクニカル・上級編】【上級者向け】プロジェクトのオープン・保存イベントを監視するクラスモジュールの設計 – Project VBA解析バイブル

スポンサーリンク

Project VBAを掌握せよ:Applicationイベントによる「プロジェクト常駐監視システム」の深淵

プロジェクトマネジメントの現場で、MS ProjectのVBAを単なる「タスク自動化ツール」と見なしているなら、それは大きな誤解だ。MS Projectの真の力は、そのイベント駆動型アーキテクチャにある。

特に、プロジェクトのオープン・保存といったライフサイクルを完全に制御下に置くことは、エンタープライズレベルの統合管理システムにおいて不可欠な要件だ。本稿では、Applicationオブジェクトのイベントをフックし、プロジェクトの動向を不可侵なログとして記録するための、堅牢かつ軽量な常駐監視システムの構築手法を伝授する。

1. なぜ「Applicationイベント」なのか

MS ProjectのVBAにおいて、`Project_Open`や`Project_BeforeSave`といったイベントは`ThisProject`モジュールに記述するのが一般的だ。しかし、この手法には致命的な欠点がある。「各ファイルごとにコードを埋め込む必要がある」点だ。

シニアエンジニアとして、そんな非効率な設計は許容できない。我々が構築すべきは、グローバルにApplicationレベルでイベントを捕捉する「イベント・シンク・クラス」だ。これを使えば、アドインや単一の制御用ファイルから、開かれる全てのプロジェクトを一元管理できる。

2. 実装:イベント監視クラスの極意

まずは、Applicationイベントを外部から制御するためのクラスモジュール(仮名:`AppEventMonitor`)を設計する。

‘ クラス名: AppEventMonitor
Option Explicit

‘ WithEventsキーワードにより、Applicationのイベントを捕捉可能にする
Private WithEvents AppEvents As Application

‘ コンストラクタでApplicationをバインド
Public Sub Initialize(app As Application)
Set AppEvents = app
End Sub

‘ プロジェクトオープン時のイベント
Private Sub AppEvents_ProjectOpen(ByVal pj As Project)
‘ メモリリークを避けるため、極力軽量な処理を心がける
LogAction “OPEN”, pj.Name
End Sub

‘ プロジェクト保存前のイベント(ベースライン整合性チェック等に有効)
Private Sub AppEvents_ProjectBeforeSave(ByVal pj As Project, ByRef Cancel As Boolean)
If Not ValidateBaseline(pj) Then
‘ 保存を阻止する場合はCancel = Trueを設定
MsgBox “ベースラインが未設定です。保存を中断します。”, vbCritical
Cancel = True
End If
End Sub

‘ ログ記録用のプライベートメソッド
Private Sub LogAction(actionType As String, projectName As String)
Dim logPath As String: logPath = Environ(“USERPROFILE”) & “\Desktop\ProjectLog.csv”
Dim fileNum As Integer: fileNum = FreeFile

Open logPath For Append As #fileNum
Print #fileNum, Now & “,” & actionType & “,” & projectName
Close #fileNum
End Sub

3. シニアエンジニアが意識すべき「メモリの生存戦略」

このシステムの最大のリスクは、「イベント監視オブジェクトの予期せぬ破棄」だ。VBAにおいてグローバル変数は不安定な場合がある。確実に常駐させるためには、`Auto_Open`でインスタンスを生成し、静的な領域に保持させる必要がある。

‘ 標準モジュール: MonitorManager
Option Explicit

Private Monitor As AppEventMonitor

Public Sub Auto_Open()
‘ インスタンスを生成し、静的変数として生存させる
Set Monitor = New AppEventMonitor
Monitor.Initialize Application
End Sub

重要な知見:オブジェクトの解放

VBAにおいて`Set Monitor = Nothing`を行わない限り、このインスタンスはプロセス終了までメモリ上に留まる。レガシー環境では、COMポインタの解放が不完全だとExcelやProjectのゾンビプロセスが発生する原因となる。本システムのように「常駐」を前提とする場合は、明示的な終了処理(Terminateイベントでのクリーンアップ)を設計に組み込むことを推奨する。

4. Windows APIと連携した「極限の制御」

ログをCSVに書き出すだけでは物足りない場合、`kernel32.dll`を用いてシステムイベントログへの直接書き込みや、Mutexによる多重起動制御を行うことも可能だ。

例えば、プロジェクトの保存時にファイルサーバーへのネットワークトラフィックが激しい場合、`WaitForSingleObject`をAPIで呼び出し、同期を待機させる制御を入れることで、データの競合を物理的に回避できる。

‘ 特定のAPI宣言例
Private Declare PtrSafe Function GetCurrentProcessId Lib “kernel32” () As Long
‘ 監査ログにプロセスIDを付与することで、複数ユーザー環境での追跡性を飛躍的に向上させる

5. 結びに代えて

プロジェクトのライフサイクルを監視するということは、単に「いつ保存されたか」を知ることではない。「組織のナレッジがどのように変化したか」を可視化することだ。

この設計をベースに、さらに「ベースラインの変更履歴」や「リソース配分の異常検知」を組み込めば、それはもはやVBAの域を超えたエンタープライズ・ガバナンス・システムとなる。

コードは嘘をつかない。あなたの書くVBAが、今日もどこかで組織の資産を守る砦となることを期待している。


アーキテクトからの助言:
本コードは極めて強力だが、Projectのイベントは負荷が高い。ログ記録処理で重いAPIを叩く場合は、非同期処理を模倣するために `OnTime` メソッドを併用し、UIスレッドをブロックしないよう細心の注意を払うこと。それが、真のシニアエンジニアの流儀である。

タイトルとURLをコピーしました