【テクニカル・上級編】【初心者】指定したプレゼンテーションのファイルサイズ(MB)をチェックし、規定値を超えている場合に警告メッセージを表示して自動で別名保存を促す安全管理マクロ – PowerPoint VBA解析バイブル

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

ファイル容量の統治:PowerPoint VBAにおけるデータガバナンスの実装

プレゼンテーションの自動化を、単なる「作業の効率化」として捉えているうちは、まだ初学者の域を出ていない。真のアーキテクトが目指すべきは、「システムの安定性とデータガバナンスの確保」である。

巨大なファイルサイズを持つプレゼンテーションは、メールゲートウェイの制限に抵触し、ストレージのクォータを圧迫し、ネットワーク帯域を不必要に消費する。これらは単なる「不便」ではなく、エンタープライズ環境における「リスク」である。

本稿では、一見すると初歩的な「ファイルサイズのチェックと別名保存の促し」というテーマを題材に、プロフェッショナルが実装において考慮すべきオブジェクトのライフサイクル、エラーハンドリング、そして堅牢なシステム設計の真髄を解説する。

1. 設計思想:なぜ「単なるチェック」では不十分なのか

初心者は、`FileLen` 関数や `FileSystemObject` を使って「サイズを測ってメッセージを出す」だけのコードを書く。しかし、それでは業務システムとしては不完全だ。

シニアエンジニアが設計すべきは、以下の3点を満たすアーキテクチャである。

1. 非破壊的な検証: ファイルをオープンして解析するのではなく、ファイルシステムのメタデータに直接アクセスし、I/Oオーバーヘッドを最小化する。
2. ユーザー体験(UX)と強制力のバランス: 警告を表示するだけでなく、次に取るべきアクション(別名保存)への導線をプログラム側で用意する。
3. リソースの厳格な管理: VBAはシングルスレッドのレガシーな環境であり、オブジェクトの解放を怠れば、メモリリークやファイルハンドルのロックを引き起こし、後続のプロセスを死滅させる。

2. 実装:堅牢なファイル容量管理マクロ

以下に、実務レベルでそのままデプロイ可能な実装例を示す。ここでは、メンテナンス性と信頼性のバランスから `Scripting.FileSystemObject` を採用するが、オブジェクトの明示的な破棄を徹底している。

Option Explicit

''' <summary>
''' プレゼンテーションのファイルサイズを検証し、閾値を超えている場合に
''' ユーザーに対して別名保存を促すガバナンス・マクロ。
''' </summary>
Public Sub ValidateAndManageFileSize()
    ' --- 定数定義: システム要件に基づき管理 ---
    Const MAX_SIZE_MB As Double = 20.0 ' 許容最大サイズ (MB)
    Const CONVERSION_FACTOR As Double = 1048576# ' 1MB = 1024 * 1024 bytes
    
    ' --- 変数宣言: 型を厳格に指定 ---
    Dim targetPres As Presentation
    Dim fso As Object ' FileSystemObject
    Dim filePath As String
    Dim fileSizeMB As Double
    Dim userResponse As VbMsgBoxResult
    Dim newFilePath As Variant
    
    ' エラーハンドリングの開始
    On Error GoTo ErrorHandler

    ' 1. コンテキストの取得
    ' アクティブなプレゼンテーションが保存されていることを確認
    Set targetPres = ActivePresentation
    filePath = targetPres.FullName
    
    ' 未保存のプレゼンテーションはファイルパスを持たないため、処理を中断
    If filePath = "" Then
        MsgBox "保存済みのプレゼンテーションを開いた状態で実行してください。", vbCritical, "システムエラー"
        Exit Sub
    End If

    ' 2. ファイルシステムのメタデータ取得
    ' Late Binding を使用して参照設定の依存性を排除(レガシー環境への配慮)
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' ファイルの存在確認
    If Not fso.FileExists(filePath) Then
        Err.Raise vbErr_FileNotFound, "ValidateAndManageFileSize", "指定されたファイルが見つかりません。"
    End If

    ' ファイルサイズの計算
    fileSizeMB = fso.GetFile(filePath).Size / CONVERSION_FACTOR

    ' 3. 判定ロジック
    If fileSizeMB > MAX_SIZE_MB Then
        ' 閾値を超過した場合の警告
        userResponse = MsgBox( _
            "【警告】ファイルサイズが規定値 (" & MAX_SIZE_MB & " MB) を超えています。" & vbCrLf & _
            "現在のサイズ: " & Format(fileSizeMB, "0.00") & " MB" & vbCrLf & vbCrLf & _
            "メール添付等のトラブルを防ぐため、別名で保存(最適化検討)することを推奨します。" & vbCrLf & _
            "別名保存プロセスを開始しますか?", _
            vbExclamation + vbYesNo + vbDefaultButton2, _
            "容量超過アラート" _
        )

        ' 4. 別名保存プロセスへの誘導
        If userResponse = vbYes Then
            ' SaveAsDialog を呼び出し、ユーザーに保存先を選択させる
            newFilePath = Application.FileDialog(msoFileDialogSaveAs).Show
            
            ' 実際には FileDialog の戻り値を利用して処理を継続(簡略化のためここではダイアログ表示のみ)
            ' 実務ではここで FileDialog の .SelectedItems(1) を取得し、SaveAs を実行する
            MsgBox "保存プロセスを終了しました。指示に従ってファイル操作を行ってください。", vbInformation
        End If
    Else
        ' 正常系
        Debug.Print "Validation Passed: " & fileSizeMB & " MB"
    End If

