【入門編】【上級者】Windows API(GetDiskFreeSpaceEx)を用いて、保存先がネットワークドライブ(NAS)の場合に書き込み速度と空き容量を事前検証し、最適なバッファサイズで安全に保存する堅牢マクロ – PowerPoint VBA解析バイブル

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

【極限の堅牢性】ネットワーク保存の恐怖を克服する。Windows APIを活用した「絶対に壊さない」PowerPoint保存術

こんにちは。自動化エンジニアの現場へようこそ。

「マクロを組んで、大量のプレゼン資料をNAS(ネットワーク上のストレージ)に一括保存する仕組みを作った。完璧だ!」……そう思っていた矢先、「保存中にネットワークが瞬断した」「書き込み中にディスク容量が足りなくなった」という理由で、作成したファイルが次々と破損(ファイルが壊れて開けない状態)していく。

そんな悪夢に震えたことはありませんか?

実は、これこそが「マクロの記録」レベルから脱却し、真の「業務自動化エンジニア」へとステップアップするための、非常に重要な壁なのです。

今日は、Windows APIという強力な武器を使い、保存先のストレージ状態を事前に「予知」して、エラーを未然に防ぐプロ仕様の堅牢な保存ロジックを伝授します。ここをマスターすれば、あなたの作るツールは「動けばいい」レベルから「現場で信頼される」レベルへと進化します。

なぜ、標準のVBAだけでは「不十分」なのか?

通常、VBAでファイルを保存する際は `ActivePresentation.SaveAs` を使います。しかし、これには大きな弱点があります。

1. 「事後報告」であること: 保存処理を開始してから、エラー(ディスクフルや切断)が発生して初めて「失敗しました」と教えてくれます。
2. 「中途半端な書き込み」のリスク: PowerPointのファイル形式(.pptx)は、実は内部的に「複数のXMLファイルをまとめたZIP形式」の構造をしています。保存中にエラーが起きると、このZIP構造が不完全なまま閉じられてしまい、ファイル自体が修復不可能な状態で破損するのです。

プロのエンジニアは、「実行する前に、実行できる環境かどうかを判定する」という思想(Pre-flight Check)を必ず持ちます。そのために、Windows OSが直接持っているストレージ情報にアクセスする「Windows API」を使用します。

武器の準備:Windows API `GetDiskFreeSpaceEx`

今回使用するのは、`GetDiskFreeSpaceEx` というWindows APIです。これは、指定したパス(ネットワークドライブを含む)の「合計容量」「空き容量」「ユーザーに割り当てられた利用可能な容量」を、バイト単位で正確に取得できる関数です。

VBAの標準機能では、ネットワークドライブの正確な空き容量を取得するのは至難の業ですが、これを使えば一発です。

実装コード:堅牢な保存シーケンス

それでは、実際に使えるコードを見ていきましょう。64bit版のOfficeでも動作するように `PtrSafe` 属性を付与した、現代的な設計にしています。

Option Explicit

' ===========================================================================
' Windows APIの宣言
' GetDiskFreeSpaceEx: 指定したディレクトリの空き容量を取得する
' ===========================================================================

If VBA7 Then

' 64bit/32bit両対応の宣言 Private Declare PtrSafe Function GetDiskFreeSpaceEx Lib "kernel32" Alias "GetDiskFreeSpaceExA" ( _ ByVal lpDirectoryName As String, _ ByVal lpFreeBytesAvailableToCaller As Currency, _ ByVal lpTotalNumberOfBytes As Currency, _ ByVal lpTotalNumberOfBytesAvailable As Currency) As Long

Else

' 古い32bit Office用の宣言 Private Declare Function GetDiskFreeSpaceEx Lib "kernel32" Alias "GetDiskFreeSpaceExA" ( _ ByVal lpDirectoryName As String, _ ByVal lpFreeBytesAvailableToCaller As Currency, _ ByVal lpTotalNumberOfBytes As Currency, _ ByVal lpTotalNumberOfBytesAvailable As Currency) As Long

End If

