I\'m trying to rebuild an old metronome application that was originally written using MFC in C++ to be written in .NET using C#. One of the issues I\'m running into is gett
There are three timer classes called 'Timer' in .NET. It sounds like you're using the Windows Forms one, but actually you might find the System.Threading.Timer class more useful - but be careful because it calls back on a pool thread, so you can't directly interact with your form from the callback.
Another approach might be to p/invoke to the Win32 multimedia timers - timeGetTime, timeSetPeriod, etc.
A quick google found this, which might be useful http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx
'Multimedia' (timer) is the buzz-word to search for in this context.
Timer classes can start behaving strangely when the timer 'tick' event code is not finished executing by the time the next 'tick' occurs. One way to combat this is to disable the timer at the beginning of the tick event, then re-enable it at the end.
However, this approach is not suitable in cases where the execution time of the 'tick' code is not acceptable error in the timing of the tick, since the timer will be disabled (not counting) during that time.
If disabling the timer is an option, then you can also achieve the same effect by creating a separate thread that executes, sleeps for x milliseconds, executes, sleeps, etc...
What is the C++ application using? You can always use the same thing or wrap the timer code from C++ into a C++/CLI class.
System.Windows.Forms.Timer
is limited to an accuracy of 55 milliseconds...
I have had this problem when developing a recent data-logging project. The problem with the .NET timers ( windows.forms, system.threading, and system.timer ) is that they are only accurate down to around 10 milli seconds which is due to the event scheduling built into .NET I believe. ( I am talking about .NET 2 here ). This wasn't acceptable for me and so I had to use the multimedia timer ( you need to import the dll ). I also wrote a wrapper class for all the timers and so you can switch between them if necessary using minimal code changes. Check out my blog post here: http://www.indigo79.net/archives/27
Another possibility is that there is a bug in WPF implementation of DispatcherTimer (there is a mismatch between milliseconds and ticks causing potential inaccuracy depending on exact process execution time) , as evidenced below:
http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/DispatcherTimer.cs,143
class DispatcherTimer
{
public TimeSpan Interval
{
set
{
...
_interval = value;
// Notice below bug: ticks1 + milliseconds [Bug1]
_dueTimeInTicks = Environment.TickCount + (int)_interval.TotalMilliseconds;
}
}
}
http://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs
class Dispatcher
{
private object UpdateWin32TimerFromDispatcherThread(object unused)
{
...
_dueTimeInTicks = timer._dueTimeInTicks;
SetWin32Timer(_dueTimeInTicks);
}
private void SetWin32Timer(int dueTimeInTicks)
{
...
// Notice below bug: (ticks1 + milliseconds) - ticks2 [Bug2 - almost cancels Bug1, delta is mostly milliseconds not ticks]
int delta = dueTimeInTicks - Environment.TickCount;
SafeNativeMethods.SetTimer(
new HandleRef(this, _window.Value.Handle),
TIMERID_TIMERS,
delta); // <-- [Bug3 - if delta is ticks, it should be divided by TimeSpan.TicksPerMillisecond = 10000]
}
}
http://referencesource.microsoft.com/#WindowsBase/Shared/MS/Win32/SafeNativeMethodsCLR.cs,505
class SafeNativeMethodsPrivate
{
...
[DllImport(ExternDll.User32, SetLastError = true, ExactSpelling=true, CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr SetTimer(HandleRef hWnd, int nIDEvent, int uElapse, NativeMethods.TimerProc lpTimerFunc);
}
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906%28v=vs.85%29.aspx
uElapse [in]
Type: UINT
The time-out value, in milliseconds. // <-- milliseconds were needed eventually