【テクニカル・上級編】【実務中級】Presentation.SlideShowSettingsを操作し、特定の「カスタムスライドショー(NamedSlideShows)」をVBAから動的に作成・実行する自動化 – PowerPoint VBA解析バイブル

スポンサーリンク

【実務中級】Presentation.SlideShowSettingsを操作し、特定の「カスタムスライドショー」をVBAから動的に作成・実行する自動化

PowerPoint VBAの真価は、単なる「図形の自動整列」や「テキストの置換」にあるのではない。
プレゼンテーションという非構造化データを、プログラムの制御下において動的に再構築し、実行時にその文脈を最適化する能力――これこそが、シニアエンジニアがVBAに求める領域だ。

今回は、全百数枚に及ぶ肥大化したマスタープレゼンテーションから、特定の顧客や会議体が必要とするトピックだけを瞬時に抽出し、動的に「カスタムスライドショー(NamedSlideShows)」を構築して即座に全画面上映を開始する自動化アーキテクチャを解説する。

1. オブジェクトモデルの深層:なぜ「NamedSlideShows」なのか

多くの開発者は、スライドの取捨選択が必要な場面になると、不要なスライドを一時的に削除(`Slide.Delete`)したり、スライドの非表示フラグ(`SlideShowTransition.Hidden`)をループで書き換えたりする愚を犯す。

これは極めて低悪質なアプローチである。

  • Undoスタックの肥大化とメモリリーク: 実行時の一括削除・復元は、Presentationのドキュメント構造を破壊し、最悪の場合ファイル破損を招く。
  • 非表示フラグの汚染: 元に戻す処理(ロールバック)で例外が発生した際、プレゼンターのマスターデータが「隠されたスライドだらけ」のゴミ屋敷と化す。

ここで投入すべきが、`Presentation.SlideShowSettings` 配下の `NamedSlideShows` コレクション である。

`NamedSlideShows` は、プレゼンテーションファイル内に「再生リスト(プレイリスト)」をメタデータとして保持する。スライド本体を一切改変せず、インデックスの配列(ポインタの集合)だけで仮想的なスライドショーを定義できる。メモリ消費は無視できるほど小さく、オブジェクトのライフサイクル管理としても圧倒的に安全だ。

2. アーキテクチャ設計:動的プレイリスト生成の要件

実務環境において、カスタムスライドショーの動的生成は以下のステップで流れるように実行されなければならない。

1. 既存の同名カスタムショーのパージ(存在確認と例外回避)
2. メタデータ(設定ファイルやスライド上のタグ)に基づく対象スライドIDの抽出
3. `NamedSlideShows.Add` によるプレイリストの構築
4. `SlideShowSettings` への適用と、実行パラメータ(ウィンドウモード、ループ等)の最適化
5. 上映の非同期実行(または制御の移譲)

これを実装した実務投入可能なプロダクションコードを提示する。

3. 実装コード:動的カスタムスライドショー・エグゼキューター

以下のコードは、アクティブなプレゼンテーションに対し、特定のキーワード(例: 「【財務】」など)をスライドのノートまたはタイトルから正規表現的に検出し、即座にカスタムショーを構築して実行するモジュールである。

Option Explicit

‘ ==============================================================================
‘ módulo名: MdlDynamicSlideShow
‘ 概要: 指定された条件に基づいてNamedSlideShowsを動的に構築し、上映を実行する
‘ ==============================================================================

Public Sub ExecuteTargetedSlideShow(ByVal targetKeyword As String)
Dim targetPres As Presentation
Set targetPres = ActivePresentation

Dim customShowName As String
customShowName = “AutoGenerated_” & Format(Now, “yyyymmdd_hhnnss”)

On Error GoTo ErrorHandler

‘ 1. 対象スライドのインデックス配列を動的に収集
Dim slideIndices() As Long
Dim count As Long
count = 0

Dim sld As Slide
Dim i As Long

For i = 1 to targetPres.Slides.Count
Set sld = targetPres.Slides(i)

‘ 判定ロジック: スライド内のシェイプテキストまたはノートにキーワードが含まれるか
If EvaluateSlideCriteria(sld, targetKeyword) Then
ReDim Preserve slideIndices(count)
slideIndices(count) = sld.SlideIndex
count = count + 1
End If
Next i

‘ 該当スライドがゼロ件の場合は処理を中断
If count = 0 Then
MsgBox “指定された条件に一致するスライドが見つかりませんでした: ” & targetKeyword, vbExclamation, “動的ショー生成エラー”
Exit Sub
End If

‘ 2. 既存の同名カスタムショーがあれば念のため削除(通常はタイムスタンプ付与で衝突しない)
Call PurgeNamedSlideShow(targetPres, customShowName)

‘ 3. NamedSlideShowsコレクションへの追加
‘ Variant型の配列に変換して渡す必要がある(COMの仕様上の要件)
Dim varIndices() As Variant
ReDim varIndices(count – 1)
For i = 0 To count – 1
varIndices(i) = slideIndices(i)
Next i

