【実務・中級編】【初心者】上書き保存時に同階層へ「.bak」形式のバックアップファイルを自動生成する簡易世代管理マクロ – PowerPoint VBA解析バイブル

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

「保存」を信じるな。データ整合性を守るための「イベント・シンク」設計論

業務自動化の世界において、最も恐ろしいのは「コードが動かないこと」ではない。「コードは動いているが、データが壊れていること」、あるいは「ユーザーの意図しない上書きが発生すること」だ。

多くの開発者が、PowerPoint VBAで「保存時に何かをする」という機能を実装しようとして、壁にぶち当たる。なぜなら、Excelの`Workbook_BeforeSave`のような、直感的で便利なイベントがPowerPointの標準モジュールには存在しないからだ。

今回は、単なる「バックアップ作成マクロ」の提供ではない。PowerPointのオブジェクトモデルを深く理解し、アプリケーション全体を監視する「イベント・シンク(Event Sink)」という設計思想に基づいた、堅牢な世代管理システムの構築術を伝授する。

1. なぜ「標準モジュール」にコードを書くだけでは不十分なのか

初心者はこう考える。「保存ボタンを押したときに実行されるマクロを、どこかに仕込めばいいのだろう?」と。

しかし、PowerPoint VBAにおいて、標準モジュールに書かれたプロシージャは、ユーザーが「保存」をクリックした瞬間に自動で呼び出されることはない。これを実現するには、Applicationオブジェクトのイベントを監視する「クラスモジュール」を定義し、それをメモリ上に常駐させる必要がある。

この「オブジェクトのライフサイクル」を制御する概念こそが、ツールを「単なる便利機能」から「プロダクト」へと昇華させる境界線だ。

2. 実装アーキテクチャ:イベント・シンク・モデル

我々が構築するのは、以下の二層構造だ。

1. Class Module (`clsAppEvent`): PowerPointアプリケーションの挙動を監視する「耳」の役割。
2. Standard Module (`modMain`): アプリケーションの監視を開始し、バックアップの具体的なロジックを実行する「脳」の役割。

ステップ1:クラスモジュールの作成

まず、挿入メニューから「クラスモジュール」を追加し、オブジェクト名を `clsAppEvent` に変更せよ。ここに、アプリケーションのイベントをキャッチする定義を記述する。

' クラスモジュール: clsAppEvent
Option Explicit

' PowerPointアプリケーションのイベントを捕捉するための宣言
' WithEventsキーワードにより、Applicationオブジェクトのイベントを監視可能にする
Private WithEvents App As Application

' 初期化メソッド:監視対象となるApplicationオブジェクトを注入する
Public Sub Init(ByVal targetApp As Application)
    Set App = targetApp
End Sub

' プレゼンテーションが保存される直前に発生するイベント
' 引数 Pres: 保存されようとしているプレゼンテーションオブジェクト
Private Sub App_PresentationBeforeSave(ByVal Pres As Presentation)
    ' バックアップ処理を標準モジュールのプロシージャに委譲する
    ' 責務を分離(Separation of Concerns)し、保守性を高める設計
    Call CreateBackup(Pres)
End Sub

ステップ2:標準モジュールの作成

次に、通常の「標準モジュール」を作成し、バックアップの実行ロジックと、監視システムの起動ルーチンを記述する。ここでは、ファイル操作の堅牢性を担保するために `FileSystemObject` を活用する。

※ 事前準備:ツール > 参照設定 > “Microsoft Scripting Runtime” にチェックを入れてください。

' 標準モジュール: modMain
Option Explicit

' クラスインスタンスをモジュールレベルで保持
' これをPrivate変数として保持しない限り、マクロ終了と共に監視役(イベント・シンク)は消滅する
Private AppWatcher As clsAppEvent

