VBA|保存処理(SaveAs)がフリーズする原因と対策
作成日:2025-11-06
更新日:2025-11-06

進捗ダイアログを出さないことで、保存後の“見えないフリーズ”は消える。
Kill the progress dialog, kill the freeze.
SaveAsの前後にアラートを止めるコード
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As Long)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If
Public Sub SaveWorkbookScoped(ByVal wb As Workbook, ByVal path As String, ByVal fmt As XlFileFormat)
Dim prevAlerts As Boolean, prevEvents As Boolean
On Error GoTo CLEANUP
' --- save current states
prevAlerts = Application.DisplayAlerts
prevEvents = Application.EnableEvents
' --- suppress UI
Application.EnableEvents = False
Application.DisplayAlerts = False
' --- risky I/O
wb.SaveAs FileName:=path, FileFormat:=fmt
wb.Close SaveChanges:=False
' --- let UI breathe
DoEvents
Sleep 100
' success path → always cleanup
GoTo CLEANUP
CLEANUP:
' restore no matter what
Application.DisplayAlerts = prevAlerts
Application.EnableEvents = prevEvents
End SubWhy this freezes|なぜ固まるのか
- Excelは長いI/O時に進捗ダイアログを出す。
- それにより、VBA実行が待機状態になることがある。
Application.DisplayAlerts=Falseは「ユーザー入力のダイアログ」を既定の応答で処理するため、早く終了できる。- ただし公式は、進捗自体を明示的に“消す”とは書いていない点に注意(Microsoft Learn)
Notes|補足
DoEventsはOSへ制御を渡し、メッセージキュー処理をさせるので固まり解消に寄与。- 過剰多用は避け、要所に限定。 (Microsoft Learn)
SleepはWindows API。64bitではPtrSafe必須。
Resource Release Lag|リソース解放の遅延とは
Excelが「保存完了」のあと、ファイルやUIリソースをすぐに解放できずに一瞬つかんだままになる状態。
- UI Thread Freeze|UIスレッドのフリーズ は、
その“解放待ち”の処理をUIスレッド(画面を担当するスレッド)が抱えてるせいで、
画面もVBAも動かなくなる(応答なしに見える)現象のこと。
Excelの中には「2つの世界」がある
| 種類 | 役割 | 例 |
|---|---|---|
| UI Thread(ユーザーインターフェイススレッド) | 画面描画、ダイアログ表示、メニュー操作など | 「保存中…」ダイアログ、進捗バー、マウスカーソルの砂時計表示 |
| Worker Thread(バックグラウンド処理) | ファイルI/Oや計算、保存の実行 | SaveAs の実処理、ディスク書き込み、再計算 |
普通は、
→ Worker Thread がファイル保存を終えたら
→ UI Thread に「終わったで」って通知して
→ 進捗ダイアログを閉じる、画面を再描画する、って流れになる。
Resource Release Lag|リソース解放の遅延
でも大量ファイル保存とかネットワーク越しやと、
Worker Threadが完了通知を送っても、Excel内部のCOMオブジェクトやファイルハンドルがまだ解放されてない。
UI側は「終わった通知を受け取ったのに、裏でまだ握られてる」と混乱する。
つまり:
“終わったっぽいけど、実際はまだ掴んでる” — これがリソース解放ラグ。
この瞬間、UIスレッドは「待機状態」に入って、
画面が固まったように見える(Stuck状態)。
UI Thread Freeze|UIスレッドのフリーズ
ExcelはシングルUIスレッド構造やから、
進捗ダイアログを出してる時にそのスレッドが止まると、
画面の更新もVBAの実行も止まる。
たとえば:
NewBook.SaveAs ...
' ←ここでUIがフリーズ
ってなると、
後続の DisplayAlerts = False も Close も実行に進めない。
Progress Dialog|進捗ダイアログの負担
「保存中… [キャンセル]」っていう小さいダイアログも、実はUIスレッドの管轄。
ファイルI/O中ずっとそのUIを描画・更新してるから、
ディスクやネットワーク遅延があるとCPUスレッドが飽和して、
UIが「描画更新待ち」に陥る=Stuckする。
しかもその進捗ウィンドウはVBAとは別の“モーダルUI”扱いになるから、
裏でコードが「完了を待機」する設計になってる。
→ 保存自体は完了してるのに、「UIが閉じない」せいでコードが動かない、というズレが発生。
だからこうなる
ファイルは保存されてる
でもUIスレッドが「終わった通知」を受け取れず固まってる
→ 結果として「キャンセルを押すと動く」ように見える。
対処の本質
DisplayAlerts = FalseでUI進捗を出さないDoEventsでOSに制御を戻す(UIスレッドに処理させる)Sleepで微小時間の同期を取る
これが、リソース解放ラグ+UIスレッドフリーズの両方に効く構造的対策。
保存完了=ファイルが書けた、ではなく、
「ExcelがUIごと全部片付けた」まで待たなければならない。
| UI Thread|ユーザーインターフェイスの主スレッド |
| Worker Thread|実処理担当スレッド |
| Resource Release Lag|リソース解放の遅延 |
| Progress Dialog|進捗ダイアログ |
| Stuck|描画・操作が止まる状態 |
| DoEvents|処理をOSに一時委譲 |
| Sleep|短いウェイトで同期を取る |
| Modal UI|操作をブロックするUI |
| COM Handle|内部リソースハンドル |
DoEvents + Sleep 100 はなぜ必要?
→ DoEvents で「Windowsに処理を渡す」
→ Sleep 100 で「CPUを0.1秒休ませる」
Excelが内部でリソース解放やUI更新を完了する時間を与えるために入れる。
たとえば、
- 保存直後 (
SaveAs→Close) はファイルI/Oが終わっても、
Excel内部のCOMリファレンス解放や画面再描画がまだ残ってる。 - その状態で次の処理(別ブック開く、フォルダ操作など)に進むと、
一瞬“競合”や“再ロック”が起きて固まるケースがある。
これでExcelが追いつく猶予を与える。
いつ要るか・いつ要らないか
| 状況 | 推奨 |
|---|---|
| ローカル保存で軽いファイル | ほぼ不要。速度優先で削ってOK |
| ネットワークドライブ/OneDrive保存 | あった方が安定(解放遅延が起こりやすい) |
| 繰り返し大量保存するバッチ処理 | 挟まないとリソースリークやUIフリーズリスクあり |
| Excelを閉じる直前だけ | 1回だけなら「保険」としてアリ |
まとめ
DoEvents→ UI・イベントの残処理を完了させる。Sleep→ OSレベルで短時間ウェイトを入れる。- 両方セットで「同期の保険」。
- だが、常時必須ではない。ネットワーク保存や連続I/O処理の時だけで充分。
短く言うと:
普通の保存なら要らない。ネットワーク越しや連続保存のときだけ、保険で入れる。
| DoEvents|処理をOSに明け渡す |
| Sleep|短時間停止(CPUクールダウン) |
| Cleanup Sync|後処理の同期 |
| I/O Release Lag|入出力の遅延解放 |
| Insurance Wait|保険的待機 |
Referenced Insights & Citations
- Microsoft. (2023). Application.DisplayAlerts property (Excel). https://learn.microsoft.com/ja-jp/office/vba/api/excel.application.displayalerts (Microsoft Learn)
- Microsoft. (2022). DoEvents function (VBA). https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/doevents-function (Microsoft Learn)
- Microsoft Support. (n.d.). DoEvents 関数. https://support.microsoft.com/ja-jp/office/doevents-%E9%96%A2%E6%95%B0-7af41eca-88e0-470d-adaf-0b3d4c2575b0 (Microsoft Support)
- Keysight. (n.d.). 64ビット版Excel/VBAでSleepを使用する場合のPtrSafe. https://docs.keysight.com/kkbopen/64excelvbasleep-749636346.html (Keysight Documentation)
- Microsoft. (2021). Workbook.SaveAs method (Excel). https://learn.microsoft.com/en-us/office/vba/api/excel.workbook.saveas (Microsoft Learn)
| Problem Isolation|問題の切り分け |
| UI Thread Freeze|UIスレッドのフリーズ |
| Progress Dialog|進捗ダイアログ |
| DisplayAlerts|表示警告の抑止 |
| DoEvents|イベント処理の明け渡し |
| Sleep (PtrSafe)|スリープ(PtrSafe宣言) |
| Silent Execution|サイレント実行 |
| Cleanup/FInally Pattern|後始末(Finally相当) |
| SaveCopyAs|コピー保存 |
| Best Practices|ベストプラクティス |
2025-11-06
編集後記:
この記事の内容がベストではないかもしれません。
記事一覧
-

[VBA]Make Directory MkDir 【VBA】フォルダを作る|MkDir(フォルダがすでに存在していればエラーになる) -

[VBA]開始と終了イベント停止と再開 【VBA高速化】開始と終了のルーチン呼び出し -

[VBA]Transpose2D Array 【VBA】配列の縦横変換|WorksheetFunction.Transpose は使わない -

[VBA]Nameでパス変更 【VBA】ブックのフルパスを変更する(ファイル名の変更も含む)|Name -

vbaの色設定 【VBA】色の定数は8つ|RGB対称表 -

Let と Getで読み取り専用 【VBA】クラスのプロパティを読み取り専用にするLet と Getの書き方