targetPres.SlideShowSettings.NamedSlideShows.Add customShowName, varIndices

‘ 4. SlideShowSettingsの設定と実行
With targetPres.SlideShowSettings
.ShowType = ppShowTypeSpeaker // 発表者として実行(ウィンドウ or 全画面)
.LoopUntilStopped = False
.AdvanceMode = ppSlideAdvanceUseSlideTimings

‘ 作成したカスタムショーを指定
.RangeType = ppShowNamedSlideShow
.SlideShowName = customShowName

‘ 5. スライドショーの実行
Dim ssw As SlideShowWindow
Set ssw = .Run
End With

‘ オブジェクトの明示的解放(VBAのガベージコレクション挙動を補完)
Set ssw = Nothing
Set targetPres = Nothing
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
Set ssw = Nothing
Set targetPres = Nothing
End Sub

‘ — ヘルパー関数: スライドが抽出条件を満たすか判定 —
Private Function EvaluateSlideCriteria(ByVal sld As Slide, ByVal keyword As String) As Boolean
EvaluateSlideCriteria = False

Dim shp As Shape
For Each shp in sld.Shapes
If shp.HasTextFrame Then
If shp.TextFrame.HasText Then
If InStr(1, shp.TextFrame.TextRange.Text, keyword, vbTextCompare) > 0 Then
EvaluateSlideCriteria = True
Exit Function
End If
End If
End If
Next shp

‘ 必要に応じてノートページのテキストも走査対象に含める
If sld.HasNotesPage Then
Dim notesShp As Shape
For Each notesShp In sld.NotesPage.Shapes
If notesShp.HasTextFrame Then
If notesShp.TextFrame.HasText Then
If InStr(1, notesShp.TextFrame.TextRange.Text, keyword, vbTextCompare) > 0 Then
EvaluateSlideCriteria = True
Exit Function
End If
End If
End If
Next notesShp
End If
End Function

‘ — ヘルパー関数: 既存のカスタムショーのクリーンアップ —
Private Sub PurgeNamedSlideShow(ByVal pres As Presentation, ByVal showName As String)
Dim nss As NamedSlideShow
On Error Resume Next
Set nss = pres.SlideShowSettings.NamedSlideShows(showName)
If Not nss Is Nothing Then
nss.Delete
End If
On Error GoTo 0
End Sub

4. チーフアーキテクトが指摘する「実務上の罠」と最適化知見

上記のコードは美しく動作するが、真にエンタープライズなシステムを構築する上では、さらに以下のレイヤーを考慮しなければならない。

① COM相互運用性とVariant配列の型制約

`NamedSlideShows.Add` メソッドの第2引数には、スライドインデックスの配列を指定する。ここで `Long()` 型のまま渡すと、COMのマーシャリングで型ミスマッチ(エラー 13: 型が一致しません)が発生することがある。
コード内で行っている通り、必ず `Variant` 型の配列にキャストし直してから渡す のが、PowerPoint VBAにおける堅牢なコーディング作法である。

② メモリリークとリファレンスカウントの管理

PowerPointの `SlideShowSettings.Run` は、新しい `SlideShowWindow` オブジェクトを返すが、このウィンドウインスタンスや背後にあるスライドショーのプロセスは、Officeアプリケーションのライフサイクルから独立してメモリ上に残存しやすい。
不要になった `NamedSlideShows` のエントリは、プレゼンテーションを閉じる際に自動破棄されるものの、セッション中に動的生成を何千回も繰り返すようなバッチ処理(例:サーバーサイドでのPDF/動画一括変換の事前処理など)では、メモリ肥大化の原因となる。
定期的な `.NamedSlideShows` のクリア、あるいは `ActivePresentation.Saved = True` の適切なハンドリングを忘れてはならない。

③ レガシー環境・マルチスレッド連携の限界

PowerPointのオブジェクトモデルはシングルスレッドアパートメント(STA)で動作する。外部のC#アプリケーションやWebAPI(ASP.NET等)からこのVBAロジック、あるいはCOM経由でPowerPointを操作する場合、UIスレッドの競合やモーダルダイアログのブロックに直面する。
もしシステム間連携で同様の動的スライドショー制御を行いたい場合は、VBAに閉じこもらず、`.NET (C#) + OpenXML SDK` を用いてプレゼンテーションのXML(`presentation.xml` や `sldSz` など)を直接書き換えるアプローチこそが、現代の最高峰のアーキテクチャであることを最後に付言しておく。

結び

VBAはレガシーな言語とやゆされがちだが、PowerPointの描画エンジンとダイレクトに対話し、プレゼンテーションの構造を瞬時にハックする力においては、いまだに他の追随を許さない圧倒的な即効性を持つ。
オブジェクトモデルの裏側にある「メモリ構造」と「COMの制約」を理解した者だけが、真に安定した自動化の果実を手にすることができる。コードの細部にまで魂を宿せ。

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