こんにちは!PowerPoint VBAの世界へようこそ。
マクロの記録ボタンを押して「動いたはいいけれど、中身が全然読めない……」と頭を抱えていませんか?
大丈夫、安心してください。今日ここでお話しするオブジェクトモデルの基本と、実務で即戦力になる「プレゼン比較ツール」の作り方をマスターすれば、あなたのPowerPoint自動化スキルは間違いなく一段上のステージに到達します。
今回は、先輩エンジニアである私と一緒に、「2つのプレゼンテーションを比較して差分を暴く簡易監査ツール」を作ってみましょう。ここをクリアすれば、PowerPoint VBAの基本はバッチリですよ!
—
1. なぜ「プレゼン比較」なのか?(オブジェクトモデルの核心)
実務では、「本番用のマスター版」と「クライアント提出用の編集版」など、似たようなファイルを並行して扱うことがよくあります。
「あれ? どっちのファイルが最新だっけ?」「スライドの枚数が違う気がする……」そんな時、人間の目だけでチェックするのは時間の無駄であり、ミスのもとです。
PowerPoint VBAには、これを一瞬で解決する「オブジェクト階層」という強力な仕組みがあります。
PowerPointのピラミッド構造を理解しよう
PowerPointのVBAを操る上で、頭に入れておくべき階層構造(オブジェクトモデル)は以下の通りです。
1. `Application`(アプリ全体):PowerPointそのもの
2. `Presentation`(ファイル):開いている個別のファイル
3. `Slide`(スライド):ファイルの中にある1枚1枚のキャンバス
今回は、2つの `Presentation` オブジェクトを同時にメモリ上にロードし、中身を比較するという、オブジェクト指向の本質に迫るコードを書きます。
—
2. 準備:比較する2つのファイルを指定する
まずは、PC内にある「マスター版」と「編集版」のファイルをVBAから読み込みます。
ここで陥りがちなエラーが「ファイルパスの指定ミス」や「すでに開いているファイルを再度開こうとしてエラーになる現象」です。
実務で使える堅牢(ロバスト)なコードを見ていきましょう。
—
3. 実装:プレゼン比較監査ツール・コード
以下のコードを、VBAエディタ(`Alt + F11` で起動)の標準モジュールに貼り付けてください。
Option Explicit
‘ =====================================================================
‘ 汎用監査ツール:2つのプレゼンテーションの差異を検出する
‘ =====================================================================
Sub AuditPresentationDiff()
Dim pathMaster As String
Dim pathEdit As String
Dim prasMaster As Presentation
Dim prasEdit As Presentation
‘ 【重要】ご自身の環境に合わせてファイルパスを書き換えてください
pathMaster = “C:\Test\Master_Presentation.pptx”
pathEdit = “C:\Test\Edit_Presentation.pptx”
‘ エラーハンドリングの開始(ファイルが見つからない事故を防ぐ)
On Error GoTo ErrorHandler
‘ 1. 2つのプレゼンテーションをバックグラウンド(非表示)で開く
‘ WithWindow:=False にすることで、画面描画のちらつきと無駄なリソース消費を防ぎます
Set prasMaster = Application.Presentations.Open(FileName:=pathMaster, WithWindow:=msoFalse)
Set prasEdit = Application.Presentations.Open(FileName:=pathEdit, WithWindow:=msoFalse)
‘ 2. イミディエイトウィンドウにヘッダーを出力
Debug.Print “====================================================”
Debug.Print ” プレゼンテーション監査レポート ”
Debug.Print “====================================================”
Debug.Print “■ マスター版: ” & prasMaster.Name
Debug.Print “■ 編集版 : ” & prasEdit.Name
Debug.Print “—————————————————-”
‘ 3. 最終更新日時の比較
Call CompareFileProperties(prasMaster, prasEdit)
‘ 4. 総スライド数の比較
Call CompareSlideCounts(prasMaster, prasEdit)
‘ 5. スライド構成(タイトル・レイアウト)の突合
Call CompareSlideDetails(prasMaster, prasEdit)
‘ 6. クリーンアップ(メモリの解放)
prasMaster.Close
prasEdit.Close
Debug.Print “====================================================”
Debug.Print ” 監査が正常に完了しました。”
Debug.Print “====================================================”
On Error GoTo 0
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “監査ツール異常終了”
‘ 異常終了時もオブジェクトが残っていれば閉じる配慮を忘れない
On Error Resume Next
If Not prasMaster Is Nothing Then prasMaster.Close
If Not prasEdit Is Nothing Then prasEdit.Close
End Sub
‘ =====================================================================
‘ サブ処理1:ファイルプロパティ(最終更新日時など)の比較
‘ =====================================================================
Private Sub CompareFileProperties(pMaster As Presentation, pEdit As Presentation)
Debug.Print “【1. ファイルプロパティ比較】”
‘ BuiltinDocumentProperties を使うと作成日時や更新日時が取得できます
On Error Resume Next
Dim dateMaster As Date, dateEdit As Date
dateMaster = pMaster.BuiltinDocumentProperties(msoPropertyTimeLastSaved)
dateEdit = pEdit.BuiltinDocumentProperties(msoPropertyTimeLastSaved)
On Error GoTo 0
Debug.Print ” – マスター版 最終保存: ” & dateMaster
Debug.Print ” – 編集版 最終保存: ” & dateEdit
If dateMaster > dateEdit Then
Debug.Print ” ⚠️ 警告: マスター版の方が新しく保存されています。”
ElseIf dateEdit > dateMaster Then
Debug.Print ” ℹ️ 情報: 編集版の方が新しく更新されています。”
Else
Debug.Print ” ✔ 一致: 最終保存日時は同一です。”
End If
Debug.Print “”
End Sub
‘ =====================================================================
‘ サブ処理2:総スライド数の比較
‘ =====================================================================
Private Sub CompareSlideCounts(pMaster As Presentation, pEdit As Presentation)
Debug.Print “【2. 総スライド数比較】”
Debug.Print ” – マスター版スライド数: ” & pMaster.Slides.Count
QueryEditCount:
Debug.Print ” – 編集版スライド数 : ” & pEdit.Slides.Count
If pMaster.Slides.Count = pEdit.Slides.Count Then
Debug.Print ” ✔ 一致: スライド枚数は同じです。”
Else
Debug.Print ” ❌ 差異アリ: スライド枚数に ” & Abs(pMaster.Slides.Count – pEdit.Slides.Count) & ” 枚のズレがあります。”
End If
Debug.Print “”
End Sub
‘ =====================================================================
‘ サブ処理3:各スライドのタイトル・構成比較
‘ =====================================================================
Private Sub CompareSlideDetails(pMaster As Presentation, pEdit As Presentation)
Debug.Print “【3. スライド詳細突合(タイトルチェック)】”
Dim maxSlides As Long
If pMaster.Slides.Count > pEdit.Slides.Count Then
maxSlides = pMaster.Slides.Count
Else
maxSlides = pEdit.Slides.Count
End If
Dim i As Long
Dim titleMaster As String, titleEdit As String
For i = 1 To maxSlides
titleMaster = “(マスターにスライドなし)”
titleEdit = “(編集版にスライドなし)”
‘ マスター側のスライドタイトル取得(安全策としてエラー対策)
On Error Resume Next
If i <= pMaster.Slides.Count Then
titleMaster = GetSlideTitle(pMaster.Slides(i))
End If
' 編集側のスライドタイトル取得
If i <= pEdit.Slides.Count Then
titleEdit = GetSlideTitle(pEdit.Slides(i))
End If
On Error GoTo 0
' 比較結果の出力
If titleMaster = titleEdit Then
Debug.Print " [Slide " & i & "] ✔ 一致: " & titleMaster
Else
Debug.Print " [Slide " & i & "] ❌ 不一致 -> マ: ” & titleMaster & ” / 編: ” & titleEdit
End If
Next i
Debug.Print “”
End Sub
‘ =====================================================================
‘ ヘルパー関数:スライドからタイトル文字列を抽出する
‘ =====================================================================
Private Function GetSlideTitle(sld As Slide) As String
Dim shp As Shape
Dim titleText As String
titleText = “(タイトル未設定)”
For Each shp in sld.Shapes
‘ プレースホルダー(タイトル枠)を判定
If shp.Type = msoPlaceholder Then
If shp.PlaceholderFormat.Type = ppPlaceholderTitle Or _
shp.PlaceholderFormat.Type = ppPlaceholderCenterTitle Then
If shp.HasTextFrame Then
If shp.TextFrame.HasText Then
titleText = shp.TextFrame.TextRange.Text
Exit For
End If
End If
End If
End If
Next shp
‘ 改行文字が含まれている場合はスペースに置換してログを綺麗にする
GetSlideTitle = Replace(Replace(titleText, vbCr, ” “), vbLf, ” “)
End Function
—
4. このコードの「プロたる所以」と、初心者が陥りがちな罠
今回のコードには、実務で絶対に知っておくべきテクニックが散りばめられています。いくつかポイントを解説しましょう。
① `WithWindow:=msoFalse` でパフォーマンスを劇的に上げる
ファイルを普通に開くと、PowerPointの画面がパカパカと切り替わり、処理速度がガタ落ちします。`Open` メソッドの引数に `WithWindow:=msoFalse` を指定することで、メモリ上だけでファイルを展開し、描画コストをゼロに抑えることができます。これは大規模なファイルや複数ファイルを一括処理する際の鉄則です。
② エラーハンドリングと「クリーンアップ」の美学
VBAでファイルを操作するとき、最も怖いのは「コードの途中でエラーが起き、ファイルがメモリにロックされたまま残る現象」です。
今回のコードでは `On Error GoTo ErrorHandler` を仕込み、万が一途中でエラーが発生しても、必ず `Close` メソッドが走るように配慮しています。プログラマーとしての優しさがここに宿ります。
③ プレースホルダーの安全な走査
スライドのタイトルを取得する際、単に「1番目のテキストボックス」などを指定すると、レイアウトが違うスライドで意図しない文字列を拾ってエラーや誤検知を起こします。
`shp.PlaceholderFormat.Type` を用いて、しっかりと「タイトルとして定義された枠」をピンポイントで狙い撃ちしている点が、このコードの最もスマートな部分です。
—
5. まとめと次のステップ
今回は、2つのプレゼンテーションを比較して差分をイミディエイトウィンドウに出力する監査ツールを作成しました。
- Application / Presentation / Slide のオブジェクトの繋がり
- 非表示でファイルを開くことによる高速化
- プレースホルダーを識別して安全にテキストを抜き出す技術
これらはすべて、今後のあなたがより高度な自動化ツール(例えば、Excelの表データを元にPowerPointを全自動生成するシステムなど)を開発する際の強力な土台となります。
イミディエイトウィンドウに出力されたレポートを眺めながら、「お、動いた!」という感動をぜひ味わってください。
ここをクリアしたあなたなら、もうマクロの記録者ではありません。立派なPowerPoint自動化エンジニアの仲間入りです。
それでは、次の開発現場でお会いしましょう!
