【入門編】【中級者】複数のPPTXファイルを一括で開き、各スライドの「更新日時」を比較して、最新のスライドだけを集約した「最新版マージプレゼンテーション」を自動生成・保存するマクロ – PowerPoint VBA解析バイブル

スポンサーリンク
スポンサーリンク

【極限の自動化】「最新版はどれ?」の地獄から脱出する。複数ファイルから最新スライドを集約する究極のマクロ

「最新版_修正済み_final_v2.pptx」
「最新版_修正済み_final_v3_本当にこれ最後.pptx」

……そんなファイル名がフォルダに並んでいる光景、何度見てきましたか?

複数のメンバーが分担してスライドを作成している現場では、必ずと言っていいほど「どのファイルが最新のパーツを持っているのか」を突き止める作業が発生します。これを手作業で一つずつ開き、更新日時を確認して、新しいスライドをコピーして……なんて作業は、エンジニアの魂が泣きます。

今日は、そんな「バージョン管理の迷宮」を、VBAという名の剣で切り裂く方法を伝授しましょう。
単なる「マクロの記録」を超え、「オブジェクトのライフサイクル」と「データ構造」を制御するプロフェッショナルな設計思想を、あなたのものにしてください。

1. 本日のアーキテクチャ(設計図)

今回のミッションは、「特定のルールに従った複数のPPTXファイルをスキャンし、各スライド(または各構成要素)の最新版だけを抽出して、一つのマスタープレゼンテーションに統合する」ことです。

ここで、初心者の方が陥りがちな誤解を解いておきましょう。
実は、PowerPointのスライド単体には「更新日時」というプロパティは存在しません。スライドの更新日時は、「そのスライドが含まれているファイル全体の更新日時」として管理するのが、プログラム設計における定石です。

解決のための3ステップ・アルゴリズム

1. Scan(スキャン): `FileSystemObject` を使い、フォルダ内の全ファイルを巡回する。
2. Compare(比較): `Dictionary` オブジェクトを「脳」として使い、ファイル名から「どのスライドのパーツか」を識別し、更新日時が最も新しいファイルのパスを記憶する。
3. Merge(統合): 記憶した「最新ファイルのリスト」に基づき、`InsertFromFile` メソッドで一気に新しいプレゼンテーションへ流し込む。

2. 実装:最新版マージ・エンジン

それでは、魂を込めたコードを見ていきましょう。このコードは、コピー&ペーストで動作するように設計していますが、コメントを読み飛ばさないでください。コードの「意味」を理解することこそが、脱初学者の唯一の道です。

Option Explicit