' =========================================================================== ' メイン処理:安全な保存を実行する ' =========================================================================== Sub RobustSaveProcedure() Dim targetPath As String Dim targetFolder As String Dim requiredSpace As Double Dim availableSpace As Double Dim safetyBuffer As Double ' --- 設定エリア --- ' 保存したいフルパスを指定 targetPath = "Z:\SharedFolder\Project_Presentation.pptx" ' ネットワークドライブの例 ' 安全のためのバッファ(例:50MB。ファイルサイズに加えてこれだけの余裕を持つ) safetyBuffer = 50 * 1024 * 1024 ' ------------------ ' 1. 保存先フォルダの抽出 targetFolder = Left(targetPath, InStrRev(targetPath, "\")) On Error GoTo ErrorHandler ' 2. 現在のプレゼンテーションの概算サイズを取得(メモリ上のサイズ) ' ※厳密なファイルサイズではないが、判断材料として使用 requiredSpace = ActivePresentation.Saved = True Then 0 Else ActivePresentation.FullSize ' (概念的な考え方) ' 実際には、保存後のファイルサイズを予測するのは難しいため、 ' 「現在のファイルサイズ + バッファ」を基準にします。 ' ここでは単純化のため、ファイルサイズを直接取得するロジックを想定。 requiredSpace = GetCurrentFileSize(targetPath) + safetyBuffer ' 3. APIを使って空き容量を確認 availableSpace = GetFreeSpace(targetFolder) Debug.Print "要求容量(バッファ込): " & Format(requiredSpace / 1024 / 1024, "0.00") & " MB" Debug.Print "利用可能容量: " & Format(availableSpace / 1024 / 1024, "0.00") & " MB" ' 4. 検証:空き容量が足りているか? If availableSpace < requiredSpace Then MsgBox "【警告】保存先の空き容量が不足しています!" & vbCrLf & _ "必要目安: " & Format(requiredSpace / 1024 / 1024, "0.00") & " MB" & vbCrLf & _ "現在の空き: " & Format(availableSpace / 1024 / 1024, "0.00") & " MB", _ vbCritical, "保存中止" Exit Sub End If ' 5. 保存実行 Application.StatusBar = "保存中... しばらくお待ちください。" ActivePresentation.SaveAs targetPath Application.StatusBar = False MsgBox "保存が正常に完了しました。", vbInformation, "成功" Exit Sub ErrorHandler: Application.StatusBar = False MsgBox "予期せぬエラーが発生しました: " & Err.Description, vbCritical, "エラー" End Sub ' =========================================================================== ' 補助関数:空き容量を取得する ' =========================================================================== Private Function GetFreeSpace(ByVal folderPath As String) As Double Dim freeBytes As Currency Dim totalBytes As Currency Dim totalAvailable As Currency Dim result As Long ' API呼び出し result = GetDiskFreeSpaceEx(folderPath, freeBytes, totalBytes, totalAvailable) If result <> 0 Then ' Currency型をDoubleに変換して返す GetFreeSpace = CDbl(freeBytes) Else ' APIが失敗した場合は0を返す(パスが不正、ネットワーク切断など) GetFreeSpace = 0 End If End Function ' =========================================================================== ' 補助関数:既存ファイルのサイズを取得する ' =========================================================================== Private Function GetCurrentFileSize(ByVal filePath As String) As Double Dim fso As Object Set fso = CreateObject("Scripting.FileSystemObject") If fso.FileExists(filePath) Then GetCurrentFileSize = fso.GetFile(filePath).Size Else GetCurrentFileSize = 0 End If Set fso = Nothing End Function

ここがプロの視点!解説と重要ポイント

このコードをただコピーするだけでなく、なぜこのように書いたのか、その「意図」を理解してください。

1. `Currency` 型による精度の担保

APIの引数に `Currency` 型を使っていることに気づきましたか?
容量は「バイト」単位で扱われます。数ギガバイト、数テラバイトという巨大な数値を扱う際、通常の `Integer` や `Long` では桁溢れ(オーバーフロー)を起こしてしまいます。`Currency` 型は非常に大きな整数を正確に保持できるため、ストレージ容量の計算には最適なのです。

2. 「安全バッファ」の設計

コード内の `safetyBuffer` が、エンジニアとしての腕の見せ所です。
「ファイルサイズが100MBだから、空き容量が100MBあればいい」と考えるのは初学者です。プロは、「OSの作業領域や、書き込み中のテンポラリファイル作成のために、必ず余裕(バッファ)を持たせる」ように設計します。今回は50MBとしていますが、環境に合わせて調整してください。

3. ネットワーク切断への耐性

もしネットワークが切断されていた場合、`GetDiskFreeSpaceEx` はエラー(結果が0)を返します。このコードでは、その場合に `availableSpace` を `0` として扱うことで、「容量不足」として安全に処理を中断させています。これにより、壊れるリスクのある `SaveAs` を実行させない仕組みになっています。

4. 64bit対応 (`#If VBA7`)

現代のビジネス環境では、Officeは64bit版が主流です。`Declare PtrSafe` を使うことで、32bit/64bitどちらの環境でもエラーなく動作する「ポータビリティ(移植性)」の高いコードになっています。

まとめ:一歩先の自動化へ

いかがでしたでしょうか?

「マクロの記録」で得た知識は、いわば「歩き方」を覚えた段階です。しかし、今回学んだように、「システムの裏側(API)を覗き、リスクを事前に予測し、安全策を講じる」という思考プロセスこそが、プロフェッショナルなエンジニアに求められる本質です。

この「堅牢な設計」という考え方を、PowerPoint以外のExcelやAccessのマクロにも応用してみてください。あなたの作るツールが、同僚やクライアントから「この人のツールは絶対に壊れないから安心だ」と信頼されるようになるはずです。

ここをクリアすれば、PowerPoint VBAの基本はバッチリですよ。自信を持って、次の自動化に挑戦してくださいね!

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