【テクニカル・上級編】【中級者向け】保存処理をフックして、未完了タスクがある場合に警告を出すカスタム保存ボタンの作成 – Project VBA解析バイブル

スポンサーリンク

プロジェクトの「整合性」を死守せよ:Project VBAにおけるガードロジックの極致

Project VBAの現場において、最も避けるべきは「不完全な状態での保存」である。標準の「保存」ボタンは無慈悲だ。ユーザーがどれほど未完了タスクを放置していようと、それがプロジェクトのベースラインを歪めるものであろうと、何食わぬ顔でディスクへ書き込む。

シニアエンジニアたる我々が構築すべきは、単なるツールではない。プロジェクトという「生き物」の整合性を担保するゲートキーパー(門番)である。

本稿では、標準の保存ボタンを無効化し、特定のビジネスロジックを通過したものだけをディスクにコミットする、堅牢なカスタム保存機構の設計論を説く。

1. 概念設計:なぜ標準の保存を「殺す」必要があるのか

MS ProjectのVBA環境において、`FileSave`メソッドをオーバーライドすることはできない。しかし、`ProjectBeforeSave`イベントをフックし、`Cancel`引数に`True`を代入することで、保存処理を物理的に遮断できる。

このアプローチの肝は、「なぜ保存が拒否されたか」というコンテキストをユーザーに即座にフィードバックするUXの設計と、メモリリークを許さないオブジェクト管理にある。

2. 実装:ガードロジックの実装コード

以下のコードは、プロジェクト内の「未完了タスク」を検出し、条件を満たさない場合に保存をキャンセルする実装例である。

‘ Class Module: clsProjectEvents
Option Explicit

‘ プロジェクトイベントをキャッチするための宣言
Private WithEvents prj As MSProject.Project

Private Sub Class_Initialize()
Set prj = ActiveProject
End Sub

‘ 【極限の知見】BeforeSaveイベントをフックする
Private Sub prj_BeforeSave(ByVal pj As MSProject.Project, ByVal SaveAs As Boolean, Cancel As Boolean)
Dim t As Task
Dim unfinishedCount As Long

‘ プロジェクトの整合性チェック
‘ パフォーマンス向上のため、フィルタリングではなくループ内での条件分岐を選択する
For Each t In pj.Tasks
If Not t Is Nothing Then
If Not t.Summary And t.PercentComplete < 100 Then unfinishedCount = unfinishedCount + 1 End If End If Next t ' ガードロジック:未完了タスクがある場合は保存を許可しない If unfinishedCount > 0 Then
MsgBox “保存エラー:未完了タスクが ” & unfinishedCount & ” 件存在します。” & vbCrLf & _
“全てのタスクを完了させてから保存してください。”, vbCritical, “Integrity Guard”

‘ ここでキャンセルをTrueにすることで、保存プロセスを物理的に停止させる
Cancel = True
End If
End Sub

‘ オブジェクトの明示的解放:メモリリークは許されない
Private Sub Class_Terminate()
Set prj = Nothing
End Sub

3. シニアエンジニアが意識すべき「深層」の技術課題

① イベントのライフサイクル管理

`WithEvents`を使用する際、クラス変数が生存し続けているかを確認せよ。イミディエイトウィンドウで`Set`したオブジェクトが消滅すれば、フックは解除される。アドイン(COMアドイン)として実装しない場合、`Auto_Open`でこのクラスをグローバル変数に格納し、ライフサイクルをアプリケーションの生存期間と同期させるのが定石だ。

② Windows APIによる「保存ボタン」の強制無効化

より高度な制御が必要な場合、`FindWindow`や`EnumChildWindows`を用いたWindows APIによるボタンコントロールのグレーアウトも検討対象となる。しかし、OfficeのバージョンアップによるUI構造の刷新リスクを考慮すると、`BeforeSave`イベントでの制御が現代の最適解である。

③ パフォーマンスの最適化

大規模なプロジェクトファイル(数万行)において、保存のたびに全タスクを走査するのは低コストではない。

  • フィルタリングの活用: `pj.Tasks.SelectByField`等で対象を絞り込む手法も有効だが、メモリ消費とのトレードオフになる。
  • チェックポイントの導入: 最終更新日時やベースラインとの差異フラグを事前にチェックし、計算コストを最小化せよ。

4. 総括:レガシーを「保守可能」にするために

このガードロジックを組み込むことで、システム管理者は「いつの間にかデータが汚染されている」という悪夢から解放される。VBAはレガシーと言われるが、その背後にある「状態管理の厳格化」というアーキテクチャの思想は、現代のどのモダンな開発言語においても不変の価値を持つ。

コードを書くのではない。プロジェクトの意志をコードに宿すのだ。これこそが、真のエンジニアリングである。


本稿が、貴殿の管理するプロジェクトに真の整合性をもたらす一助となれば幸いである。

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