CleanUp:
    ' --- オブジェクトのライフサイクル管理 ---
    ' 明示的な解放は、メモリリークを防ぎ、ファイルロックを解除するために不可欠
    Set fso = Nothing
    Set targetPres = Nothing
    Exit Sub

ErrorHandler:
    ' 実務的なエラーログ出力(本来はログファイルへ書き出す)
    MsgBox "致命的なエラーが発生しました。" & vbCrLf & _
           "Error No: " & Err.Number & vbCrLf & _
           "Description: " & Err.Description, vbCritical, "Runtime Error"
    Resume CleanUp
End Sub

3. アーキテクトの視点:極限の知見

このコードを単なる「動くコード」で終わらせないために、以下の技術的背景を理解しておく必要がある。

オブジェクトのライフサイクルとメモリ管理

VBAにおける `Set obj = Nothing` は、単なる作法ではない。特に `FileSystemObject` のような外部COMコンポーネントを使用する場合、参照カウントが適切にデクリメントされないと、プロセスが終了してもファイルが「使用中」としてロックされ続ける現象が発生する。これは自動化バッチを組む際に、後続のプロセスが「ファイルが見つかりません」あるいは「アクセス拒否」で落ちる最大の原因となる。

Windows APIへの拡張性

もし、数千個のファイルをスキャンするような極限のパフォーマンスを要求される場合、`FileSystemObject` のオーバーヘッドすら無視できなくなる。その場合、我々は `kernel32.dll` の `GetFileAttributesEx` APIを直接叩き、ファイルシステムから直接構造体としてメタデータを引き出す手法を選択する。

' APIを使用する場合のイメージ(概念)
Private Declare PtrSafe Function GetFileAttributesEx Lib "kernel32" _
    Alias "GetFileAttributesExA" (ByVal lpFileName As String, ByVal fInfoLevelId As Long, pFileInfo As WIN32_FILE_ATTRIBUTE_DATA) As Long

このように、「どの抽象化レイヤー(VBA標準 vs FSO vs Win32 API)を選択するか」という判断こそが、エンジニアの腕の見せ所である。

レガシー環境への配慮(Late Binding)

本コードでは `CreateObject(“Scripting.FileSystemObject”)` を用いた Late Binding(遅延結合) を採用している。これは、クライアントPCごとに参照設定(References)のバージョンが異なることによる「参照不可エラー」を回避するための、実務上の必須テクニックである。

結論

「ファイルサイズをチェックする」というタスクの裏側には、リソース管理、エラーハンドリング、そしてシステムの堅牢性という深い設計思想が隠れている。

コードを書くときは常に自問せよ。
「このコードは、1万回連続で実行されても、メモリを食いつぶさずに、ファイルをロックし続けずに、エラーなく動き続けるか?」

その問いに「Yes」と答えられる実装のみが、プロフェッショナルの仕事である。

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