【テクニカル・上級編】【非同期処理の監視】”Presentation.CreateVideo”による動画生成と、”CreateVideoStatus”を用いたエクスポート完了待ちポーリング実装 – PowerPoint VBA解析バイブル

スポンサーリンク

PowerPoint VBAを掌握する極限の知見:`CreateVideo`の非同期地獄を制圧するポーリング実装の全貌

PowerPointのプレゼンテーションをMP4などの動画ファイルへエクスポートする `Presentation.CreateVideo` メソッド。
この機能は一見すると非常に便利だが、実務で大規模な自動化パイプラインやシステム間連携に組み込んだ瞬間、多くの開発者が絶望の淵に立たされる。

なぜか? このメソッドは完全に「非同期(Async)」で動作するにもかかわらず、完了を検知するためのイベントやコールバック機構を一切提供していないからだ。

VBAの実行スレッドは動画生成の裏で何食わぬ顔で次の行へ進み、場合によってはPowerPointのプロセスそのものが不安定化する。野良の無限ループでCPUコアを100%に張り付かせるような愚行は、プロのアーキテクトとして絶対に避けるべきだ。

今回は、Windows環境におけるAPIの特性、COMオブジェクトのライフサイクル、そして堅牢なポーリング設計の極限を網羅した、実戦投入可能なソリューションを提示する。

1. `CreateVideo` の挙動と非同期の罠

`CreateVideo` を実行すると、PowerPointの内部エンジンはバックグラウンドスレッドでレンダリングを開始する。この時、親オブジェクトである `Presentation` には `CreateVideoStatus` プロパティがバインドされ、現在のステータスが数値(定数)として返されるようになる。

ステータス遷移のライフサイクルは以下の4つに分類される。

  • `ppMediaTaskStatusNone` (0): タスク未実行
  • `ppMediaTaskStatusInProgress` (1): レンダリング実行中
  • `ppMediaTaskStatusQueued` (2): キュー待機中
  • `ppMediaTaskStatusFailed` (3): 失敗
  • `ppMediaTaskStatusDone` (4): 完了

私たちが監視すべきは、このステータスが `ppMediaTaskStatusInProgress` または `ppMediaTaskStatusQueued` から `ppMediaTaskStatusDone`(または `Failed`)に変化する瞬間だ。

しかし、VBAで単純な `Do While` ループを回すと、UIスレッドが完全にブロックされ、PowerPoint自体が「応答なし」の状態に陥る。 これを防ぎつつ、CPUリソースを適正に管理するポーリング機構が求められる。

2. 実装:堅牢な非同期監視ポーリングエンジン

以下に、実務のバッチ処理やRPA連携の基盤として耐えうる、極限まで最適化されたVBAコードを示す。
ビジーステートの制御、タイムアウト機構、そしてAPIの過負荷を防ぐための `DoEvents` とスリープ制御を完備している。

Option Explicit

‘ Windows API: スレッドを指定時間スリープさせることでCPU使用率のスパイクを防ぐ
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

‘ 定数定義(PowerPointの型ライブラリに依存しない安全策)
Private Const PP_MEDIA_STATUS_NONE As Long = 0
Private Const PP_MEDIA_STATUS_IN_PROGRESS As Long = 1
Private Const PP_MEDIA_STATUS_QUEUED As Long = 2
Private Const PP_MEDIA_STATUS_FAILED As Long = 3
Private Const PP_MEDIA_STATUS_DONE As Long = 4

Public Sub ExecuteVideoExportPipeline()
Dim targetPres As Presentation
Dim outputPath As String
Dim isSuccess As Boolean

‘ 参照パスの設定(環境に合わせて変更)
outputPath = “C:\AutomatedOutputs\Presentation_Master.mp4”
Set targetPres = ActivePresentation

On Error GoTo ErrorHandler

‘ 1. 既存ファイルのクリーンアップ(同名ファイルが存在する場合のロック回避)
Call SafeDeleteFile(outputPath)

‘ 2. 動画生成の非同期リクエストを発行
‘ 引数: FileName, UseTimingsAndNarrations, Resolution, FramesPerSecond, Quality
Debug.Print “[” & Now & “] 動画生成タスクを非同期で開始します…”

targetPres.CreateVideo FileName:=outputPath, _
UseTimingsAndNarrations:=True, _
Resolution:=1080, _
FramesPerSecond:=30, _
Quality:=85

‘ 3. 堅牢なポーリングループの実行(タイムアウト付き: 最大30分)
isSuccess = PollVideoCreationStatus(targetPres, 1800)

If isSuccess Then
MsgBox “動画生成が正常に完了しました。” & vbCrLf & outputPath, vbInformation, “処理成功”
Else
Err.Raise vbObjectError + 1000, “VideoExport”, “動画生成がタイムアウトまたは失敗しました。”
End If

