PowerPoint VBAの限界を突破せよ:マルチコアを支配する並列変換エンジンの構築
PowerPoint VBAを愛する諸君。君たちが直面している「数百のPPTXをPDF化するのに、なぜ数十分も待たされるのか」というフラストレーションを解消する時が来た。
VBAは、基本的には単一スレッドで動作する。GUIのイベントループを占有し、CPUの1コアをひたすら酷使する。これは現代のマルチコアCPU環境において、Ferrariに時速30kmの制限速度を課すようなものだ。
本稿では、「VBAをコントローラー(司令塔)とし、VBScriptをワーカー(実行部隊)として多重起動する」という、極めて堅牢かつ高速な並列処理アーキテクチャを伝授する。
—
1. なぜ「単一スレッド」ではいけないのか
VBAで `For Each` ループを回して `ExportAsFixedFormat` を叩く。これは、前のPDF変換が終わるまで次の処理が始まらない「逐次実行」だ。
これでは、ファイルI/Oの待機時間やPowerPointのCOM起動コストが重なり、CPU使用率はわずか数%で低空飛行を続けることになる。
我々が目指すのは、「CPUの論理コア数分のPowerPointインスタンスを同時に叩き起こし、PDF変換を並走させる」ことである。
—
2. アーキテクチャの設計思想
1. VBA (Controller): 処理対象のファイルリストを生成し、キューを管理する。
2. VBS (Worker): 独立したプロセスとして起動。渡された引数(対象ファイル)に基づき、PowerPointをバックグラウンドで操作し、PDF化して終了する。
3. WSH (Windows Script Host): `WScript.Shell` を利用し、非同期でVBSをキックする。これにより、VBA側は「投げっぱなし」で次のタスクを割り当てられる。
—
3. 実装:並列変換エンジン(プロダクションコード)
ワーカー側:Worker.vbs
このスクリプトを `C:\Scripts\Worker.vbs` として保存せよ。
‘ Worker.vbs: 引数を受け取り、単一ファイルを処理して速やかに終了する
Dim pptApp, pptPres, sourcePath, destPath
sourcePath = WScript.Arguments(0)
destPath = WScript.Arguments(1)
Set pptApp = CreateObject(“PowerPoint.Application”)
‘ 不必要なGUIを表示せず、高速に処理する
Set pptPres = pptApp.Presentations.Open(sourcePath, , , False)
‘ PDF変換(ppFixedFormatTypePDF = 2)
pptPres.ExportAsFixedFormat destPath, 2
pptPres.Close
pptApp.Quit
Set pptPres = Nothing
Set pptApp = Nothing
コントローラー側:VBAコード
VBA側では、CPUのコア数に合わせて並列数を制限する「セマフォ(制限管理)」を実装するのがプロの作法だ。
Sub ParallelExportToPDF()
Dim shell As Object
Dim fso As Object
Dim folderPath As String, targetFile As String
Dim workerScript As String
Dim maxThreads As Integer: maxThreads = 4 ‘ CPU負荷を見て調整せよ
Dim runningCount As Integer
Set shell = CreateObject(“WScript.Shell”)
Set fso = CreateObject(“Scripting.FileSystemObject”)
folderPath = “C:\SourcePPTX\”
workerScript = “C:\Scripts\Worker.vbs”
‘ 簡易的な並列キュー処理
Dim file As Object
For Each file In fso.GetFolder(folderPath).Files
If LCase(fso.GetExtensionName(file.Path)) = “pptx” Then
Dim cmd As String
cmd = “wscript “”” & workerScript & “”” “”” & file.Path & “”” “”” & _
Replace(file.Path, “.pptx”, “.pdf”) & “”””
‘ 非同期実行(0は非同期、Trueは終了待ちだが今回はあえて非同期で投げる)
shell.Run cmd, 0, False
‘ 簡易的なスロットリング(過負荷防止)
runningCount = runningCount + 1
If runningCount >= maxThreads Then
Application.Wait (Now + TimeValue(“0:00:05”)) ‘ 5秒待機してプロセスを分散
runningCount = 0
End If
End If
Next
End Sub
—
4. 堅牢性を高めるための「極限の知見」
① プロセス監視とゾンビ化防止
大量のPDF変換を行うと、稀にPowerPointのCOMプロセスがゾンビとして残る。これを防ぐには、各ワーカーが完了した後に確実に `Quit` を発行すること。また、VBAの `On Error` 制御で、変換失敗時にログを吐き出す仕組みは必須だ。
② クラウド同期の罠
OneDriveやDropboxで同期中のフォルダを直接操作してはいけない。同期エンジンがファイルをロックし、変換がタイムアウトする。
「ローカルのテンポラリ領域で処理 → 完了後に同期フォルダへ移動」というフローを徹底すること。
③ なぜマルチスレッドではなくマルチプロセスか
VBAからスレッドを扱うのは自殺行為に近い(メモリ保護違反でExcelが落ちる)。プロセスを分けることで、万が一1つの変換でPowerPointがフリーズしても、全体のプロセスは生き残り、他のPDF変換を継続させることができる。これがエンタープライズ品質の設計だ。
—
最後に:エンジニアとしての矜持
この手法は、単なる「作業の高速化」ではない。「コンピューティングリソースをいかに効率的に支配するか」というシステム設計の縮図である。
君たちが作成するこのツールは、単なるマクロではない。数百のプレゼン資料という「重力」から組織を解放するためのインフラストラクチャなのだ。自信を持って導入したまえ。
何か技術的な壁に突き当たったときは、常に「プロセスはどう動いているか」「メモリはどう解放されるべきか」という根本に立ち返れ。現場からは以上だ。健闘を祈る。
