【実務・中級編】【中級者向け】カスタムフィールドの値をクリアする際の高速化テクニック – Project VBA解析バイブル

スポンサーリンク
スポンサーリンク

【極限の知見】数千行のカスタムフィールドを瞬時に「無」に帰す:MS Project VBA 高速化の真髄

現場で「動くツール」を作っている人間は多い。しかし、「プロフェッショナルなツール」を作れる人間は極めて稀だ。

君がもし、数千行のタスクを抱える大規模プロジェクトの管理ツールを開発しているなら、一度立ち止まって考えてほしい。「カスタムフィールドの値をクリアする」という、一見シンプルに見える処理に、どれほどのコストを支払っているか?

もし君が、`For Each` でタスクを回し、一行ずつ `Task.Text1 = “”` と書き込むだけのコードを書いているなら、それは設計ミスだ。データ量が増大した瞬間、ユーザーの画面はフリーズし、君へのクレームは「重い」という言葉と共に押し寄せるだろう。

本稿では、MS Projectのオブジェクトモデルの深淵に触れ、数千行のカスタムフィールドを一括消去するための、計算量とオーバーヘッドを最小化する「極限の高速化テクニック」を伝授する。

1. なぜ、あなたのコードは遅いのか?:Recalculation Stormの正体

初級者が書くコードは、以下の構造だ。

' 【非効率なコードの典型例】
Sub BadPractice_ClearFields()
    Dim t As Task
    For Each t In ActiveProject.Tasks
        If Not t Is Nothing Then
            t.Text1 = "" ' ← ここが致命的なボトルネック
            t.Text2 = ""
        End If
    Next t
End Sub

なぜこれが遅いのか? 原因はコードの書き方そのものではなく、MS Projectの「再計算(Recalculation)エンジン」にある。

MS Projectは、タスクのプロパティ(特にカスタムフィールド)が変更されるたびに、「この変更によってスケジュールや計算式、依存関係に影響が出るか?」を検証しようとする。つまり、1つの値を書き換えるたびに、プロジェクト全体の再計算プロセスがトリガーされる。

これを繰り返すと、「値の書き換え → 再計算 → 書き換え → 再計算…」という、いわゆる Recalculation Storm(再計算の嵐) が発生する。これが、処理時間が指数関数的に増大する真犯人だ。

2. 勝利への設計指針:3つの鉄則

プロフェッショナルは、オブジェクトの状態を制御することで、この嵐を鎮める。

① Calculation モードの制御(最優先事項)

MS Projectの計算モードを `pjManual` に切り替える。これにより、値の変更がプロジェクト全体のスケジュールに及ぼす影響の検証を一時停止できる。これが最も劇的な効果をもたらす。

② ScreenUpdating の抑制

画面更新を止めるのは基本中の基本だ。描画処理は極めてコストが高い。描画を止めることで、CPUリソースを純粋なロジックに集中させる。

③ オブジェクトの生存確認とエラーハンドリング

大規模プロジェクトでは、タスクの削除やフィルタリングによって、`Tasks` コレクション内に `Nothing` が混在することがある。これを見逃すと、実行時エラーでツールは即死する。

3. プロダクション・グレードの実装例

以下に、私が実務で推奨している、堅牢かつ高速な実装パターンを示す。このコードは、単なる「クリア処理」ではなく、「システムの実行状態を適切に管理する」設計思想に基づいている。

''' <summary>
''' 数千行規模のタスクに対してカスタムフィールドを一括クリアする。
''' 計算モードと画面更新を制御し、オーバーヘッドを最小化する。
''' </summary>
Public Sub FastClearCustomFields()
    Dim targetProject As Project
    Dim t As Task
    Dim originalCalculation As Calculation
    Dim startTime As Double
    
    ' 実行時間の計測(パフォーマンス評価用)
    startTime = Timer
    
    On Error GoTo ErrorHandler
    
    Set targetProject = ActiveProject
    
    ' --- [Phase 1: 状態の保存と抑制] ---
    ' 現在の計算モードを保存(後で復元するため)
    originalCalculation = targetProject.Calculation
    
    ' 画面更新と計算を停止(これが高速化の核)
    Application.ScreenUpdating = False
    targetProject.Calculation = pjManual
    
    Debug.Print "Starting massive clear operation..."

    ' --- [Phase 2: 高速ループ実行] ---
    ' コレクションを直接回し、Nothingチェックを厳格に行う
    For Each t In targetProject.Tasks
        ' タスクが存在しない(削除済みなど)場合はスキップ
        If Not t Is Nothing Then
            ' 複数のフィールドをクリアする場合、
            ' プロパティへのアクセス回数を最小限にするのが定石
            t.Text1 = ""
            t.Text2 = ""
            t.Text3 = ""
            ' 必要に応じて追加
        End If
    Next t

    ' --- [Phase 3: 状態の復元] ---
    ' ユーザーの環境を壊さないよう、元の設定に戻す
    targetProject.Calculation = originalCalculation
    Application.ScreenUpdating = True
    
    MsgBox "処理が完了しました。" & vbCrLf & _
           "実行時間: " & Format(Timer - startTime, "0.00") & " 秒", vbInformation, "Success"

ExitSub:
    Exit Sub

ErrorHandler:
    ' エラーが発生した場合でも、必ず画面更新と計算モードを復元する
    ' これを怠ると、MS Projectが「使い物にならない状態」で止まってしまう
    Application.ScreenUpdating = True
    If Not targetProject Is Nothing Then
        targetProject.Calculation = originalCalculation
    End If
    
    MsgBox "致命的なエラーが発生しました。" & vbCrLf & _
           "Error No: " & Err.Number & vbCrLf & _
           "Description: " & Err.Description, vbCritical, "Critical Error"
    Resume ExitSub
End Sub

4. アーキテクトからの警告:データベース連携における注意点

もし君が、このクリア処理の結果を外部のデータベース(SQL ServerやAccess)やExcelファイルに書き出そうとしているなら、さらに注意が必要だ。

1. トランザクションの意識:
VBA側で大量の値を書き換えた直後に外部DBへ書き込む場合、MS Project側のメモリ上のデータと、DB側の整合性が一時的に崩れるリスクがある。必ず `targetProject.Calculation = pjAutomatic` で計算を完了させてから、外部へのエクスポート処理に移ること。
2. メモリの解放:
大規模なオブジェクト操作を繰り返す場合、`Set t = Nothing` をループの最後に入れる必要はないが、プロシージャを抜ける際に `Set targetProject = Nothing` を明示的に行うことで、COMオブジェクトのライフサイクルを制御し、メモリリークを防止する癖をつけておくべきだ。

結論

「動けばいい」という思考は、スケールしないシステムを生む。
MS Project VBAにおける高速化とは、単に速い書き方を探すことではない。「アプリケーションがいかにして計算し、描画し、メモリを管理しているか」という内部メカニズムを理解し、それを制御することだ。

この設計パターンをマスターすれば、君のツールは「重い」という批判を浴びることはなくなる。代わりに、「驚くほどスムーズだ」という賞賛を受けることになるだろう。

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