CleanUp:
‘ オブジェクトの明示的解放(メモリリーク防止の鉄則)
Set targetPres = ActiveSnapShot(targetPres) ‘ 便宜上のプレースホルダー
Set targetPres = Nothing
Exit Sub

ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
Resume CleanUp
End Sub

”’

”’ 動画生成の完了を監視するポーリング関数
”’

”’ 対象のPresentationオブジェクト ”’ タイムアウトまでの秒数 ”’ Boolean 成功時はTrue
Private Function PollVideoCreationStatus(ByRef pres As Presentation, ByVal timeoutSeconds As Long) As Boolean
Dim startTime As Double
Dim currentStatus As Long
Dim checkIntervalMs As Long

startTime = Timer
checkIntervalMs = 1000 ‘ 1秒ごとにステータスを確認

Do
‘ タイムアウト判定(日跨ぎを考慮しない簡易実装。実運用では Timer のラップに注意)
If (Timer – startTime) > timeoutSeconds Then
PollVideoCreationStatus = False
Exit Function
End If

‘ ステータス取得
currentStatus = pres.CreateVideoStatus

Select Case currentStatus
Case PP_MEDIA_STATUS_DONE
PollVideoCreationStatus = True
Exit Function

Case PP_MEDIA_STATUS_FAILED
PollVideoCreationStatus = False
Exit Function

Case PP_MEDIA_STATUS_IN_PROGRESS, PP_MEDIA_STATUS_QUEUED
‘ まだ処理中のため、UIフリーズを防ぎつつ待機
DoEvents
Sleep checkIntervalMs

Case PP_MEDIA_STATUS_NONE
‘ レンダリング開始直後のタイムラグを考慮し、少し待つ
DoEvents
Sleep 500

Case Else
‘ 未知のステータスコードに対する安全策
DoEvents
Sleep checkIntervalMs
End Select

Loop
End Function

”’

”’ 既存ファイルの安全な削除処理
”’

Private Sub SafeDeleteFile(ByVal filePath As String)
On Error Resume Next
If Dir(filePath) <> “” Then
Kill filePath
End If
On Error GoTo 0
End Sub

3. チーフアーキテクトが解説する「死角のない設計」のポイント

上記のコードは、単に動くだけのスクリプトではない。エンタープライズ環境やサーバサイドでの無人実行(RPA・タスクスケジューラ)を想定し、以下のアーキテクチャ上の工夫が組み込まれている。

① `Sleep` と `DoEvents` のハイブリッド制御

単なる `DoEvents` のみのループは、CPUコアのクロックを激しく消費し、ノートPCなどの環境ではファンの回転数が跳ね上がる。かといって `Sleep` だけを呼び出すと、PowerPointのUIスレッドが完全に凍結し、OSから「応答なし」と判定されてプロセスが強制終了されるリスクがある。
「`DoEvents` でイベントキューを処理しつつ、`Sleep 1000` でスレッドを1秒間休眠させる」 この組み合わせこそが、リソース消費を最小限に抑える唯一の解である。

② COMオブジェクトのライフサイクル管理

PowerPoint VBAにおいて、オブジェクト変数の解放漏れは、目に見えないメモリリークやバックグラウンドプロセスのゾンビ化を引き起こす。特に外部システム(C#やPython、あるいはWSH)からPowerPointインスタンスを操る場合、`.CreateVideo` のような重い処理の後は、確実に参照を切断し、ガベージコレクションの契機を作るべきだ。

③ 失敗ステータスと例外ハンドリングの分離

動画生成エンジンは、スライド内に破損したメディアオブジェクトが含まれている場合や、ディスク容量が枯渇している場合に `ppMediaTaskStatusFailed` を返す。この時、VBA側で何も検知せずに次の処理へ進むと、破損した0バイトのファイルが後続システムに渡り、大惨事を引き起こす。
返り値を厳密に `Boolean` で判定し、異常時は即座に `Err.Raise` でパイプライン全体を停止させる設計が不可欠である。

4. まとめ:レガシーの殻を破る自動化の極意

PowerPoint VBAは、しばしば「おもちゃの言語」と揶揄される。しかし、オブジェクトモデルの裏側にあるWin32 APIの挙動、スレッドのライフサイクル、そしてCOMの制約を完全に理解したエンジニアが書いたコードは、極めて堅牢なエンタープライズシステムの一部として機能する。

`CreateVideo` の非同期監視はその試金石だ。イベント駆動ではないレガシーな世界であっても、緻密なポーリング設計とリソース管理によって、モダンなアプリケーションに匹敵する安定性を手に入れることは十分に可能である。

現場のインフラを守るエンジニア諸賢の武器として、この知見が役立つことを確信している。

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