🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Application.Wait — Excel が固まる理由と、代わりに Sleep を使うべきとき

|

Excel VBA の Application.Wait — Excel が固まる理由と、代わりに Sleep を使うべきとき

TL;DRApplication.Wait はマクロを壁時計の瞬間まで一時停止するのであって、秒数のあいだ止めるのではありません。だから Application.Wait 5 はほとんど何もしません — 5 はすでに過去にある時刻のシリアル値だからです。欲しいのは「いま+5 秒」であり、その分解能は秒単位だけです。

Sub PauseFiveSeconds()
    ' 現在時刻に 5 秒足した瞬間に起きる
    Application.Wait Now + TimeValue("0:00:05")
    MsgBox "Five seconds later."
End Sub

マクロを「一時停止」させたいとき、人が最初に手を伸ばすのが Application.Wait であり、そして最初に間違えるのもこれです。名前が仕組みを隠しているからです。これは時間の長さをセットするキッチンタイマーではありません — 瞬間をセットする目覚まし時計です。本記事はこの 1 つの考えを軸にしています。目覚まし時計のモデルが、あらゆるクセを説明するからです。引数のこと、秒単位という下限、そしてアラームがセットされている間はExcel が完全に固まって他に何もできないこと。

この記事で学べること

  • 考え方の軸 — Application.Wait は目覚まし時計(瞬間)であって、ストップウォッチ(時間の長さ)ではない
  • 誰もがつまずくたった一つのルール — 引数は時間の長さではなく絶対時刻である
  • なぜ秒単位でしか刻めないのか、そして 1 秒未満の停止には何を使うか
  • 待っている間、なぜExcel が固まるのか — 再描画なし、クリックなし、ステータスバーの更新なし
  • Application.Wait が正しいのはいつか、そして SleepDoEvents ループこそが本当に欲しかった道具なのはいつか、についての正直な結論

考え方の軸:目覚まし時計であって、ストップウォッチではない

目覚まし時計に「8 時間後に鳴れ」とは言いません。「7 時に鳴れ」と言います。Application.Wait もまったく同じです。起きるべき時点を渡すと、システムクロックがその時点に達するまでブロックします。時間の長さをカウントダウンするのではありません。

このたった一つの事実が、ナンバーワンのバグの源です。引数が瞬間であるため、欲しい秒数をそのまま書くことはできません — いま、プラス欲しい秒数、と書かねばならず、その「欲しい秒数」は TimeValue で組み立てます。

Application.Wait Now + TimeValue("0:00:05")   ' いま + 5 秒に起きる -> 約 5 秒待つ
Application.Wait Now + TimeValue("0:01:30")   ' いま + 1 分 30 秒に起きる
Application.Wait "14:30:00"                    ' 今日の午後 2 時 30 分に起きる(文字どおりの瞬間)

Now は現在の日付と時刻、TimeValue("0:00:05") は 5 秒という時間の長さを時刻値で表したもの。両者を足すと、いまから 5 秒後の瞬間になります。それが Application.Wait の求めるものです。

誰もがつまずくルール:引数は絶対時刻である

人を検索エンジンへ走らせる失敗がこれです。「Wait はマクロを一時停止する」と読んで、こう書きます。

Application.Wait 5      ' 誤り - 5 秒は待たない

VBA にとって 5 は「5 秒」ではありません。シリアル値の 5、つまり日付/時刻です。1900 年のエポックから 5 日後の深夜 0 時 — 何十年も過去の瞬間です。Application.Wait はクロックを見て、その瞬間はとうに過ぎていると分かり、実質すぐに戻ります。マクロはエラーになりません。ただ待たないだけです。この「止まりもしなければ、文句も言わない」という静けさが、まさに混乱の元です。

もっと分かりにくい形の同じ罠:Application.Wait Now + 55 日待ちます。日付に足した 5 は 5 秒ではなく 5 日を意味するからです。時間の長さは必ず TimeValue(または TimeSerial)で包みましょう。

Application.Wait Now + 5                      ' 5 日待つ - まず意図しない結果
Application.Wait Now + TimeValue("0:00:05")   ' 5 秒待つ - 正しい
Application.Wait Now + TimeSerial(0, 0, 5)    ' 同じこと。数値から組み立てる

このページから一行だけ覚えるなら、Now + TimeValue(...) にしてください。

刻めるのは秒単位だけ — もっと細かくは Sleep を

TimeValue は 1 秒未満を表現できません。Application.Wait が取れる最小の停止は1 秒で、TimeValue("0:00:00.25") などというものはありません。4 分の 1 秒の停止 — ポーリングループを間引く、リクエストの間隔を空ける、アニメーションを一押しする — を頼んでも、Application.Wait にはできません。

これが、二つの待機ツールを分けるきれいな境界線です。秒単位で、Declare も不要なら Application.Wait。1 秒未満、ミリ秒精度なら Sleep という Windows API です。Application.Wait がミリ秒を取ってくれたら、と思い始めたら、あなたはもうそれを卒業しています — Sleep に切り替えましょう。

誰もが忘れる部分:Excel を完全に固める

Application.Wait がブロックしている間、Excel は他に何もしていません。これは Excel のたった一本のスレッドの上で走り、メッセージを処理するためにそのスレッドを手放しません。だから待っている間は次のようになります。

  • 画面は再描画されない、
  • いま設定したステータスバーのメッセージは現れない、
  • クリックとキー入力は処理されないまま溜まっていく、
  • そして待ちが十分に長ければ、Windows はウィンドウに**「応答なし」**を焼き付ける。

