timeSetEvent の制限事項と不具合について
こんにちははらだんです。週末は雨というシーズンは終わりかな?という今日この頃です。いやもう終わってますね。週末雨の音を聞きながら部屋でごろごろしているのはわりと好きなのです。湿度が高くて暑いのはいやですが・・。
さて、本日は Multimedia API (mmsystem.h/winmm.lib)の timeSetEvent 関数についてのお話です。
お題:timeSetEvent の引数、 uDelay (イベント遅延)の最大値について
Windows XP の timeSetEvent() 関数には不具合があります。Windows Vista の timeSetEvent() には制限事項があります。
Windows XP の timeSetEvent() 関数について:
MSDN のtimeSetEvent() の記述では「タイマでサポートされるイベント遅延の最小値から最大値までの範囲にない場合、関数はエラーを返します。」とあります。範囲はタイマー デバイスに依存するというわけですが、実際にはソフトウェアつまり API レベルで 1000 秒が最大という制限があります。
しかし、Windows XP ではエラーを返さないにもかかわらず(実際にタイマーが設定されます)設定したイベント遅延よりもはるかに短い時間で発火する現象が発生することがあります。具体的には timeSetEvent の引数で TIME_PERIODIC を指定した場合イベント遅延時間は 429,496 ミリ秒が最大で、それより 1 ミリ秒大きくなるとオーバーフローによりイベント遅延時間が 1 ミリ秒に戻ります。
これは引数で受け取った uDelay (ミリ秒単位)を内部で 100ns (ナノ秒)単位の値として計算する際に 32bit の整数であつかうのが原因です。
429,496 (msec) = 4,294,960,000 (100nsec) = 0xFFFFE380
これに 1 ミリ秒を加算すると
429,497 (msec) = 4,294,970,000 (100nsec) = 0x100000A90
となり、繰り上がってオーバーフローするので実際には 0xA90 (100ns) となってしまいます。
わかりやすくおおむねの数値にすると約 7 分 9 秒が最大で、7 分 10 秒はオーバーフローして
即イベントが発火します。
Windows Vista の timeSetEvent() 関数について:
Windows Vista では実装が変わり、途中の計算で正しく 64bit であつかいます。上限はものすごい時間になるはずですが、実際は先に述べた 1000 秒に制限されます。つまり約 16 分 40 秒が上限となります。こちらは想定されている実装です。これ以上の時間を指定しようとするとタイマーは設定されません。
その他の OS についてもまとめますと、以下のようになります。
-
OS
オーバーフローの発生
1000 秒の制限
Windows XP
あり
あり
Windows Server 2003
あり
あり
Windows Vista
なし
あり
Windows Server 2008
なし
あり
XP についてはイベントのコールバック関数内で回数をカウントして 5 分のイベントを 3 回数えて 15 分のイベント遅延とするなどの対策が必要となります。ご不便おかけして申し訳ございません。
マルチメディア タイマーについては以下の記事もご参考ください。
次回はこれを実際にデバッガで確認するデバッグ例を紹介したいと思います。
※ 2009 年 9 月 3 日 追記
本件についてサポート技術情報が公開されましたのでお知らせいたします。