''' <summary>
''' 複数ファイルから最新のパーツを集約し、一つのプレゼンテーションを作成する
''' </summary>
Sub MergeLatestSlidesMaster()
    ' --- 1. 変数定義(アーキテクトの作法) ---
    Dim fso As Object
    Dim folderPath As String
    Dim targetFolder As Object
    Dim fileItem As Object
    Dim dictLatestFiles As Object ' Key: スライドID, Value: 最新ファイルのフルパス
    Dim masterPres As Presentation
    Dim latestFilePaths As Variant
    Dim i As Integer
    Dim fileName As String
    Dim slideID As String
    Dim fileDate As Date
    
    ' --- 2. 環境設定 ---
    ' フォルダ選択ダイアログを表示
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "PPTXファイルが格納されているフォルダを選択してください"
        If .Show = -1 Then
            folderPath = .SelectedItems(1)
        Else
            Exit Sub ' キャンセル時は終了
        End If
    End With

    ' オブジェクトの初期化
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set dictLatestFiles = CreateObject("Scripting.Dictionary")
    Set targetFolder = fso.GetFolder(folderPath)
    
    ' --- 3. スキャン&比較フェーズ ---
    ' フォルダ内のファイルを一つずつチェック
    For Each fileItem In targetFolder.Files
        ' 拡張子が .pptx であることを確認(一時ファイルなどは除外)
        If LCase(fso.GetExtensionName(fileItem.Name)) = "pptx" And Left(fileItem.Name, 2) <> "~$" Then
            
            ' 【重要】ファイル名から「スライドID」を抽出するルールを決める
            ' 例: "Slide01_田中.pptx" -> "Slide01" をIDとする
            ' ここでは、最初の "_" までの文字列をIDとみなすロジックにしています
            fileName = fileItem.Name
            If InStr(fileName, "_") > 0 Then
                slideID = Left(fileName, InStr(fileName, "_") - 1)
            Else
                slideID = fileName ' "_" がない場合はファイル名全体をIDとする
            End If
            
            fileDate = fileItem.DateLastModified
            
            ' Dictionaryを使って、既に登録されているものより新しい日付か判定
            If Not dictLatestFiles.Exists(slideID) Then
                ' 初めて見るIDなら登録
                dictLatestFiles.Add slideID, fileItem.Path
            Else
                ' 既に登録されている場合、更新日時を比較
                Dim existingFilePath As String
                existingFilePath = dictLatestFiles(slideID)
                
                If fileDate > fso.GetFile(existingFilePath).DateLastModified Then
                    ' 今見ているファイルの方が新しければ、上書き更新
                    dictLatestFiles(slideID) = fileItem.Path
                End If
            End If
        End If
    Next fileItem

    ' --- 4. マージフェーズ ---
    If dictLatestFiles.Count = 0 Then
        MsgBox "対象となるPPTXファイルが見つかりませんでした。", vbExclamation
        Exit Sub
    End If

    ' 新規プレゼンテーションを作成
    Set masterPres = Presentations.Add

    ' Dictionaryに格納された「最新パス」を順番に処理
    ' ※注:Dictionaryの順序は追加順。必要に応じてソートロジックを追加してください。
    For Each slideID In dictLatestFiles.Keys
        Dim targetPath As String
        targetPath = dictLatestFiles(slideID)
        
        ' InsertFromFile はコピー&ペーストよりも高速で、書式崩れが少ないプロの技
        ' 引数: ファイルパス, 挿入開始スライド, 挿入終了スライド
        On Error Resume Next
        masterPres.Slides.InsertFromFile targetPath, masterPres.Slides.Count
        If Err.Number <> 0 Then
            Debug.Print "Error inserting: " & targetPath
            Err.Clear
        End If
        On Error GoTo 0
    Next slideID

    ' --- 5. 完了処理 ---
    MsgBox "統合が完了しました!" & vbCrLf & _
           "集約されたパーツ数: " & dictLatestFiles.Count, vbInformation

    ' メモリ解放
    Set fso = Nothing
    Set dictLatestFiles = Nothing
    Set targetFolder = Nothing
End Sub

3. ここが「プロ」の知見。解説と陥りやすい罠

このコードをただ動かすだけでは、あなたはまだ「マクロ使い」です。このコードの裏側にある設計思想を理解すれば、あなたは「エンジニア」になれます。

① なぜ `Dictionary` を使うのか?

初心者の方は、ファイルを一つずつ見て「これは最新かな?次は……」と、フラグ変数(Boolean)をいくつも作って管理しようとしがちです。しかし、それは拡張性のない設計です。
`Dictionary`(連想配列)を使えば、「スライドID(Key)」と「その最新パス(Value)」をセットで管理できます。これにより、データの検索と更新が爆速になり、コードも劇的にシンプルになります。

② `InsertFromFile` vs `Copy & Paste`

「スライドをコピーして貼り付ける」という操作は、マクロの記録ではよく見られます。しかし、これは非常に危険です。
クリップボードを経由するため、実行中にユーザーが他の操作をするとエラーになりますし、メモリ消費も激しい。
一方、`InsertFromFile` は、ファイルから直接スライドオブジェクトを流し込むため、動作が安定し、速度も圧倒的に速いのです。

③ 陥りやすいエラー:ファイル名の命名規則

このマクロの命運は、「ファイル名の命名規則」にかかっています。
上記のコードでは `slideID = Left(fileName, InStr(fileName, “_”) – 1)` としており、`Slide01_Tanaka.pptx` のようにアンダースコアで区切られていることを前提としています。
もし、メンバーが `Slide01Tanaka.pptx` と命名してしまうと、IDが正しく抽出できず、マージに失敗します。
「自動化を成功させるには、人間側のルール(運用)を固めること」。これが、現場を知るアーキテクトの教えです。

4. 次のステップへ

このマクロをマスターしたら、次は以下のようなカスタマイズに挑戦してみてください。

  • ソート機能: `Dictionary` の中身をスライド番号順に並び替えてからマージする。
  • ログ出力: どのファイルが採用され、どのファイルが「古い」として捨てられたのかをテキストファイルに書き出す。
  • エラーハンドリングの強化: ファイルが開けなかった場合に、ユーザーに通知してスキップする処理をより堅牢にする。

ここをクリアすれば、PowerPoint VBAの基本はバッチリですよ。
一歩ずつ、しかし確実に、自動化の深淵へと進んでいきましょう。応援しています!

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