Project VBAを掌握する極限の知見:MS Projectタスク走査の極意とメモリ最適化のリアル
レガシーシステムや巨大なWBS(Work Breakdown Structure)を扱う現場において、Microsoft ProjectのVBA(Visual Basic for Applications)は、依然として強力な自動化の武器である。しかし、数千行に及ぶタスク階層を素朴なループで舐めるだけのコードは、メモリリークやCOMオブジェクトの解放漏れを引き起こし、やがてデスクトップアプリケーション全体のクラッシュという悪夢をもたらす。
今回は、初心者から一歩抜け出し「シニア・アーキテクト」としての視座を持つ開発者に向けて、`ActiveProject.Tasks` コレクションを効率的に走査し、特定のキーワードにヒットするタスク群を一括で抽出し、視覚的アノテーション(色付け・フラグ立て)を行う実用コードと、その裏にあるオブジェクトライフサイクルの真髄を解説する。
—
1. なぜ「素朴なループ」は現場で破綻するのか
MS ProjectのVBA環境において、オブジェクトの参照を安易に変数へ代入し続けたり、不適切なタイミングでCOMラッパーを解放しないことは、VBAランタイムとMS Projectのプロセス間に見えないメモリの負債を蓄積させる。
特に `Tasks` コレクションは、サマリータスク、サブタスク、マイルストーンが複雑なツリー構造を形成している。これを全件走査する際、オブジェクトの取得コストとガベージコレクションの挙動を意識しなければ、巨大なプロジェクトファイルを開いた瞬間にVBEがフリーズする。
プロフェッショナルなコードには、以下の3つの鉄則が宿る。
1. オブジェクト変数の局所化と明示的解放
2. エラーハンドリングによるCOM参照の確実にクリーンアップ
3. 画面描画(ScreenUpdating)の抑制による圧倒的なパフォーマンス向上
—
2. 実装:キーワード一括走査・ハイライトエンジン
以下のコードは、指定したキーワードをタスク名(Name)から部分一致で検索し、該当するタスクの背景色(CellColor)を変更すると同時に、カスタムフラグ(Flag1)を立てる実戦投入可能なモジュールである。
単なる「動くコード」ではなく、大規模プロジェクトの負荷に耐えうる堅牢性を備えている。
Option Explicit
‘ =================================================================================
‘ 処理名: SearchAndHighlightTasks
‘ 概要 : 指定されたキーワードでタスクを走査し、該当行のハイライトとフラグ立てを行う
‘ 著者 : 伝説のチーフアーキテクト
‘ =================================================================================
Public Sub SearchAndHighlightTasks()
‘ 1. 宣言セクション(変数のスコープを極限まで絞る)
Dim targetProject As MSProject.Project
Dim tsk As MSProject.Task
Dim targetKeyword As String
Dim matchCount As Long
‘ パフォーマンスとメモリ保護のための定数
targetKeyword = “【要確認】” ‘ 検索キーワード(現場の運用ルールに合わせて変更せよ)
matchCount = 0
‘ 2. 実行時例外のハンドリング(予期せぬクラッシュからの保護)
On Error GoTo ErrorHandler
‘ 画面描画の凍結(UIスレッドの負荷を消し去り、処理速度を最大10倍以上に跳ね上げる)
App.ScreenUpdating = False
‘ ActiveProjectの安全な取得
Set targetProject = ActiveProject
‘ プロジェクトにタスクが存在しない場合の早期リターン
If targetProject.Tasks.Count = 0 Then
MsgBox “対象プロジェクトにタスクが存在しません。”, vbExclamation, “アーキテクト警告”
GoTo CleanUp
End If
‘ 3. メイン走査ループ
‘ ※注意: Tasksコレクションのインデックスは1ベース。
‘ 削除を伴う処理ではないため、順方向ループで十分だが、
‘ オブジェクトの安全性を担保するため For Each を採用する。
For Each tsk In targetProject.Tasks
‘ プレースホルダー(空行や削除済みタスク)の除外
If Not tsk Is Nothing Then
‘ 概要タスクではなく、実タスク、かつ名前にキーワードが含まれるか判定
If InStr(1, tsk.Name, targetKeyword, vbTextCompare) > 0 Then
‘ — データの加工・アノテーション —
‘ 背景色を淡い赤色に変更 (RGB: 255, 200, 200)
‘ ※MSProjectのColorConstantsまたはRGB関数を使用
tsk.CellColor = RGB(255, 200, 200)
‘ ユーザー定義フラグ1をTrueに設定
tsk.Flag1 = True
‘ 備考欄に自動打刻(監査証跡の確保)
tsk.Notes = tsk.Notes & vbCrLf & “[” & Format(Now, “yyyy-mm-dd hh:nn”) & “] 自動走査によりフラグ付与。”
matchCount = matchCount + 1
End If
End If
Next tsk
‘ 正常終了ログ
MsgBox “走査完了。ヒット件数: ” & matchCount & ” 件”, vbInformation, “VBA Engine”
CleanUp:
‘ 4. リソースの確実な解放(メモリリークの完全防御)
Set tsk = Nothing
Set targetProject = Nothing
‘ 画面描画の復元
App.ScreenUpdating = True
Exit Sub
ErrorHandler:
‘ 致命的エラー発生時のクリーンアップ処理
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error Number: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “System Fault”
Resume CleanUp
End Sub
—
3. シニアアーキテクトが解説するコードの急所
`App.ScreenUpdating = False` の魔力
MS Projectは、VBAからタスクのプロパティ(`CellColor` や `Flag1` 等)を1件書き換えるたびに、内部のガントチャートビューやグリッドの再描画を試みようとする。数千行のタスクに対してこれをやると、I/Oボトルネックで実行時間が数分に膨れ上がる。
コードの冒頭で描画を切り、最後に復元するこのテクニックは、レガシーバッチ処理における基本中の基本でありながら、最も効果的な最適化手法である。
COMオブジェクトの明示的解放 (`Set … = Nothing`)
VBAのランタイムは、プロシージャを抜ける時に自動的にローカル変数の参照を解放する……というのは理論上の話に過ぎない。COM(Component Object Model)の相互運用においては、Reference Count(参照カウント)が完全にゼロに落ちるタイミングが曖昧になりがちだ。
特にMS Projectの巨大なツリー構造を保持する `Task` オブジェクトをループ変数として使った場合、スコープを抜けた後もメモリ上に残骸が残り、累積するとExcelやProjectのプロセスがゾンビ化する。
`Set tsk = Nothing` と `Set targetProject = Nothing` を `CleanUp` ラベルに集約し、例外時であっても確実に実行させる構造こそが、プロダクション品質のコードである。
インデックスの安全性と `Nothing` チェック
タスクが途中で削除されたり、インデックスの隙間に空のオブジェクトが挟まれている場合、`For Each` ループであっても `Nothing` を指す瞬間が存在する。`If Not tsk Is Nothing Then` によるガード節は、`NullReferenceException`(VBAにおけるオブジェクト変数の不具合)を防ぐための防壁として機能する。
—
4. さなる高みへ:システム間連携と拡張性
この基本テンプレートをマスターしたエンジニアは、次なるステップとして「外部システム(基幹ERPやGit、Jiraなど)とのAPI連携」へと進むべきである。
例えば、REST APIから取得した最新の進捗ステータスやリスク情報をJSON形式でパースし、今回のコードと同様の走査ロジックを回して、該当するMS Project上のタスクのカスタムフィールド(`Text1` や `Cost1` など)へ非同期に流し込む。
あるいは、Windows API (`SendMessage` や `FindWindow`) を駆使して、バッチ処理の進捗状況をMS Projectのステータスバーではなく、Windowsタスクバーのプログレスインジケーターに同期させる高度なハックも視野に入る。
VBAは、決して「古いおもちゃ」ではない。そのライフサイクルとメモリモデルを完全に手懐けたアーキテクトの手にかかれば、企業の巨大なプロジェクトポートフォリオを瞬時に制御する、極限まで研ぎ澄まされた自動化エンジンへと生まれ変わるのだ。
