こんにちは!プロジェクト管理の現場で日々、Microsoft Project(以下、MS Project)と格闘お疲れ様です。
「マクロを書いたはいいものの、現場のメンバーが保存するたびに実行し忘れて、進捗データがゴミだらけになる…」
「毎回手動で不要なタスクや一時的なフィルターをクリアしてから保存してほしいのに、誰もやってくれない…」
そんな悩みを抱えたことはありませんか?VBAのコードを`.mpp`ファイルの中に仕込んでも、ユーザーがマクロを有効にしてくれなかったり、そもそも実行を忘れたりすれば意味がありません。
今回は、そんな現場の絶望を華麗に解決する【上級者向け】COMアドインを利用した「保存時強制クリーンアップ」機能の配布について、熱く、そして分かりやすく解説していきます。
ここをクリアすれば、Project VBAとアドイン開発の本質がグッと見えてきますよ。焦らず、一歩ずつ紐解いていきましょう!
—
1. なぜ「VBAマクロ」ではなく「COMアドイン」なのか?
通常のVBAマクロは、プロジェクトファイル(`.mpp`)の中にコードを保存します。しかし、これには致命的な弱点があります。
1. ユーザー依存: マクロのセキュリティ警告が出ると、ユーザーが「無効」にしてしまう。
2. ファイルごとの管理: 新しいプロジェクトを作るたびに、テンプレートからマクロを引き継がせる必要がある。
3. 強制力の欠如: 「保存」というシステムイベントにVBAからフック(割り込み)をかけるのが難しい場合がある。
ここで登場するのがCOMアドインです。
COMアドインは、MS Projectそのものに「常駐するプログラム」としてインストールされます。つまり、ユーザーがどのプロジェクトファイルを開こうが、保存しようが、裏でアドインが強制的に介入し、勝手にクリーンアップを実行するという、神がかった自動化が可能になるのです。
—
2. 全体像の把握:アドインが動く仕組み
COMアドインを作るというと「なんだか難しそう…」と思われるかもしれませんが、基本の概念はシンプルです。
1. イベントのキャッチ: MS Projectが「保存ボタンが押された瞬間(BeforeSave)」を検知する。
2. 強制クリーンアップの実行: プロジェクト内の不要なリソース、孤立したタスク、ローカルの不要なビュー設定などをコードで一掃する。
3. 保存の継続: クリーンアップが終わったピカピカの状態のデータを、そのままディスクに書き込ませる。
今回は、この仕組みをVB.NET(Visual Studio)で作成し、全ユーザーに配布する形を想定して解説します。
—
3. 実装ステップ:COMアドインの核心コード
Visual Studioで「Shared Add-in」または「COMアドイン(クラスライブラリ .NET Framework)」プロジェクトを作成したと仮定し、MS Projectのイベントをフックする核心部分を見ていきましょう。
以下のコードは、MS Projectの保存イベントを捉え、保存の直前に不要なデータを消し去るマジックコードです。
Imports Extensibility
import Microsoft.Office.Interop.MSProject
import System.Runtime.InteropServices
Public Class Connect
Implements IDTExtensibility2
Private appProject As Microsoft.Office.Interop.MSProject.Application
‘ アドインが読み込まれた時に呼ばれる
Public Sub OnConnection(application As Object, connectMode As ext_ConnectMode, addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection
appProject = CType(application, Microsoft.Office.Interop.MSProject.Application)
‘ MS Projectのイベントハンドラをフックする
AddHandler appProject.ProjectBeforeSave, AddressOf ForceCleanupBeforeSave
End Sub
‘ 【核心】保存直前に走るイベントプロシージャ
Private Sub ForceCleanupBeforeSave(ByVal pj As Microsoft.Office.Interop.MSProject.Project, ByRef Cancel As Boolean)
try
‘ ユーザーに無言で実行するため、画面描画を一旦ストップ(パフォーマンス向上)
appProject.ScreenUpdating = False
‘ 1. 完了したタスクにぶら下がる不要なゴーストデータを削除する処理(例)
Dim t As Task
For Each t In pj.Tasks
If t IsNot Nothing Then
‘ 例:名前が空のタスクや、異常なフラグが立ったものを強制削除
If t.Name = “” Then
t.Delete()
End If
End If
Next t
‘ 2. 使われていない一時的なリソースの割り当てをクリア
‘ (ここに独自のクリーンアップロジックを記述します)
‘ ログを残す(社内サーバー等へ)
System.Windows.Forms.MessageBox.Show(“プロジェクトは正常にクリーンアップされてから保存されます。”, “クリーンアップ・アドイン”)
Catch ex As Exception
‘ エラー時に保存自体をクラッシュさせないためのフェイルセーフ
System.Windows.Forms.MessageBox.Show(“クリーンアップ中にエラーが発生しました: ” & ex.Message, “警告”, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning)
Finally
‘ 画面描画を復元
appProject.ScreenUpdating = True
End Try
End Sub
‘ アドインがアンロードされる時の処理
Public Sub OnDisconnection(disconnectMode As ext_DisconnectMode, ByRef custom As Array) Implements IDTExtensibility2.OnDisconnection
appProject = Nothing
End Sub
‘ その他の必須インターフェース実装(省略)
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
End Class
コードのポイント解説
- `appProject.ProjectBeforeSave`: これこそが、全ユーザーの「保存」に介入する最強のフックポイントです。保存ボタンが押された瞬間、ファイルが書き込まれる「一瞬前」にこのプロシージャが割り込みます。
- `ScreenUpdating = False`: 大規模なプロジェクトファイルでは、マクロやアドインでタスクを走査する処理は重くなりがちです。画面描画をロックすることで、ユーザーにストレスを与えない高速な処理を実現します。
- `Try…Catch` 構造: 万が一クリーンアップ処理内で予期せぬエラーが起きても、プロジェクトファイルの保存自体が失敗してデータが失われないよう、フェイルセーフを絶対に組み込みましょう。
—
4. 現場で陥りやすい罠とエラー回避の知見
上級者へのステップアップとして、実際にこのアドインを組織内に配布した際によくある「罠」と、その対策を共有しておきます。
罠1:COMアドインのレジストリ登録権限問題
原因: ユーザーのPCにアドインをインストールする際、Windowsのレジストリ(`HKEY_CURRENT_USER` または `HKEY_LOCAL_MACHINE`)に適切なキーを書き込む必要がありますが、権限エラーで弾かれることがあります。
対策: `.msi` インストーラーを作成し、部署ごとの展開ツール(SCCMやIntuneなど)を用いてサイレントインストールする仕組みを情報システム部門と連携して構築します。
罠2:無限保存ループの恐怖
原因: クリーンアップ処理の中でうっかり `pj.Save()` などの保存メソッドを呼び出してしまった場合、「保存しようとする → クリーンアップが走る → 保存する → クリーンアップが走る…」という無限地獄(スタックオーバーフロー)に陥ります。
対策: `ProjectBeforeSave` イベントの引数にある `Cancel` やフラグ管理を徹底し、アドイン側からプログラム的に保存をトリガーしないように厳重に設計してください。
—
まとめ:自動化の「その先」へ
今回は、VBAの枠を超えたCOMアドインによる「保存時強制クリーンアップ」という、一歩進んだ自動化の世界をご紹介しました。
「マクロを書いて終わり」ではなく、「ユーザーが意識しなくても、システムが勝手に正しい状態へ導いてくれる環境を作る」ことこそが、真の業務自動化エンジニアの仕事です。
最初は難しく感じるかもしれませんが、一度この仕組みを構築してしまえば、組織全体のプロジェクトデータの品質は劇的に向上します。ぜひ、あなたの現場でもチャレンジしてみてくださいね。
ここをクリアすれば、Project VBAの基本と応用はもうバッチリですよ!次のステップへ進みましょう。
