【PowerPoint VBA】マクロ付き(.pptm)からVBAを完全に駆逐し、安全な「.pptx」を自動生成する極限の処方箋
開発プロジェクトの現場において、VBAを組み込んだマクロ有効プレゼンテーション(`.pptm`)をそのままクライアントや社外へ配布する愚行を犯していないだろうか。
セキュリティリスクの観点から、マクロが含まれたファイルをそのまま外部に出すことは、地雷原を裸足で歩くようなものだ。受け取り側のセキュリティポリシーに引っかかるのはもちろん、意図しないコードの流出やマルウェアと誤認されるリスクすら孕んでいる。
「配布直前に手動で『名前を付けて保存』から `.pptx` に切り替えている」
もし君がそう答えるなら、エンジニアとしての自動化スピリットを疑わざるを得ない。ヒューマンエラーの温床であり、多重業務の典型例だ。
今回は、現在アクティブな `.pptm` からVBAプロジェクトのコードを完全に消去し、安全な標準形式(`.pptx`)として一瞬で別名保存を完了させる、実務直結のプロダクションコードを授けよう。
—
1. なぜ「単なる名前を付けて保存」では不十分なのか?
GUI操作でファイル形式を `.pptx` に変更して保存すれば、PowerPointは自動的にVBAコードを切り落としてくれる。しかし、これをVBAから自動化しようとしたとき、甘い設計をしていると痛い目を見る。
ここでPowerPoint VBAの残酷な真実を伝えよう。
「現在実行中のVBAコード自身を、コード実行中にそのファイルから削除することはできない」。
考えてみれば当然だ。自分の足元にある地面を自分で切り崩すようなものであり、実行コンテキストそのものが消滅するため、ランタイムエラー(または強制終了)を引き起こす。
したがって、安全に `.pptx` を生成するためには、以下のスマートなアプローチを取る必要がある。
1. 別名でコピーを保存する(この時点ではまだ `.pptm` または `.pptx`)
2. そのコピーを開き、VBAからVBAComponent(コードモジュール)をすべて削除する
3. 最終的な `.pptx` として上書き保存をかけ、クローズする
このライフサイクルを完璧に制御して初めて、現場で使える「堅牢なツール」となる。
—
2. プロダクションコード:完全自動サニタイズ&セーブ
以下のコードを、標準モジュールにそのまま貼り付けてほしい。
エラーハンドリング、同名ファイルの存在チェック、そして実行時の画面描画抑制(パフォーマンス最適化)を網羅した、実務クオリティのコードだ。
Option Explicit
‘ ==============================================================================
‘ 処理名 : ExportAsCleanPptx
‘ 概要 : 実行中のマクロ有効プレゼンテーションからVBAコードを完全除去し、
‘ 安全な「.pptx」として同階層に別名保存する
‘ ==============================================================================
Public Sub ExportAsCleanPptx()
Dim srcPath As String
Dim srcName As String
Dim extPos As Long
Dim dstPath As String
Dim targetPres As Presentation
Dim vbComp As Object
‘ 0. 実行前チェック:ファイルが一度も保存されていない(新規作成のまま)場合は弾く
If ActivePresentation.Path = “” Then
MsgBox “このプレゼンテーションはまだ保存されていません。” & vbCrLf & _
“一度名前を付けて保存してから実行してください。”, vbCritical, “致命的なエラー”
Exit Sub
End If
‘ 画面描画と警告を抑制し、処理速度を極限まで高める
With Application
.ScreenUpdating = False
.DisplayAlerts = ppAlertsNone
End With
On Error GoTo ErrorHandler
‘ 1. パスとファイル名の解決
srcPath = ActivePresentation.FullName
extPos = InStrRev(srcPath, “.”)
If extPos > 0 Then
dstPath = Left(srcPath, extPos – 1) & “_Safe.pptx”
Else
dstPath = srcPath & “_Safe.pptx”
End If
‘ 同名ファイルが存在する場合は上書き確認(または自動連番付与)
If Dir(dstPath) <> “” Then
If MsgBox(“指定されたファイルは既に存在します。” & vbCrLf & _
“上書きして保存しますか?” & vbCrLf & vbCrLf & dstPath, _
vbYesNo + vbQuestion, “上書き確認”) = vbNo Then
GoTo CleanUp
End If
‘ 既存ファイルをあらかじめ削除(PowerPointのSaveAs上書きバグ回避)
Kill dstPath
End If
‘ 2. 現在のプレゼンテーションを別名(.pptx)でコピー保存
‘ ※この時点ではまだVBAコードが内部に残っている
ActivePresentation.SaveCopyAs dstPath, ppSaveAsOpenXMLPresentation
‘ 3. 保存したコピーをバックグラウンドで開き、VBAコードを全消去する
Set targetPres = Presentations.Open(FileName:=dstPath, WithWindow:=msoFalse)
‘ VBAプロジェクトへのアクセスがセキュリティセンターで許可されているか確認
On Error Resume Next
Set vbComp = targetPres.VBProject
On Error GoTo ErrorHandler
If vbComp Is Nothing Then
MsgBox “VBAプロジェクトへのアクセスが信頼されていません。” & vbCrLf & _
“「ファイル > オプション > セキュリティセンター > セキュリティセンターの設定 > マクロの設定」から” & vbCrLf & _
“「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」を有効にしてください。”, _
vbCritical, “セキュリティ設定エラー”
targetPres.Close
GoTo CleanUp
End If
‘ 4. すべてのコンポーネント(標準モジュール、クラス、フォーム)を削除
Dim comp As Object
For Each comp in targetPres.VBProject.VBComponents
‘ ワークシートやThisDocumentなどの標準ドキュメントオブジェクト以外を削除
‘ 標準モジュール(1)、クラスモジュール(2)、フォーム(3)などが対象
Select Case comp.Type
Case 1, 2, 3
targetPres.VBProject.VBComponents.Remove comp
Case Else
‘ Document系モジュール(100)は削除できないため、コードの中身をクリアする
If comp.CodeModule.CountOfLines > 0 Then
comp.CodeModule.DeleteLines 1, comp.CodeModule.CountOfLines
End If
End Select
Next comp
‘ 5. サニタイズ完了したプレゼンテーションを「.pptx」として明示的に上書き保存して閉じる
targetPres.Save
targetPres.Close
‘ 成功通知
MsgBox “マクロの完全除去に成功しました!” & vbCrLf & vbCrLf & _
“保存先: ” & dstPath, vbInformation, “処理完了”
CleanUp:
‘ 描画・警告設定を復元
With Application
.ScreenUpdating = True
.DisplayAlerts = ppAlertsAll
End With
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “システムエラー”
Resume CleanUp
End Sub
—
3. アーキテクチャの解説:なぜこの実装が「プロフェッショナル」なのか?
ただ動くだけのコードなら素人でも書ける。プロのエンジニアが担保すべき「堅牢性」のポイントを解説しよう。
① `SaveCopyAs` と `Presentations.Open(…, WithWindow:=msoFalse)` のコンボ
オリジナル(編集中のファイル)を汚さずに、かつ安全に別形式へトランスフォームするために、一度 `SaveCopyAs` で別名(`.pptx` 拡張子)としてディスク上にファイル実体を生成する。
その後、そのファイルをあえて非表示ウィンドウ (`WithWindow:=msoFalse`)で開き、メモリ上でVBAの外科手術を行う。ユーザーに無駄なウインドウのチラつきを見せない、これがUX(ユーザー体験)への配慮だ。
② VBAコンポーネントの型 (`comp.Type`) の選別
VBAプロジェクト内には、ユーザーが追加したモジュールだけでなく、各スライドや `ThisDocument` といったシステム必須のDocument系オブジェクト(Type 100)が混在している。
これらを無理に `Remove` しようとすると容赦なくランタイムエラーが発生する。
そのため、コードブロックでは以下のように明確に処理を分岐させている。
- 標準・クラス・フォームモジュール (Type 1, 2, 3): `VBComponents.Remove` で丸ごと消去。
- ドキュメントモジュール (Type 100): 削除は不可能なため、`CodeModule.DeleteLines` でコード行を完全にゼロに清掃。
③ 「VBA プロジェクト オブジェクト モデルへのアクセス」の壁への配慮
Officeのデフォルトセキュリティでは、プログラムからVBAのコード領域へ干渉することが固く禁じられている。ここを見落とすと、現場で突然エラーを吐いてツールが停止する。
コード内では、`targetPres.VBProject` へのアクセスが遮断されているケースを検知し、ユーザーに対して的確なセキュリティセンターの設定変更を促すガードを実装している。
—
4. 現場への導入と運用ティップス
このスクリプトを組み込んだ `.pptm` を「マスターテンプレート」として運用し、リボンやクイックアクセスツールバーにこのマクロを登録しておけば、担当者は「安全なPPTXを出力するボタン」を1クリックするだけで、手動作業のミスとセキュリティリスクを完全に排除できる。
業務自動化の本質は、「人間がやるべきでない泥臭い作業を、機械に完璧に代行させること」だ。
セキュリティと効率性を両立させるこのアーキテクチャを、ぜひあなたの開発現場にも導入してほしい。
