【実務・中級編】【上級者】マルチスレッド風の非同期タスク制御をVBScriptとのプロセス連携で擬似的に実現し、マルチコアCPUをフル活用して数百ファイルのPPTXを並列かつ超高速にPDFエクスポート・クラウド同期するバッチ基盤 – PowerPoint VBA解析バイブル

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

【極限設計】単一スレッドの呪縛を解け:マルチプロセス駆動によるPPTX一括PDF変換・同期エンジンの構築

「VBAで数百個のファイルを順番に処理させていたら、昼休みが終わってしまった」

もし君が、このような初歩的な設計ミスで時間を浪費しているとしたら、それはエンジニアとして致命的だ。PowerPointのVBAは、その性質上、単一スレッドで動作する。つまり、1つのインスタンスが1つのタスクをこなしている間、他のCPUコアは退屈なほど暇を決め込んでいるのだ。

現代のワークステーションは、8コア、16コア、あるいはそれ以上のマルチコアCPUを搭載している。これを使わずに、一本道のシーケンシャルな処理を強いるのは、F1マシンで渋滞の一般道を走るようなものだ。

本記事では、VBAの単一スレッドという「物理的限界」を、VBScriptによるマルチプロセス制御によって突破する。数百規模のPPTXファイルを、マルチコアをフル活用して並列・超高速にPDF変換・クラウド同期させる、プロフェッショナル向けの「並列バッチ基盤」の設計思想と実装を伝授しよう。

1. 設計思想:Master-Workerアーキテクチャの導入

単一のVBAマクロでループを回す設計を捨てろ。我々が構築するのは、「指揮官(Master)」と「実行兵(Worker)」を分離したMaster-Workerアーキテクチャだ。

アーキテクチャの構造

1. Master (VBScript/PowerShell):

  • 対象となるファイルのリストを取得し、タスクをキュー(Queue)化する。
  • CPUのコア数に基づき、複数の「Workerプロセス」を同時起動する。
  • 各Workerの生存確認と、終了後のリソース回収を行う。

2. Worker (VBScript + PowerPoint COM):

  • Masterから渡された「単一のファイルパス」を、独立したPowerPointインスタンスで開く。
  • PDFエクスポートを実行し、成功/失敗のステータスを返す。
  • 処理が終われば、自身を完全に終了(Terminate)させる。

この設計の肝は、「PowerPointのインスタンスをプロセスレベルで分離する」点にある。これにより、OSレベルでの並列処理が可能になり、マルチコアのパワーをダイレクトにスループットへ変換できる。

2. 実装:プロフェッショナル・コード・エディション

ここでは、実務に耐えうる堅牢なコードを示す。

【Worker】単一ファイル処理エンジン (`Worker.vbs`)

このスクリプトは、引数として受け取った1つのファイルを処理する「最小単位」だ。

' ==========================================================================
' Worker.vbs
' 役割: 単一のPPTXをPDFに変換し、クリーンアップを行う
' 使用方法: cscript Worker.vbs "C:\Path\To\File.pptx"
' ==========================================================================
Option Explicit

Dim objArgs, strFilePath, strPdfPath
Set objArgs = WScript.Arguments

' 引数チェック
If objArgs.Count < 1 Then
    WScript.Echo "Error: No file path provided."
    WScript.Quit 1
End If

strFilePath = objArgs(0)
strPdfPath = Replace(strFilePath, ".pptx", ".pdf")

Dim objPPT, objPres
Set objPPT = Nothing
Set objPres = Nothing

On Error Resume Next ' エラーハンドリングの開始

' PowerPointインスタンスの生成(独立したプロセスとして起動)
Set objPPT = CreateObject("PowerPoint.Application")

' プレゼンテーションを開く
' ReadOnly:=True, Untitled:=False, WithWindow:=False (ウィンドウ非表示)
Set objPres = objPPT.Presentations.Open(strFilePath, -1, 0, 0) 

If Err.Number <> 0 Then
    WScript.Echo "Error opening file: " & strFilePath & " | " & Err.Description
    If Not objPPT Is Nothing Then objPPT.Quit
    WScript.Quit 1
End If

' PDFエクスポート実行 (ppSaveAsPDF = 32)
' 成功したら終了コード0を返す
objPres.SaveAs strPdfPath, 32

If Err.Number <> 0 Then
    WScript.Echo "Error exporting PDF: " & strFilePath & " | " & Err.Description
    objPres.Close
    objPPT.Quit
    WScript.Quit 1
Else
    objPres.Close
    objPPT.Quit
    WScript.Quit 0 ' 成功
End If

On Error GoTo 0

【Master】並列プロセス・オーケストレーター (`Master.vbs`)

