【PowerPoint VBA】Application.OnTimeの幻想を捨てろ:Windows APIで実現する「ミリ秒精度」のプレゼン計測基盤
PowerPoint VBAにおいて、Excelのような`Application.OnTime`は存在しない。もしあなたが「スライドショーの経過時間を取得したい」と考え、ループ処理で`DoEvents`を連打するようなコードを書いているなら、今すぐそのキーボードから手を離してほしい。
スライドショー実行中にCPUを占有し、プレゼンの滑らかさを損なうような実装は、プロの成果物ではない。本稿では、Windows API(`timeSetEvent`)と`WithEvents`を組み合わせ、システムリソースを食いつぶさずに「ミリ秒単位」で経過時間をトレースする、堅牢なアーキテクチャを伝授する。
—
1. なぜ「タイマー」の設計が重要なのか
PowerPointのイベントモデルは、プレゼンテーションの進行状況(`SlideShowBegin`, `SlideShowNextSlide`)をフックするのには長けているが、「実行中の時間経過」を追跡する能力を持たない。
不正確な計測は、分析データのノイズとなる。特に、複数のスライドを跨いだ平均滞在時間や、特定のスライドでの離脱率を分析する場合、ミリ秒のズレは累積して致命的な誤差を生む。我々が構築すべきは、「イベント駆動」かつ「非同期」で動作する高精度な計測エンジンだ。
—
2. 堅牢な計測エンジンの設計(実装戦略)
今回のアーキテクチャは以下の3階層で構成する。
1. Event Handler (Class Module): `PowerPoint.Application`を監視し、スライドショーの開始・終了をトリガーする。
2. Multimedia Timer (API): Windows OSのマルチメディアタイマーを利用し、バックグラウンドで高精度な割り込み処理を行う。
3. Data Logger: 計測結果を外部ログ(CSVやDB)へセキュアに書き出すためのバッファリング。
—
3. 実装コード:高精度タイマーエンジンの全容
クラスモジュール:`clsSlideTimer`
このクラスは、プレゼンのライフサイクルを監視し、タイマーの制御を行います。
‘ クラス名: clsSlideTimer
Option Explicit
Private WithEvents App As PowerPoint.Application
Private m_TimerID As Long
Private Sub Class_Initialize()
Set App = Application
End Sub
‘ スライドショー開始時にタイマーを起動
Private Sub App_SlideShowBegin(ByVal Wn As SlideShowWindow)
‘ 100ms毎にコールバックする高精度タイマーを起動
m_TimerID = timeSetEvent(100, 10, AddressOf TimerCallback, 0, 1)
End Sub
‘ スライドショー終了時にタイマーを破棄(メモリリーク厳禁)
Private Sub App_SlideShowEnd(ByVal Pres As Presentation)
If m_TimerID <> 0 Then
timeKillEvent m_TimerID
m_TimerID = 0
End If
End Sub
標準モジュール:`modTimerCore`
API宣言とコールバック関数を記述します。ここで最も重要なのは、API関数の呼び出しはVBAのメモリ管理の外側にあるという点です。
Option Explicit
‘ Windows Multimedia API
Public Declare PtrSafe Function timeSetEvent Lib “winmm.dll” _
(ByVal uDelay As Long, ByVal uResolution As Long, _
ByVal lpFunction As LongPtr, ByVal dwUser As LongPtr, _
ByVal dwFlags As Long) As Long
Public Declare PtrSafe Function timeKillEvent Lib “winmm.dll” _
(ByVal uID As Long) As Long
‘ ミリ秒単位のコールバック
Public Sub TimerCallback(ByVal uID As Long, ByVal uMsg As Long, _
ByVal dwUser As LongPtr, ByVal dw1 As LongPtr, _
ByVal dw2 As LongPtr)
‘ ここで経過時間を記録する。
‘ ※注意: この関数内で重い処理を行うとOSがフリーズします。
‘ ログ書き出しは別プロセスかバッファリングキューを介すること。
Debug.Print “Elapsed: ” & Timer 1000 & ” ms”
End Sub
—
4. プロフェッショナルとしての注意点
このコードを実務に投入する際、以下の3点だけは必ず厳守してほしい。
- メモリ管理の徹底: `timeSetEvent`でタイマーを起動させたままスライドショーを終了すると、アプリケーションがクラッシュするか、メモリリークの原因となる。`SlideShowEnd`イベントでの`timeKillEvent`実行は義務である。
- コールバック内の制約: `TimerCallback`の中でオブジェクト操作(`ActivePresentation.Slides(1)…`など)を行ってはいけない。APIから呼び出される関数内でVBAのオブジェクトモデルにアクセスすると、予測不能な例外を引き起こす。データは必ずグローバルな変数や型付き配列に書き出し、記録はメインスレッドで行うこと。
- ログ連携の最適化: プレゼン終了後にCSVへ一括出力する設計を推奨する。都度ファイルI/Oを行うと、ディスクアクセスによる遅延がタイマーの精度を汚染する。
まとめ:エンジニアの誇りとして
「動けばいい」というコードは、誰でも書ける。しかし、OSの仕組みを理解し、計算資源を浪費せずに高精度な計測を行うことこそ、自動化エンジニアの付加価値だ。
この仕組みを導入することで、あなたのプレゼン分析は「感覚」から「科学」へと進化する。次に作成するプレゼンテーションの裏側で、このコードが静かに、そして正確に時を刻んでいる様子を想像してほしい。それこそが、技術力で業務を支配する者の特権である。
