Getting accurate ticks from a timer in C#

前端 未结 6 897
北荒
北荒 2020-12-28 18:21

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

6条回答
  •  孤城傲影
    2020-12-28 19:03

    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
    

提交回复
热议问题