これこそ、人が Application.Wait を使う最も一般的な理由に対して、それを間違った道具に変えてしまう罠です。目的が「カウントダウンを見せる」「進捗をユーザーに見せる」「キャンセルを押させる」のいずれかなら、Application.Wait は積極的にあなたの邪魔をします — 生かしておきたかったまさにそのインターフェイスを固めてしまうのです。

応答的な停止は、まったく別の構成です。DoEvents で制御を譲る短いループで、時間が過ぎる間も Excel が息をつき続けます。

' Excel を生かしたまま中断もできる停止 - Application.Wait ではない
Dim finishAt As Double
finishAt = Timer + 5                 ' Timer = 深夜 0 時からの秒数
Do While Timer < finishAt
    DoEvents                          ' Excel に再描画とクリック処理をさせる
    If gCancel Then Exit Do
Loop

何を使っているかに注目してください。経過秒数を測る Timer と、ウィンドウを生かし続ける DoEvents です。Application.Wait はそのどちらも与えてくれません。

正直な結論:Application.Wait が本当に正しいとき

Application.Wait がその居場所を得るのは、ちょうど一つの状況です。整数秒の停止が必要で、その間 Excel が固まっていても本当に構わないとき。教科書的な例は、外部フィードが追いつくのを少し待つ場面です — DDE/RTD リクエスト、Web クエリ、あるいは QueryTable の更新を撃ったばかりで、結果を読む前にデータが着地するのを 2、3 秒待ちたい。単純で、API 宣言も要らず、CPU を手放す(スピンしない)ので、短く、対話を伴わない、整数秒の停止なら申し分ない用途です。

それ以外はすべて、本当に欲しいものを名指ししましょう。

  • 1 秒未満の停止(ループを間引く、呼び出しの間隔を空ける)— SleepApplication.Wait は 1 秒より下へ行けないからです。
  • Excel が応答的でなければならない停止(進捗、キャンセル、目に見えるカウントダウン)— DoEvents ループ。Application.Wait はウィンドウを固めるからです。
  • 何かを後で、スケジュールに従って実行する(5 分ごと、午前 9 時に)— Application.OnTime。そもそも待機ではありません。

固まった Excel は Application.Wait の正しい挙動であって、バグではありません。バグは、固まった Excel が望みでないときにそれを使うことです。

ExcelMaster の活用

Application.WaitSleepDoEvents ループ、OnTime のどれを選ぶかは、1 秒未満の精度が要るか、Excel が応答的であり続けねばならないか、遅延が一度きりかスケジュールか、に左右される判断です。間違えれば、生かしておくつもりだった Excel を固めるか、Application.Wait 5 と書いて何も止まらない理由に首をひねるか、どちらかです。

ExcelMaster は、その判断をあなたの代わりに下します。欲しいものを言うだけ — 「クエリの更新のために 2、3 秒止めて」あるいは「待ちたい、でもキャンセルはさせて」 — で、正しい構成を選びます。単純な整数秒の停止には Application.Wait Now + TimeValue(...)、1 秒未満の間引きには Sleep の宣言、ウィンドウが応答的であり続けねばならないときはガード付きの DoEvents ループ。シリアル値ひとつ分のズレもなく、生きたマクロが欲しかったのに固まったマクロ、ということもありません。

よくある質問

VBA でマクロを 5 秒待たせるには?

Application.Wait Now + TimeValue("0:00:05") を使います。Application.Wait の引数は時間の長さではなく起きるべき瞬間なので、5 秒分の TimeValueNow(現在時刻)に足します。Application.Wait 5 と書いても効きません — VBA は 5 を過去の日付/時刻シリアル値として読むため、マクロはまったく止まりません。

Application.Wait 5 でマクロが止まらないのはなぜですか?

5 が時刻のシリアル値(おおよそ 1900 年の 5 日目の深夜 0 時)として解釈され、それがすでに過去だからです。Application.Wait は渡された瞬間にクロックが達するまでブロックしますが、その瞬間はとうに過ぎているので、すぐに戻ります。Now + TimeValue("0:00:05") のように未来の瞬間を渡す必要があります。

Application.Wait は 1 秒未満で止められますか?

いいえ。TimeValue が 1 秒未満を表現できないため、Application.Wait は秒単位でしか刻めません。1 秒未満の停止 — たとえば 250 ミリ秒 — には、代わりにミリ秒を取る Windows の Sleep API(Sleep 250)を使います。

Application.Wait の最中に Excel が固まったり「応答なし」と出たりするのはなぜですか?

Application.Wait が Excel のたった一本のスレッドをブロックし、待っている間メッセージを処理させないため、画面は再描画できず、クリックも処理されないからです。Excel が生きていなければならない停止 — 進捗を見せる、キャンセルを許す — には、Application.Wait ではなく DoEvents を呼ぶ短いループを使いましょう。

Application.Wait と Sleep の違いは何ですか?

Application.Wait は Excel に組み込まれ、宣言が不要で、壁時計の瞬間まで待ち、秒単位で刻みます。Sleep は自分で宣言しなければならない Windows API 呼び出しで、ミリ秒数だけ待ち(1 秒未満の精度)、64 ビット Excel では PtrSafe 属性が必要です。単純な整数秒の停止には Application.Wait を、もっと細かい精度が要るときは Sleep を使いましょう。どちらも待っている間は Excel を固めます。

検証環境

検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-19。

関連ガイド: VBA Sleep · VBA Timer · VBA DoEvents · VBA StatusBar · VBA ScreenUpdating