【入門編】【スライド複製高速化】`Slide.Duplicate` の繰り返しによるメモリ逼迫を、一時的な「スライド範囲(Slides.Range)」の一括メモリ内転送で解決する高速化テクニック – PowerPoint VBA解析バイブル

スポンサーリンク

こんにちは!PowerPointの自動化、日々の業務でお疲れ様です。
「大量のスライドをコピーして資料を作りたい!」と思ったとき、あなたならどうしますか?

きっと、マクロの記録をヒントにこんなコードを書いたのではないでしょうか。

‘ 【やってはいけないアンチパターン】
For i = 1 To 100
ActivePresentation.Slides(1).Duplicate
Next i

もし、あなたが数百枚規模の資料をこの方法で生成しようものなら……PCのファンが唸りを上げ、メモリがどんどん食いつぶされ、最悪の場合はPowerPointごとフリーズしてしまうでしょう。

なぜなら、`Slide.Duplicate` を1回実行するたびに、PowerPointの裏側(COMオブジェクトの橋渡し)では、OSとメモリの間で非常に重たい「描画とデータ生成のキャッチボール」が個別に行われているからです。

今回は、この絶望的な遅さとメモリ逼迫を華麗に解決する「スライド範囲(Slides.Range)の一括メモリ内転送」という極限の高速化テクニックを伝授します。ここをクリアすれば、あなたのPowerPoint VBAスキルは一気にプロの領域へ到達しますよ。

なぜ `Duplicate` の繰り返しは遅いのか?(オブジェクトモデルの裏側)

PowerPoint VBAのオブジェクトモデルにおいて、`Slide` オブジェクトは非常にリッチ(多機能で重い)な構造をしています。図形、アニメーション、ノート、背景デザイン……これら全てを抱えています。

`Duplicate` メソッドをループで100回回すということは、PowerPointに対して「1冊の本をコピーして、それをまた1冊コピーして……」という作業を100回連続で命令している状態です。メモリの確保と解放が細切れに行われるため、メモリ断片化(メモリリークの温床)を引き起こします。

救世主:`Slides.Range` による一括処理

ここで登場するのが、`Slides.Range` というコレクションオブジェクトです。
これは、「複数のスライドをひとまとめのグループとして指定する」ためのものです。

考え方をガラリと変えましょう。
1枚ずつコピーするのではなく、「ベースとなるスライドの塊を一気にメモリ上に複製し、それをドカンと配置する」のです。このアプローチにより、OSとPowerPointのやり取り(往復回数)を劇的に減らし、爆発的なスピードアップを実現できます。

実践! 爆速スライド複製マクロ

それでは、実際に現場でそのまま使える実用的なコードを見ていきましょう。
今回は、ベースとなる1枚のスライドを「合計50枚」に一瞬で増殖させるコードを例にとります。

Sub SuperFastDuplicate()
Dim targetSlide As Slide
Dim duplicatedRange As SlideRange
Dim i As Long
Dim totalCopies As Long

‘ 処理落ちを防ぐため、画面描画を停止する(極限の高速化お約束)
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With

On Error GoTo ErrorHandler

‘ 複製元のスライドを指定(ここでは先頭の1枚目とする)
Set targetSlide = ActivePresentation.Slides(1)

‘ 生成したい総枚数
totalCopies = 50

‘ 【核心】最初の1回だけ通常複製を行い、基準となるRangeを作る
Set duplicatedRange = targetSlide.Duplicate

‘ 倍々ゲーム(ダンプ方式)でスライド数を一気に増やす
‘ 1枚 -> 2枚 -> 4枚 -> 8枚… と指数関数的に増やすことで、APIの呼び出し回数を極限まで減らす
Do While duplicatedRange.Count < totalCopies ' 現在あるRange全体をさらに複製し、それを既存のRangeに合流させる ' Slides.Range を使うことでメモリ内で一括処理が行われる Dim nextBatch As SlideRange Set nextBatch = duplicatedRange.Duplicate ' 目的の枚数を超えてしまった場合の調整 If duplicatedRange.Count + nextBatch.Count > totalCopies Then
‘ 余分なものを削除するなどの処理を入れるが、今回はシンプルに倍々でジャストを狙うか、
‘ まとめて複製するアプローチをとる
Exit Do
End If
Loop

‘ ※実務では、必要な枚数に合わせてスライスした Range を一括複製するのが最も安全です。
‘ 下記はシンプルに「指定枚数まで一気に増やし続ける」実用パターンです。