''' <summary>
''' 監視システムの起動
''' </summary>
Public Sub StartBackupWatcher()
    ' すでに起動している場合は一度解放する(二重起動防止)
    If Not AppWatcher Is Nothing Then
        Set AppWatcher = Nothing
    End If
    
    ' クラスのインスタンス化
    Set AppWatcher = New clsAppEvent
    ' Applicationオブジェクトを注入
    AppWatcher.Init Application
    
    MsgBox "バックアップ監視システムが起動しました。" & vbCrLf & _
           "保存時に自動的に .bak ファイルが生成されます。", vbInformation
End Sub

''' <summary>
''' バックアップ生成のコアロジック
''' </summary>
''' <param name="Pres">対象のプレゼンテーション</param>
Public Sub CreateBackup(ByVal Pres As Presentation)
    On Error GoTo ErrorHandler
    
    Dim fso As New FileSystemObject
    Dim currentPath As String
    Dim folderPath As String
    Dim fileName As String
    Dim fileExt As String
    Dim baseName As String
    Dim timestamp As String
    Dim backupPath As String
    
    ' 1. ファイルが一度も保存されていない(パスが存在しない)場合はスキップ
    currentPath = Pres.FullName
    If currentPath = "" Or Not fso.FileExists(currentPath) Then
        ' 未保存の新規ファイルはバックアップの対象外とする(論理的整合性)
        Exit Sub
    End If
    
    ' 2. パス情報の分解
    folderPath = fso.GetParentFolderName(currentPath)
    baseName = fso.GetBaseName(currentPath)
    fileExt = fso.GetExtensionName(currentPath)
    
    ' 3. タイムスタンプの生成 (VBAのMinuteは"nn"であることに注意)
    ' yyyymmdd_hhnnss 形式を採用し、ソート順を保証する
    timestamp = Format(Now, "yyyymmdd_hhnnss")
    
    ' 4. バックアップファイル名の構築 (.bak 形式)
    backupPath = folderPath & "\" & baseName & "_" & timestamp & ".bak"
    
    ' 5. ファイルのコピー実行
    ' FileCopyは対象が開かれているとエラーになるため、FSOを使用して堅牢にコピー
    fso.CopyFile currentPath, backupPath, True
    
    ' デバッグ・ログ出力(運用フェーズでは不要に応じて削除)
    Debug.Print "Backup Created: " & backupPath

ExitSub:
    Exit Sub

ErrorHandler:
    ' 実行時エラーが発生しても、メインの保存処理を阻害してはいけない
    ' ログへの記録に留めるのがプロフェッショナルの設計
    Debug.Print "Backup Error: " & Err.Description
    Resume ExitSub
End Sub

''' <summary>
''' 監視システムの停止
''' </summary>
Public Sub StopBackupWatcher()
    Set AppWatcher = Nothing
    MsgBox "監視システムを停止しました。", vbExclamation
End Sub

3. プロフェッショナルとしての設計ポイント

このコードが、単なる「コピペ用コード」と一線を画している理由は、以下の3点にある。

① 責務の分離 (Separation of Concerns)

`clsAppEvent` は「いつ実行するか」を知っているが、「どうバックアップするか」は知らない。一方で `CreateBackup` は「どうバックアップするか」を知っているが、「いつ実行されるか」は関知しない。この分離により、将来的に「バックアップ先をクラウドストレージに変更したい」となった際、修正すべき箇所が明確になる。

② タイムスタンプの厳密な管理

`Format(Now, “yyyymmdd_hhnnss”)` を使用している。ここで、多くの初心者が犯すミスは `mm`(月)と `nn`(分)の混同だ。`mm` を使うと、分が変わるたびに「月」が書き換わるという致命的なバグを生む。また、`yyyymmdd` 形式は、ファイルエクスプローラーでの名前順ソート時に、時系列順に綺麗に並ぶという実務上のメリットがある。

③ エラーハンドリングの哲学

`CreateBackup` 内の `On Error GoTo ErrorHandler` は極めて重要だ。
もしバックアップ処理(ファイルコピー)が、権限不足やディスクフルによって失敗したとき、そのエラーが呼び出し元(PowerPoint自体の保存処理)に波及してはいけない。「バックアップに失敗したからといって、ユーザーのメイン作業(保存)を止めてはならない」。これが、業務ツールにおける鉄則だ。

4. 運用へのアドバイス

このマクロを実務で運用する場合、`modMain` の `StartBackupWatcher` を `Auto_Open` プロシージャ(またはアドインとして登録)に配置することで、PowerPointの起動と同時に監視を開始させることができる。

しかし、忘れてはならない。「自動化は、人間が管理しきれない複雑さを導入する行為でもある」。
バックアップファイルが無限に増殖してディスクを圧迫しないよう、定期的に古い `.bak` ファイルを削除するクリーンアップ・ロジックを検討することも、アーキテクトとしての次のステップだ。

設計に魂を込めろ。コードに責任を持て。それが、真のエンジニアへの道だ。

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