VBAには本来の非同期処理がないため、Application.OnTimeで疑似的にタイマー処理を組もうとして何度もハマりました。実行中のブックが閉じられた時の挙動など、ドキュメントだけでは分からない制約を中心に記録しています。
OnTime の構文
図1: Application.OnTime の定期実行フロー
' Application.OnTime EarliestTime, Procedure, [LatestTime], [Schedule]
' EarliestTime : 実行する時刻(Date型)
' Procedure : 実行するプロシージャ名(文字列)
' Schedule : True=登録(既定)/ False=キャンセル
指定時刻に1回実行
Option Explicit
Sub ScheduleOnce()
' 30秒後に DoTask を実行
Application.OnTime Now + TimeValue("00:00:30"), "DoTask"
End Sub
Sub DoTask()
MsgBox "30秒後の処理が実行されました: " & Now
End Sub
一定間隔で定期実行
Option Explicit
Private g_NextTime As Date
Private g_Running As Boolean
Sub StartTimer()
g_Running = True
g_NextTime = Now + TimeValue("00:00:10")
Application.OnTime g_NextTime, "TimerTick"
MsgBox "タイマー開始"
End Sub
Sub TimerTick()
If Not g_Running Then Exit Sub
' ── 定期処理 ──
Debug.Print "実行: " & Now
ThisWorkbook.Sheets(1).Cells(1, 1).Value = Now
' 次回を予約
g_NextTime = Now + TimeValue("00:00:10")
Application.OnTime g_NextTime, "TimerTick"
End Sub
Sub StopTimer()
g_Running = False
On Error Resume Next
Application.OnTime g_NextTime, "TimerTick", Schedule:=False
On Error GoTo 0
MsgBox "タイマー停止"
End Sub
タイマーのキャンセル
Schedule:=False で登録済みのタイマーをキャンセルできます。同一の時刻とプロシージャ名を指定する必要があります。
制約と注意事項
| 制約 | 内容 |
|---|---|
| Excelが開いている必要あり | Excelを閉じるとタイマーは無効化される |
| マクロ実行中はキューイング | 他のマクロ実行中は OnTime の時刻が来てもキューに積まれ、完了後に実行される |
| 精度は1秒単位 | ミリ秒以下の精度は出ない |
| 引数なしプロシージャのみ | 引数付きプロシージャは直接指定できない(グローバル変数経由で代替) |
| キャンセル時の注意 | タイマー時刻を変数に保持しておかないとキャンセルできない |
⚠️ ブックを閉じる前にタイマーを必ず停止する
Workbook_BeforeClose で StopTimer を呼び出すか、g_Running = False を設定してください。停止せずに閉じると次回開いたときに意図しない実行が起きる場合があります。
Application.OnTimeの活用パターン
業務Excelで実際に使われる定期処理の用途と、実装時の注意点をまとめる。
| 活用シナリオ | 実装のポイント | 注意点 |
|---|---|---|
| 外部データの定期取得(株価・為替・APIレスポンス) | TimerTick内でHTTPリクエストを発行しセルに書き込む。次回を再スケジュールして繰り返す | APIレスポンスが遅延すると次回スケジュールがずれる。Timeoutを設定しておく |
| 一定時間後の自動保存 | Now + TimeValue("00:05:00")で5分後にThisWorkbook.Saveを呼ぶ |
保存ダイアログが出ないようDisplayAlerts = Falseを設定する |
| 処理の分割実行(大量データを少しずつ処理) | 処理済み行番号をグローバル変数で持ち、OnTimeで次のチャンクを処理 | 途中でExcelを操作されると競合が起きる。処理中はUIをロックする工夫が必要 |
| アラート通知(閾値超え時にメッセージを表示) | 監視対象セルを定期チェックし、閾値超えでMsgBoxまたはテキスト書き込み |
MsgBoxはモーダルのため次回タイマーがキューに積まれる。非モーダル表示を検討 |
まとめ
Application.OnTime は定期実行ツールや自動保存・自動更新処理に有効です。ただし「Excelを閉じると止まる」「精度1秒」「引数なし限定」という制約を理解したうえで使いましょう。
✅ 次の章では…
PART 13 では API呼び出し を解説します。Declare Function でWin32 APIを呼び出し、64bit対応の PtrSafe についても解説します。
Application.OnTimeでよくある誤り
OnTimeによるタイマー処理は便利ですが、Excelのライフサイクルや制約を理解せずに使うと予期しない動作になります。
| 誤り/失敗パターン | 何が起きるか | 正しい対処/防止策 |
|---|---|---|
| OnTimeのキャンセル処理を書かない | ブックを閉じた後もタイマーが残り、次回Excel起動時にエラーが発生する | Workbook_BeforeCloseでApplication.OnTime EarliestTime:=nextTime, Procedure:="...", Schedule:=Falseでキャンセルする |
| Excelが閉じられてもタイマーが動くと思い込む | Excelを閉じるとOnTimeスケジュールはすべてキャンセルされ、定期実行が止まる | バックグラウンド実行が必要ならWindowsタスクスケジューラ+VBScriptやPowerShellで実装する |
| 引数ありのプロシージャをOnTimeで直接指定する | OnTimeはプロシージャ名の文字列指定のため引数を渡せず、エラーになる | 引数をグローバル変数やPublic変数で渡すか、引数なしのラッパープロシージャを作成してOnTimeで呼び出す |