共有フォルダの「爆弾」を解体せよ:PowerPoint VBAによる堅牢なPDF一括変換アーキテクチャ
ネットワーク共有フォルダ上のファイルを一括処理する際、多くのエンジニアが陥る罠がある。それは「ファイルシステムへの甘い認識」だ。
「とりあえずループでファイルを開いてPDF保存すればいい」と考えているなら、今すぐそのコードを破棄すべきだ。共有環境では、他ユーザーによる編集中(ロック中)のファイルに遭遇するのは日常茶飯事。無策で実行すれば、`Run-time error ‘-2147467259’`の嵐に巻き込まれ、変換処理は無残にクラッシュする。
本記事では、プロの現場で通用する「排他制御を考慮した堅牢なPDF一括変換スクリプト」の設計思想と実装を伝授する。
—
なぜ「そのまま」ではいけないのか?
共有フォルダにおけるファイル操作には、以下の3つのリスクが常に付きまとう。
1. 排他ロック: 誰かが開いているファイルを開こうとすれば、VBAは即座にエラーを吐く。
2. 一時ファイルの干渉: Office製品は編集中に `~$filename.pptx` という隠しファイルを生成する。これに引っかかると不整合を起こす。
3. リソースリーク: エラーで処理が中断された際、PowerPointのインスタンスがメモリ上に残り続け、次回以降の動作を不安定にする。
これらを解決する唯一の道は、「開く前に試す(Try-Open)」という防衛的プログラミングだ。
—
堅牢な設計の要諦
- Scripting.FileSystemObject (FSO): パス操作を安全に行い、ファイルの存在確認を確実にする。
- APIによるロック判定: ファイルを実際に開こうとしてエラーになる前に、排他アクセス権をテストする。
- エラーハンドリングの局所化: 個別のファイル処理でエラーが発生しても、全体を停止させずログを残して次のファイルへ進む。
—
プロダクションコード:RobustPDFConverter
このコードを標準モジュールに貼り付け、`targetPath` を環境に合わせて書き換えてほしい。
Option Explicit
‘ 共有フォルダ一括PDF変換スクリプト
Sub ConvertPptxToPdf_Robust()
Dim fso As Object: Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim folderPath As String: folderPath = “C:\Target\SharedFolder\” ‘ 処理対象フォルダ
Dim logPath As String: logPath = folderPath & “conversion_log.txt”
Dim file As Object, pptApp As Object, pres As Object
Dim logFile As Object
Set logFile = fso.OpenTextFile(logPath, 8, True) ‘ 追記モード
Set pptApp = Application ‘ 現在のインスタンスを使用
For Each file In fso.GetFolder(folderPath).Files
‘ .pptxかつ一時ファイルでないもののみ処理
If LCase(fso.GetExtensionName(file.Path)) = “pptx” And Not Left(file.Name, 2) = “~$” Then
If IsFileLocked(file.Path) Then
logFile.WriteLine Now & ” [SKIP] Locked: ” & file.Name
Else
On Error Resume Next
Set pres = pptApp.Presentations.Open(file.Path, ReadOnly:=True)
If Err.Number <> 0 Then
logFile.WriteLine Now & ” [ERROR] Open Failed: ” & file.Name
Else
pres.SaveAs Replace(file.Path, “.pptx”, “.pdf”), 32 ‘ 32 = ppSaveAsPDF
pres.Close
logFile.WriteLine Now & ” [SUCCESS] Converted: ” & file.Name
End If
Err.Clear
On Error GoTo 0
End If
End If
Next
logFile.Close
MsgBox “全工程が完了しました。ログを確認してください。”, vbInformation
End Sub
‘ ファイルが使用中か判定する関数
Function IsFileLocked(filePath As String) As Boolean
Dim fileNum As Integer
On Error Resume Next
fileNum = FreeFile
Open filePath For Binary Access Read Write Lock Read Write As #fileNum
Close #fileNum
IsFileLocked = (Err.Number <> 0)
On Error GoTo 0
End Function
—
実装のポイントと注意点
1. 排他制御の裏技(IsFileLocked)
`Open … Lock Read Write` を使うことで、ファイルが実際に排他オープン可能かを確認している。これは「開いてみるまでエラーが分からない」というVBAの仕様を逆手に取った、非常に軽量かつ効果的なテクニックだ。
2. ReadOnlyオプションの重要性
`Presentations.Open(…, ReadOnly:=True)` は必須だ。書き込み権限を要求しないことで、ネットワークトラフィックを抑え、サーバー負荷を最小化する。
3. ログの重要性
自動化ツールにとって、ログは「唯一のブラックボックスの開示手段」だ。成功・失敗・スキップを時刻付きで記録することで、運用後のトラブルシューティングが劇的に楽になる。
—
まとめ:自動化とは「失敗しないこと」ではない
真に優れた自動化ツールとは、「失敗したとき、その理由が即座に分かり、全体の業務を止めないもの」を指す。
今回紹介した設計をベースに、さらに「処理終了後のメール通知」や「特定のサブフォルダの再帰的走査(FileSystemObjectのRecursion)」を追加すれば、あなたのツールは部門内で最も信頼される業務改善システムへと進化するはずだ。
コードは書くことよりも、「いかに壊れないように設計するか」に魂を込めてほしい。健闘を祈る。
