待ち時間中でも、画面更新、キー入力やマウス操作、Application.OnTimeによるプロシージャの実行などを阻害しないようなWaitプロシージャ(WaitEx)を試作。
Public Sub WaitEx(ByVal WaitMilliSeconds As Long)
パラメーター
---
[in] WaitMilliSeconds
待ち時間(ミリ秒)。
※INFINITEで無限待ち
戻り値
---
なし
一定時間処理を待つ(停止する)手段としてはApplication.WaitやSleep(Win32API)があるけれども、これらは指定した期間が経過するまではその間のウィンドウメッセージ(イベント)が処理されない問題がある。
WaitやSleepが実行中の場合には、例えば画面更新はされなくなり、Escキー等による中断も難しく、Application.OnTimeによって特定のタイミングでプロシージャを呼び出そうとしても、これらが終了するまでは待たされてしまう。
これを回避するための常套手段としては、指定時間になるまでループ内で短い間隔でWaitやSleepを繰り返し実行し、その都度DoEventsを呼び出すことによりイベント処理が可能なタイミングを挟み込む、というものがある(もしくは単にDoEventsを指定時間までひたすら繰り返したりする)が、メッセージ(イベント)の有無に関わらずDoEventsが呼び出されるために処理が重くなったりする等の問題がある。
そこで、WaitExの内部処理では、WaitやSleepの代わりとして、Win32APIのMsgWaitForMultipleObjectsを用いた(なお、MsgWaitForMultipleObjectsExでも同様のことは可能)。
これらは、メッセージ(イベント)があるタイミングかもしくは指定時間経過で終了するといった指定が可能なため、DoEventsの呼び出しはそのタイミングだけとなり、処理効率がよくなることが期待できる。
- 調べるきっかけとなった、いき@aero_ikiさんのツイート(ポスト)
- Office VBA 64/32Bit共用 Win32 API MsgWaitForMultipleObjects 待機関数 #Win32API - Qiita
- フォーム間のイベントやりとり - Visual Basic (VB・VBA・.NET)
Application.Evaluateを使っている関係で、Excel VBAでしか動かない。
↓
メインモジュール(Mod_WaitEx)中ではEvaluateを使わないようにしたので、WaitExプロシージャについてはExcel VBA以外のVBAでもおそらく利用可能。
ただし、例えばWordのApplication.OnTimeの仕様との違いから(例えば引数付きプロシージャ呼び出しはできない・一度に設定できるタイマは1個のみ)、テストモジュール(Mod_TestWaitEx)の方は正しく動かない。
↓
自前のモジュール(Mod_Callback)を用いたテストモジュール(Mod_TestCallback)の方であれば、Wordでも動いた。