I've used a Windows multimedia dll to created a high resolution timer with
timSetEvent()
But the timeSetEvent()
page recommends the use of:
CreateTimerQueueTimer()
How can I use CreateTimerQueueTimer() to execute a method every 10 milliseconds in C#?
Here is a link to a C# wrapper for CreateTimerQueueTimer
:
http://social.msdn.microsoft.com/Forums/en-CA/csharpgeneral/thread/822aed2d-dca0-4a8e-8130-20fab69557d2
(scroll down to the last post by Hobz
for the sample class)
I just tried this out myself and it works fine. One thing you'll need to add, though, is a call to timeBeginPeriod(1)
before starting the timer in order to set your system to high-resolution. timeSetEvent
calls timeBeginPeriod
internally, which is why some people mistakenly assume that it creates a higher-resolution timer.
The callback passed to CreateTimerQueueTimer is expected to be an unmanaged function which will exist for the lifetime of the callbacks. The managed delegate can move about in memory but the underlying stub created by the marshalling will not do this so there is no need to pin the delegate. There is however a need to keep the delegate from being garbage collected since the pointer from unmanaged code is not sufficient to keep it alive. You must therefore ensure that either the delegate is kept alive by some managed reference being maintained (Perhaps through the use of GCHandle
The PVOID Parameter which is passed to the callback function must be fixed in memory since again, the unmanaged function expects it not to move about after the function returns. In .Net this pinning happens (efficiently) automatically but only for the life of the called function. Thus if you are using a reference to some managed object (say by getting an IntPtr to it) the underlying object must be pinned (again the GCHandle can be used for that in a subtly different way). To see if this is the problem try using IntPtr.Zero as the parameter to test if it works.
If this solves things you will need to either allocate your parameter as raw bytes in the unmanaged heap (and marshal accordingly), use some blittable type that is safe to put into something of size PVOID (like an Int32) or use the GCHandle technique above to maintain a stable pointer to a managed instance, this will have significant performance implications if done wrongly.
It's better to use timeSetEvent because its results are more consistent. On average modern hardware, for small intervals, the deviations in length of the intervals are about ten times smaller than when using CreateTimerQueueTimer. And that's assuming you didn't forget to increase the timer resolution before calling CreateTimerQueueTimer, otherwise the difference would be even bigger. So use timeSetEvent instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With