【テクニカル・上級編】【パフォーマンス向上】画面更新を停止してマクロを高速化する:ScreenUpdatingとCalculationの制御 – Project VBA解析バイブル

スポンサーリンク

Project VBAの深淵:ScreenUpdatingとCalculationを制御し、計算リソースを極限まで絞り出す

諸君、MS ProjectのVBA環境において、標準的なループ処理がいかに「鈍重な重石」と化すかを理解しているか。

数千行のタスクを回す際、デフォルトの挙動に身を任せるのは素人のやることだ。MS ProjectのGUIは、一つ一つのTaskオブジェクトの変更に対し、イベントを拾い、再描画を行い、さらにはスケジューリングエンジンを再計算しようと試みる。これらを放置することは、砂利道でスポーツカーを走らせるようなものだ。

本稿では、レガシーなアーキテクチャの制約を逆手に取り、計算リソースを完全に掌握するための極限の最適化手法を伝授する。

—

1. 物理的なコスト:なぜ「画面更新」と「再計算」がボトルネックになるのか

MS Projectにおいて、`Application.ScreenUpdating` は単なる描画のフラグではない。これは、COMインターフェースを介した「GUIプロセスとの同期」を制御するゲートだ。これをONにしたままの状態では、各Taskオブジェクトのプロパティ変更のたびに、UIスレッドがロックされ、再描画のキューが溜まる。

同様に、`Calculation` を自動に設定したままでは、1つのタスクを書き換えるたびにクリティカルパスの再計算が走り、CPUのサイクルをドブに捨てることになる。

これを制御するのは、単なる「作法」ではなく「生存戦略」だ。

—

2. 【核心】計算リソースを掌握する最適化パターン

以下のコードは、高負荷なタスク操作を行う際の「定石」である。重要なのは、例外処理(Error Handling)を確実に配置し、強制終了時にも確実にシステム設定を復元させることだ。これを行わないコードは、バグの温床となる。

Public Sub OptimizeTaskOperations()
Dim app As MSProject.Application
Set app = Application

‘ 現行の計算モードと更新設定を退避
Dim origCalc As PjCalculation
Dim origScreen As Boolean

origCalc = app.Calculation
origScreen = app.ScreenUpdating

‘ パフォーマンス最適化の開始
On Error GoTo Cleanup
app.ScreenUpdating = False
app.Calculation = pjManual ‘ 手動計算モードへ強制遷移

‘ — ここに重厚なタスク処理を記述 —
Call ProcessHeavyTasks(app.ActiveProject)
‘ ———————————-

Cleanup:
‘ 異常終了時も必ず設定を戻す(重要:ここを疎かにするとシステムが半壊する)
app.Calculation = origCalc
app.ScreenUpdating = origScreen

If Err.Number <> 0 Then
MsgBox “処理中に致命的なエラーが発生しました: ” & Err.Description, vbCritical
End If
End Sub

—

3. メモリの深淵:オブジェクトの明示的解放とポインタの意識

VBAはガベージコレクションを搭載しているが、MS ProjectのCOMオブジェクトは巨大だ。特に `Tasks` コレクションや `Resources` コレクションをループ内で安易に生成・保持し続けると、メモリリークの温床となる。

  • オブジェクトは参照のみ保持せよ: `Set tsk = proj.Tasks(i)` と書く際、ループの先頭で必ず `Set tsk = Nothing` を意識するレベルの規律が必要だ。
  • Late Bindingを検討せよ: もし外部ライブラリとの連携がメインであれば、`Object` 型によるレイトバインディングを使い、コンパイル時のオーバーヘッドを削減するのも一つの手だ。ただし、IntelliSenseが効かなくなるため、それ相応の設計スキルが求められる。

—

4. レガシー環境を生き抜くための「隠し味」:Windows APIの活用

さらに突き詰めたいのであれば、`Sleep` APIを用いてシステムにわずかな猶予を与える手法がある。高速化を追求するあまり、CPUを100%専有し、OSのレスポンスを奪ってしまうのはアーキテクトとして三流だ。

If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Private Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If

‘ 大規模なバッチ処理の合間に挟む
‘ DoEventsを使うより遥かに低コストで、OSへのリソース返却が可能
Sleep 10

—

最後に:シニアエンジニアとしての矜持

VBAを「古い言語」と揶揄する輩は、その真のポテンシャルを知らない。MS Projectの深い階層にあるオブジェクトモデルを操作し、計算エンジンを手のひらの上で転がす作業は、極めて高次元な計算資源の管理そのものだ。

コードを記述する際は、常に「この行はCOMインターフェースを何回叩いているか?」を自問自答せよ。無駄な呼び出しを排し、システムに余計な負荷をかけない設計こそが、大規模案件を完遂させる真のシニアエンジニアの流儀である。

次回の記事では、`Project_BeforeTaskChange` イベントをフックして、更新対象を最小限に絞り込む「差分更新アルゴリズム」について深掘りするとしよう。準備はいいか。

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