Application.OnTimeは標準モジュールのプロシージャもしくはThisWorkbookやSheet1等のCodeNameを持つオブジェクトのメソッドしか実行(コールバック)できません。
任意オブジェクトのメソッドをコールバックができないか? と思っていたのですが、Microsoft HTML Object Library で使用できる JScript を利用すればできそうに思えたので試してみました。
ライブラリ用標準モジュール(Mod_Callback.vba)のコードを標準モジュールとして貼り付けると、以下のプロシージャが使用可能となります。
なお、SetTimerとSetCallbackでは引数の指定方法が異なるだけで、機能的には同等です(待ち時間の単位がSetTimerはミリ秒(Long型)、SetCallbackでは秒(Double型)なので注意)。
※最初にSetCallbackを作った後、引数の指定方法がやや煩雑かも?と思いつつ、同じプロシージャ名で引数だけ変えると互換性の問題が出てくるので、別プロシージャ(SetTimer)にした次第。
Public Function SetTimer(ByVal WaitMilliSeconds As Long, ByVal MethodName As String, Optional ByVal ParamObject As Variant, Optional ByVal ParentObject As Object = Nothing) As Long
指定したオブジェクトのメソッド/標準モジュールのプロシージャを指定時間経過後に実行する
引数:
WaitMilliSeconds: コールバックさせるまでの時間(ミリ秒)
MethodName: コールバックさせる標準モジュールのプロシージャ名もしくはメソッド名(文字列)※メソッド名はParentObject指定時
ParamObject(オプション): コールバック時にパラメータとして渡すオブジェクト(Collection や Dictionary 等、文字列や数値も可能)
ParentObject(オプション): コールバックさせたいメソッドを持つオブジェクト・Nothing指定時は標準モジュールとみなす
戻り値: タイマーID
※該当コールバック識別用のIDとして使用
Public Function SetCallback(ByVal ParentObject As Object, ByVal MethodName As String, ByVal WaitSec As Double, Optional ByVal ParamObject As Variant) As Long
指定したオブジェクトのメソッド/標準モジュールのプロシージャを指定時間経過後に実行する
引数:
ParentObject: コールバックさせたいメソッドを持つオブジェクト・Nothing指定時は標準モジュールとみなす
MethodName: コールバックさせる標準モジュールのプロシージャ名もしくはメソッド名(文字列)※メソッド名はParentObject指定時
WaitSec: コールバックさせるまでの時間(秒)(※小数指定可)
ParamObject(オプション): コールバック時にパラメータとして渡すオブジェクト(Collection や Dictionary 等、文字列や数値も可能)
戻り値: タイマーID
※該当コールバック識別用のIDとして使用
Public Function OnTimeEx(EarliestTime As Variant, Procedure As String, Optional ByVal ParamObject As Variant) As Long
指定した標準モジュールのプロシージャを指定時間に実行する
※Application.OnTimeからの置換用、ただしProcedure内での引数指定("'<プロシージャ名> ""<引数>""'"、これは引数をParamObjectとして別に指定することで対応のこと)や、LatestTime、Scheduleパラメーターは未サポート
引数:
EarliestTime: プロシージャを実行する時刻
Procedure: 実行するプロシージャ名
ParamObject(オプション): 実行時にパラメータとして渡すオブジェクト(Collection や Dictionary 等、文字列や数値も可能)
戻り値: タイマーID
※該当コールバック識別用のIDとして使用
Public Function CancelCallback(TimerId)
SetCallback() で設定したコールバックを取り消す
引数:
TimerId: SetCallback() により返されたタイマーIDを指定
戻り値: (なし)
テスト用標準モジュール(Mod_TestCallback.vba)とテスト用クラスモジュール(Cls_TestCallback.vba)を用いてテストした結果は以下のような感じでした。
Application.OnTime で同じことをやった場合よりもコールバックの遅延が小さいような気がしなくもないですね。