これが全体の司令塔だ。CPUコア数に合わせて、Workerを並列に走らせる。

' ==========================================================================
' Master.vbs
' 役割: ファイルリストを管理し、複数のWorkerを並列起動する
' ==========================================================================
Option Explicit

Dim objFSO, objFolder, strTargetDir, strWorkerPath
Dim colFiles, objFile, strFile, i
Dim maxWorkers, currentWorkers, objShell, objExec

' --- 設定領域 ---
strTargetDir = "C:\Work\Input\"    ' 入力フォルダ
strWorkerPath = "C:\Work\Worker.vbs" ' Workerスクリプトのパス
maxWorkers = 4                      ' 同時起動プロセス数(CPUコア数に合わせる)
' ----------------

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")

If Not objFSO.FolderExists(strTargetDir) Then
    WScript.Echo "Target directory not found."
    WScript.Quit
End If

Set objFolder = objFSO.GetFolder(strTargetDir)
Set colFiles = objFolder.Files

' プロセス管理用のコレクション
Set currentWorkers = CreateObject("System.Collections.ArrayList")

WScript.Echo "Starting Parallel Processing Engine..."

' ファイルループ
For Each objFile In colFiles
    If LCase(objFSO.GetExtensionName(objFile.Name)) = "pptx" Then
        strFile = objFile.Path
        
        ' Workerの起動準備
        ' cscript を使用して、Workerを非同期プロセスとして起動
        WScript.Echo "Queueing: " & objFile.Name
        
        ' プロセスが最大数に達している場合、空きが出るまで待機
        Do While currentWorkers.Count >= maxWorkers
            CheckWorkers currentWorkers, objShell
            WScript.Sleep 1000 ' 1秒待機してCPU負荷を抑える
        Loop

        ' Workerの起動
        Set objExec = objShell.Exec("cscript //nologo """ & strWorkerPath & """ """ & strFile & """")
        currentWorkers.Add objExec
    End If
Next

' 全てのWorkerが終了するのを待機
WScript.Echo "All files queued. Waiting for remaining processes..."
Do While currentWorkers.Count > 0
    CheckWorkers currentWorkers, objShell
    WScript.Sleep 1000
Loop

WScript.Echo "Batch processing completed successfully."

' --- サブルーチン: プロセスの生存確認と回収 ---
Sub CheckWorkers(ByRef workerList, ByRef shell)
    Dim j, objCurrent
    For j = workerList.Count - 1 To 0 Step -1
        Set objCurrent = workerList(j)
        ' ProcessIDが有効か、または終了しているか確認
        ' ExecオブジェクトのStatusを利用
        If objCurrent.Status = 0 Then ' 0 = Running
            ' 実行中
        Else
            ' 終了している
            workerList.Remove j
        End If
    Next
End Sub

3. 運用における「極限の知見」:落とし穴を回避せよ

このシステムをプロダクション環境で動かす際、初心者が必ず陥る罠がある。アーキテクトとして、以下の3点を肝に銘じておけ。

① 「ゴースト・プロセス」の恐怖

PowerPointは、エラーが発生した際にCOMオブジェクトの解放に失敗し、`powerpnt.exe` がメモリ上に残り続けることが多々ある。これが積み重なると、メモリを食いつぶし、システム全体がハングアップする。

  • 対策: Worker側では必ず `On Error Resume Next` を使い、エラー時でも `objPPT.Quit` を確実に通るように設計すること。また、Master側で一定時間応答のないプロセスを強制終了(`taskkill`)する監視ロジックを追加するのが理想的だ。

② ファイルロックと競合

クラウド同期(OneDriveやSharePoint)が走っているフォルダに対して、同時に大量の書き込みを行うと、ファイルロック(Sharing Violation)が発生する。

  • 対策: 変換後のPDFは、同期対象外の「ローカル一時作業フォルダ」に出力し、全プロセス完了後に、一括で同期フォルダへ移動(Move)させる設計にせよ。これが最も堅牢だ。

③ リソースの過剰割り当て

「コア数=最大プロセス数」にするのが基本だが、PowerPointは意外とメモリを消費する。

  • 対策: メモリ容量が少ない環境では、`maxWorkers` を `(物理コア数 / 2)` 程度に抑える。スループットよりも「完走すること」に重きを置くのが、プロフェッショナルの判断だ。

結論

VBAの限界は、言語の仕様ではなく、君の設計思想の限界だ。
単一スレッドの制約に縛られず、プロセスを切り出し、OSの力を借りる。この「抽象化」と「分散」の考え方こそが、単純な自動化担当者を、真の自動化エンジニアへと進化させる。

さあ、このコードをベースに、君の業務環境に合わせた最強のエンジンを組み上げてみせろ。

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