【プロフェッショナル】Application.FileConvertersの限界を突破:レガシー.pptをモダン.pptmへコードごと昇華させる自動移植アーキテクチャ
開発の現場において、最も呪わしい遺産の一つが「旧式の `.ppt` 形式で眠る、属人化したVBAマクロ資産」である。
セキュリティポリシーが厳格化された現代のモダンなオフィスにおいて、バイナリ形式のレガシーファイルを開くこと自体がリスクであり、さらにそれをOffice 365環境の `.pptm` へ移行する作業は、手動で行えば途方もない労力とヒューマンエラーの温床となる。
「`Application.FileConverters` を使えば一発で変換できるのでは?」
そう考えて実装に踏み切ったエンジニアは、必ずや壁にぶち当たる。ファイルコンバーターは形状(バイナリのコンテナ)を変換するだけであり、その内部にカプセル化されたVBAプロジェクト(VBProject)のモジュール群まで安全に、かつ自律的に新形式へトランスレーションしてはくれない。 さらに、ExcelやWordと異なり、PowerPointのセキュリティモデルはマクロのプログラムからの動的操作に対して極めて排他的である。
今回は、このレガシーの呪縛を完全に断ち切り、無数の `.ppt` からVBAコードを安全に抽出し、モダンな `.pptm` へ完全自動で移植・再コンパイルする、チーフアーキテクト水準の極限の自動化ソリューションを伝授する。
—
1. 致命的な壁:なぜ単純な変換ではVBAが失われるのか
PowerPointのオブジェクトモデルにおいて、`.ppt`(PowerPoint 97-2003プレゼンテーション)は OLEコンパウンドファイル構造を持つバイナリである。これをプログラムから `Presentations.Open` で開いた場合、セキュリティセンターの設定やマクロの有効化状態(`TrustAccessToVisualBasicProject`)が厳しく牙をむく。
さらに、ファイルを名前を付けて保存(`SaveAs`)で `.pptm` にコンバートする際、VBComponentの参照設定(GUID)の不整合や、フォーム(`UserForm`)のバイナリ破損が頻発する。
これを解決するための設計思想は以下の3点に集約される。
1. 完全無人化の担保:Excel側のマクロ(または外部コントローラー)からPowerPointを制御し、セキュリティ警告による処理の停止を完全に排除する。
2. コンポーネント単位のクリーンエクスポート:レガシーファイルのVBProjectから、標準モジュール、クラスモジュール、UserFormを物理的なテキスト(`.bas`, `.cls`, `.frm`)として一旦切り離す。
3. モダンコンテナへのインポートと強制コンパイル:新規生成した `.pptm` に対し、切り離したモジュールをプログラム的に流し込み、メモリ上で強制的にコンパイル(バイトコード化)して保存する。
—
2. 開発現場で即座に機能するプロダクションコード
以下のコードは、指定したフォルダ内のすべての `.ppt` ファイルを走査し、内部のVBAコードを安全に抽出・移植した `.pptm` を生成する、コントローラー側のメインプロシージャである。
※実行にあたっては、あらかじめExcelまたはPowerPointのVBAエディタから、`[ファイル] -> [オプション] -> [トラスト センター] -> [トラスト センターの設定] -> [マクロの設定]` において 「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」 にチェックを入れておく必要がある。この前提をクリアできない自動化は、実務において無価値である。
Option Explicit
‘ =========================================================================
‘ ódulo名: MdlLegacyMigrationArchitect
‘ 概要 : レガシーPPTのVBAコードを抽出し、モダンなPPTMへ完全自動移植する
‘ =========================================================================
Public Sub ExecuteLegacyMigrationPipeline()
Dim targetDir As String
Dim outputDir As String
Dim fileName As String
Dim fso As Object
‘ パスの設定(実務では環境変数や設定シートから動的取得すること)
targetDir = “C:\LegacyPresentationStorage\”
outputDir = “C:\ModernizedPresentationStorage\”
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(outputDir) Then fso.CreateFolder outputDir
‘ PowerPointアプリケーションのインスタンスを非表示で安全に起動
Dim ppApp As PowerPoint.Application
Set ppApp = New PowerPoint.Application
ppApp.Visible = msoTrue ‘ セキュリティダイアログのポップアップ抑止のため可視化を推奨する場合あり
fileName = Dir(targetDir & “.ppt”)
Do While fileName <> “”
Dim srcPath As String
Dim destPath As String
srcPath = targetDir & fileName
destPath = outputDir & fso.GetBaseName(fileName) & “.pptm”
On Error GoTo ErrorHandler
Call MigrateSinglePresentation(ppApp, srcPath, destPath, targetDir & “TempSrc\”, targetDir & “TempExport\”)
On Error GoTo 0
fileName = Dir
Loop
ppApp.Quit
Set ppApp = Nothing
MsgBox “すべてのレガシー資産の移行パイプラインが正常に完了しました。”, vbInformation
Exit Sub
ErrorHandler:
MsgBox “エラー発生 [” & fileName & “]: ” & Err.Description, vbCritical
If Not ppApp is Nothing Then ppApp.Quit
Set ppApp = Nothing
End Sub
Private Sub MigrateSinglePresentation(ByVal app As PowerPoint.Application, ByVal src As String, ByVal dest As String, ByVal workDir As String, ByVal exportDir As String)
Dim pptSrc As PowerPoint.Presentation
Dim pptDest As PowerPoint.Presentation
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(exportDir) Then fso.CreateFolder exportDir
‘ 1. レガシーファイルのオープン(読み取り専用)
Set pptSrc = app.Presentations.Open(FileName:=src, ReadOnly:=msoTrue, WithWindow:=msoFalse)
‘ 2. VBAコンポーネントの抽出処理
Dim comp As Object
Dim hasVBA As Boolean
hasVBA = False
On Error Resume Next
hasVgba = (pptSrc.VBProject.VBComponents.Count > 0)
On Error GoTo 0
If hasVBA Then
Dim vbComp As Object
For Each vbComp In pptSrc.VBProject.VBComponents
‘ 標準モジュール(1), クラスモジュール(2), フォーム(3)のみを対象とする(シートモジュールは除く)
If vbComp.Type = 1 Or vbComp.Type = 2 Or vbComp.Type = 3 Then
Dim ext As String
Select Case vbComp.Type
Case 1: ext = “.bas”
Case 2: ext = “.cls”
Case 3: ext = “.frm”
End Select
vbComp.Export exportDir & vbComp.Name & ext
End If
Next vbComp
End If
‘ 3. レガシープレゼンテーションを閉じる
pptSrc.Close
‘ 4. 新規モダンプレゼンテーション(.pptm)の作成
Set pptDest = app.Presentations.Add(WithWindow:=msoFalse)
‘ 5. スライド本体の移植(必要に応じてレイアウトやシェイプをコピー)
‘ ※ここではシンプルにファイルを別名保存してコンテナを.pptmにする
pptDest.SaveAs FileName:=dest, FileFormat:=ppSaveAsOpenXMLPresentationMacroEnabled
‘ 6. 抽出したVBAモジュールを新しいプロジェクトにインポート
If hasVBA And fso.FolderExists(exportDir) Then
Dim file As Object
For Each file In fso.GetFolder(exportDir).Files
If LCase(fso.GetExtensionName(file.Name)) = “bas” Or _
LCase(fso.GetExtensionName(file.Name)) = “cls” Or _
LCase(fso.GetExtensionName(file.Name)) = “frm” Then
pptDest.VBProject.VBComponents.Import file.Path
End If
Next file
End If
‘ 7. 最終保存とクリーンアップ
pptDest.Save
pptDest.Close
‘ 一時エクスポートファイルの削除
If fso.FolderExists(exportDir) Then fso.DeleteFolder exportDir, True
Set fso = Nothing
End Sub
—
3. チーフアーキテクトが教える、実運用における罠と対策
この高度な自動化パイプラインを本番稼働させるにあたり、プロフェッショナルが必ず考慮すべき「見えないリスク」と、その処方箋を提示する。
① 参照設定(References)の断絶問題
レガシーな `.ppt` で古いライブラリ(例:旧バージョンのMicrosoft Office Web Componentsや、特定のサードパーティ製DLL)が参照されている場合、単純にコードをインポートすると新規 `.pptm` 側でコンパイルエラー(`Type mismatch` や `Can’t find project or library`)を引き起こす。
- 対策: インポート処理の直前に、移行先プロジェクトの `VBProject.References` コレクションを走査し、無効な参照(`IsBroken = True`)をプログラム的に自動削除するか、必要なGUIDのみを動的再追加する防衛ロジックを組み込むこと。
② セキュリティポリシーによる実行時クラッシュ
`TrustAccessToVisualBasicProject` が有効になっていないPC環境でこのコードを実行すると、`Runtime Error 1004: プログラムから Visual Basic プロジェクトへのアクセスは信頼されていません` が発生し、システムが停止する。
- 対策: パイプラインの初期化フェーズにおいて、Windowsレジストリ(`HKCU\Software\Microsoft\Office\16.0\PowerPoint\Security\AccessVBOM` など、Officeのバージョンに応じたパス)を書き換えて強制的に信頼を付与する初期化バッチを前置させるのが、真に自律的なエンタープライズシステムのアーキテクチャである。
③ 巨大なバイナリとメモリリーク
大量のレガシーファイルをループ処理する際、PowerPointのCOMオブジェクトはガベージコレクションのタイミングが曖昧であり、メモリリークを起こしやすい。
- 対策: ループの1回ごとに `Set pptSrc = Nothing`、`Set pptDest = Nothing` を徹底し、さらに一定ファイル数(例:50ファイルごと)に `App.Quit` と再インスタンス化を挟むことで、プロセス自体のメモリフットプリントを常にクリーンに保つ設計が不可欠である。
—
総括
「古い仕組みだから手動で直すしかない」という現場の諦めを技術の力でねじ伏せることこそ、我々プロフェッショナルエンジニアの存在意義である。
`Application.FileConverters` の限界を見極め、オブジェクトモデルの奥底にある `VBProject` を直接ハックするこの設計を取り入れれば、数千ファイルに及ぶレガシー資産のモダン化を、一晩のバッチ処理で完璧に完遂することが可能となる。
属人化の象徴であるレガシーマクロを、モダンで堅牢なエンジニアリングの管理下に置こう。
