こんにちは!プロジェクト管理の現場で、日々スケジュールやリソースの調整に奔走お疲れ様です。
「マクロの記録」から一歩踏み出し、VBAを使って日常の業務を自動化できるようになったあなたなら、きっとこんな壁にぶぶつかったことがあるはずです。
- 「メンバーが勝手にプロジェクトファイルを保存してしまうのを防ぎたい」
- 「全社共通のルールで、ファイルを開いた瞬間に特定のチェック走らせたい」
- 「個別のファイルにマクロを埋め込むのではなく、すべてのProjectファイルで一括してイベントを監視したい」
通常のVBAマクロは、あくまで「開いているプロジェクトファイルの中」でしか動きません。そのため、新しいファイルを作られたり、マクロが入っていないファイルを勝手に操作されたりすると、途端に無力になってしまいます。
そこで今回は、一歩進んだ上級者向けのアプローチとして、「COMアドイン」を使ったプロジェクトのグローバル監視アーキテクチャを解説します。
「COMアドインって難しそう…」と思うかもしれませんが、ここをクリアすれば、あなたのProject VBAのスキルは間違いなくプロの領域に到達します。優しく紐解いていくので、一緒にマスターしていきましょう!
—
1. なぜ「COMアドイン」が必要なのか?
通常、私たちが書くVBAコードは、`ThisProject` モジュールなどに記述しますよね。これは「そのプロジェクトファイルが開かれている間だけ有効」というライフサイクルを持っています。
しかし、組織全体のプロジェクト管理を統制(ガバナンスを効かせる)するためには、以下のような要件が出てきます。
1. ユーザーがどんな名前のプロジェクトファイルを開いても、自動的に監視を始めたい。
2. 保存(`BeforeSave`)やオープン(`Open`)のタイミングで、勝手にコードを書き換えられないようにしたい。
3. すべてのPCに、同じロジックを強制的に適用したい。
これを実現するのが COMアドイン(Component Object Model Add-in) です。
VB.NET(C#でも可)を使って「外側」からMicrosoft Projectのアプリケーション全体(`MSProject.Application`)を監視し、イベントをフック(横取り)する仕組みを作ります。
—
2. 全体像:COMアドインのアーキテクチャ
まずは、どのような構造で動くのかイメージ図を見てみましょう。
[ Microsoft Project アプリケーション ]
│
├── ユーザーがファイルを開く / 保存する
│
▼ (イベント発生)
[ COMアドイン (VB.NET製 DLL) ] ← 常に裏側で常駐
│
├── グローバルイベントの検知 (ProjectOpen / BeforeSave)
│
▼
[ 統制ロジックの実行 ]
・WBSの命名規則チェック
・ベースライン設定の強制
・不正な保存のキャンセル
COMアドインは、Visual Studio(VB.NETやC#)を使い、クラスライブラリとして作成します。これをWindowsのレジストリに登録することで、Project起動時に自動的に読み込まれ、裏側で常駐する仕組みです。
—
3. 実装ステップ:VB.NETによるCOMアドインの骨組み
それでは、実際に動くコードの骨組みを見ていきましょう。
今回はVisual Studioを使い、VB.NETで「Projectのオープンと保存を監視する常駐ツール」を作成する手順を解説します。
ステップ①:プロジェクトの作成と参照設定
1. Visual Studioを開き、「クラス ライブラリ (.NET Framework)」プロジェクトを新規作成します(※.NET Framework 4.8などが安定しておすすめです)。
2. 参照設定に以下を追加します。
- `Microsoft.Office.Interop.MSProject` (COMタブから追加)
- `Extensibility` (COMアドインのインターフェース用)
ステップ②:アドイン本体のコード実装
以下のコードは、COMアドインとして動作し、Projectのアプリケーションイベントをフックするメインクラスのサンプルです。
Imports Extensibility
Imports Microsoft.Office.Core
Imports MSProject = Microsoft.Office.Interop.MSProject
Public Class Connect
Implements IDTExtensibility2
‘ Project アプリケーションオブジェクトを保持
Private WithEvents projApp As MSProject.Application
‘ アドインが読み込まれた時に呼ばれる (イニシャライゼーション)
Public Sub OnConnection(application As Object, connectMode As ext_ConnectMode, addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection
‘ Projectのアプリケーションインスタンスをキャプチャ
projApp = CType(application, MSProject.Application)
System.Windows.Forms.MessageBox.Show(“Project監視アドインが有効化されました。”, “Project Governance”)
End Sub
‘ アドインがアンロードされる時
Public Sub OnDisconnection(disconnectMode As ext_DisconnectMode, ByRef custom As Array) Implements IDTExtensibility2.OnDisconnection
projApp = Nothing
End Sub
‘ — 以下、その他のIDTExtensibility2必須メソッド(中身は空でOK) —
Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate End Sub
Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete End Sub
Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown End Sub
‘ =================================================================
‘ ここからが本番:グローバルイベントの監視
‘ =================================================================
‘ 1. プロジェクトオープン時のイベント
Private Sub projApp_ProjectOpen(ByVal pj As MSProject.Project) Handles projApp.ProjectOpen
‘ 組織の統制チェック:例として、オープン時にベースラインが未設定なら警告する
Try
If pj.Name <> “” Then
‘ ここにプロジェクトが開かれた瞬間に走らせたいロジックを書く
‘ 例: 必須カスタムフィールドのチェックなど
System.Diagnostics.Debug.WriteLine(“オープン検知: ” & pj.Name)
End If
Catch ex.Exception
System.Windows.Forms.MessageBox.Show(“エラーが発生しました: ” & ex.Message)
End Try
End Sub
‘ 2. プロジェクト保存前のイベント(保存のキャンセルも可能!)
Private Sub projApp.BeforeSaveProject(ByVal pj As MSProject.Project, ByRef Cancel As Boolean) Handles projApp.BeforeSaveProject
‘ 例:プロジェクト名に特定のルール(例: [PJ]など)が含まれていない場合、保存を拒否する
If Not pj.Name.StartsWith(“[PJ]”) Then
System.Windows.Forms.MessageBox.Show(
“【保存エラー】” & vbCrLf & “プロジェクト名の先頭には必ず ‘[PJ]’ を付与してください。”,
“組織統制ポリシー”,
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error
)
‘ 保存を強制キャンセル!
Cancel = True
End If
End Sub
End Class
—
4. 陥りやすいエラーとアーキテクチャの罠
このレベルの開発を行うと、VBA単体では遭遇しない独特のトラップにハマることがあります。エンジニアとして知っておくべき重要ポイントを挙げておきます。
罠①:COMの参照解放(メモリリーク)
VB.NETからProjectのオブジェクト(`Project` や `Task` など)を操作する際、背後ではCOMコンポーネントが動いています。
ループ処理などで `System.Runtime.InteropServices.Marshal.ReleaseComObject()` を適切に呼ばないと、Projectを閉じた後もプロセスが裏に残り続け(ゾンビプロセス)、次回起動時にファイルがロックされる原因になります。
罠②:イベント内での無限ループ
`BeforeSaveProject` の中でファイル名をプログラムから書き換えようとすると、「保存」→「イベント発火」→「ファイル名変更」→「再保存」の無限ループに陥り、Projectがフリーズします。
イベントハンドラ内では「データの読み取りや検証(Cancelの切り替え)」にとどめ、書き込みを行う場合は慎重にフラグ制御を行いましょう。
—
5. まとめ:ここをクリアすれば、Project VBAの基本はバッチリ!
今回は、あえて少し背伸びをした「COMアドインによるグローバル監視アーキテクチャ」をご紹介しました。
- VBAマクロは、個別のファイル内を自動化する「特効薬」。
- COMアドインは、組織全体をシステム的に守る「インフラ」。
この2つを使い分けられるようになれば、あなたはもはや「マクロが書ける一般社員」ではなく、立派な業務自動化・アーキテクチャ設計エンジニアです。
現場のルールを強制し、品質の担保されたプロジェクト管理を実現するために、ぜひこのアプローチに挑戦してみてください。あなたのエンジニアとしての引き出しが、確実に何段階もレベルアップしますよ!