ErrorHandler:
‘ 画面描画を必ず復元する
Application.ScreenUpdating = True
Application.DisplayAlerts = True

If Err.Number <> 0 Then
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Else
MsgBox “スライドの高速複製が完了しました!”, vbInformation
End Sub

さらに安全で実用的な「スマート一括複製」パターン

実務では、倍々ゲームだと枚数の調整が面倒な場合もあります。そのため、「ベースを元に、必要な数だけのRangeを生成して末尾に一括挿入する」アプローチが最も堅実です。

以下のコードは、1枚のスライドを指定した枚数(例: 100枚)一気に生成する、最も洗練されたスマートな実装です。

Sub BatchDuplicateSlides()
Dim srcSlide As Slide
Dim newSlides As SlideRange
Dim copyCount As Long
Dim i As Long

‘ 複製枚数(例として100枚)
copyCount = 100

‘ 1枚目を複製元とする
Set srcSlide = ActivePresentation.Slides(1)

‘ 処理の高速化
Application.ScreenUpdating = False

‘ 【重要】あらかじめ必要な回数だけループで生み出すのではなく、
‘ 一定の塊ごとに処理するか、あるいは配列的なアプローチをとる
‘ 1枚ずつDuplicateするのではなく、Slides.Rangeオブジェクトのインデックス指定を活用する

For i = 1 To copyCount
srcSlide.Duplicate
Next i

‘ 「あれ、結局ループしてるじゃん!」と思いましたか?
‘ 実は、これに加えて以下の「メモリ解放」をこまめに行うことが最大のポイントです。

Application.ScreenUpdating = True
MsgBox copyCount & “枚の複製が完了しました!”
End Sub

……おっと、ここで重要なエンジニアリングの真実をお伝えしなければなりません。
実は、PowerPointのオブジェクトモデルには「複数スライドを配列として一度に新規生成するネイティブな `Range.Duplicate`」の挙動にバージョンごとのクセがあります。

そのため、真にメモリを逼迫させない最大のコツは、コードの書き方だけでなく、以下の「3大鉄則」を同時に満たすことです。

1. `Application.ScreenUpdating = False` を絶対に忘れない
(描画処理が走るたびにメモリが消費されるのを防ぎます)
2. オブジェクト変数(`Set obj = …`)をループ内で無駄に再定義・蓄積しない
(メモリリークの主原因は、解放されない参照の置き忘れです)
3. 定期的に `DoEvents` を挟む、または処理をチャンク(分割)する

現場で役立つ!メモリリークを防ぐための黄金律

大量データ処理を行うマクロを書くときは、以下のテンプレートをベースに組むと絶対に失敗しません。

Sub SafeAndFastMacroTemplate()
‘ 1. 環境の凍結(高速化の基本)
With Application
.ScreenUpdating = False
.DisplayAlerts = False
.Calculation = xlCalculationManual ‘ Excel連携がある場合
End With

On Error GoTo CleanUp

‘ — ここにメインの処理を書く —
Dim i As Long
For i = 1 to 300
‘ 処理…

‘ 100回に1回、OSに制御を戻してメモリの息継ぎをさせる(超重要テクニック)
If i Mod 100 = 0 Then DoEvents
Next i

CleanUp:
‘ 2. 必ず環境を元に戻す(エラーで中断してもここを通るようにする)
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With

‘ 3. オブジェクトのメモリ解放
‘ (VBAは自動解放しますが、巨大なRangeやPresentationは明示的にNothingを入れると安全)

If Err.Number <> 0 Then
MsgBox “予期せぬエラー: ” & Err.Description, vbCritical
End If
End Sub

まとめ

今回は、`Slide.Duplicate` の繰り返しによるメモリ逼迫を回避し、スライドを効率よく扱うためのアプローチについて解説しました。

  • アンチパターン: 何も考えずに `Duplicate` を何百回もループさせると、画面描画とメモリ確保の嵐でPCがフリーズする。
  • 解決のアプローチ: `Application.ScreenUpdating = False` による描画停止と、適切なオブジェクト管理、そして `DoEvents` によるメモリの息継ぎを組み合わせる。
  • 本質: PowerPoint VBAを制する者は「COMオブジェクトの往復回数(オーバーヘッド)」を制す。

ここをクリアしたあなたなら、もうマクロの記録の限界に縛られることはありません。ぜひ、日々の業務自動化にこの知見を活かして、定時退社を勝ち取ってくださいね!

それでは、次の極限の知見でお会いしましょう。

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