Timer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / Timer.cs / 1305376 / Timer.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms {
    using System.Threading; 
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics; 
    using System.Windows.Forms.Design;
    using System; 
    using System.Globalization; 

    ///  
    /// 
    ///    Implements a Windows-based timer that raises an event at user-defined intervals. This timer is optimized for
    ///       use in Win Forms
    ///       applications and must be used in a window. 
    /// 
    [ 
    DefaultProperty("Interval"), 
    DefaultEvent("Tick"),
    ToolboxItemFilter("System.Windows.Forms"), 
    SRDescription(SR.DescriptionTimer)
    ]
    public class Timer : Component {
 
        /// 
        ///  
        ///  
        private int interval;
 
        /// 
        /// 
        /// 
        private bool enabled; 

        ///  
        ///  
        /// 
        private EventHandler onTimer; 

        /// 
        /// 
        ///  
        private GCHandle timerRoot;
 
 
        // our holder for the HWND that handles our Timer messages.
        // 
        private TimerNativeWindow timerWindow;

        /// 
        ///  
        /// 
        private object userData; 
 
        private object syncObj = new object();
 
        /// 
        /// 
        /// Initializes a new instance of the 
        /// class. 
        /// 
        public Timer() 
        : base() { 
            interval = 100;
        } 

        /// 
        /// 
        /// Initializes a new instance of the  class with the specified container. 
        /// 
        public Timer(IContainer container) : this() { 
            if (container == null) { 
                throw new ArgumentNullException("container");
            } 

            container.Add(this);
        }
 
        /// 
        [ 
        SRCategory(SR.CatData), 
        Localizable(false),
        Bindable(true), 
        SRDescription(SR.ControlTagDescr),
        DefaultValue(null),
        TypeConverter(typeof(StringConverter)),
        ] 
        public object Tag {
            get { 
                return userData; 
            }
            set { 
                userData = value;
            }
        }
 
        /// 
        ///  
        ///    Occurs when the specified timer 
        ///       interval has elapsed and the timer is enabled.
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.TimerTimerDescr)]
        public event EventHandler Tick {
            add {
                onTimer += value; 
            }
            remove { 
                onTimer -= value; 
            }
        } 

       /// 
        /// 
        ///     
        ///       Disposes of the resources (other than memory) used by the timer.
        ///     
        ///  
        protected override void Dispose(bool disposing) {
            if (disposing) { 
                if (timerWindow != null) {
                    timerWindow.StopTimer();
                }
 
                Enabled = false;
            } 
            timerWindow = null; 
            base.Dispose(disposing);
        } 

        /// 
        /// 
        ///     Indicates whether the timer is 
        ///       running.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.TimerEnabledDescr)
        ]
        public virtual bool Enabled {
            get { 
                if (timerWindow == null) {
                    return enabled; 
                } 
                return  timerWindow.IsTimerRunning;
            } 

            set {
                lock(syncObj) {
 
                    if (enabled != value) {
 
                        enabled = value; 

                        // At runtime, enable or disable the corresponding Windows timer 
                        //
                        if (!DesignMode) {
                            if (value) {
 
                                // create the timer window if needed.
                                // 
                                if (timerWindow == null) { 

                                    timerWindow = new TimerNativeWindow(this); 
                                }

                                timerRoot = GCHandle.Alloc(this);
 
                                timerWindow.StartTimer(interval);
                            } 
                            else{ 
                                if (timerWindow != null){
                                    timerWindow.StopTimer(); 
                                }

                                if (timerRoot.IsAllocated) {
                                    timerRoot.Free(); 
                                }
 
                            } 
                        }
 

                    }
                }
 
            }
        } 
 
        /// 
        ///  
        ///    
        ///       Indicates the time, in milliseconds, between timer ticks.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(100), 
        SRDescription(SR.TimerIntervalDescr) 
        ]
        public int Interval { 
            get {
                return interval;
            }
            set { 
                lock(syncObj) {
                    if (value < 1) 
                        throw new ArgumentOutOfRangeException("Interval", SR.GetString(SR.TimerInvalidInterval, value, (0).ToString(CultureInfo.CurrentCulture))); 

                    if (interval != value) { 
                        interval = value;
                        if (Enabled) {

                            Debug.Assert(DesignMode || timerWindow != null, "Why don't we have a timer HWND?"); 
                            // just change the timer value, don't tear down the timer
                            // itself. 
                            // 
                            if (!DesignMode && timerWindow != null) {
                                timerWindow.RestartTimer(value); 
                            }
                        }
                    }
                } 
            }
        } 
 
        /// 
        ///  
        /// Raises the 
        /// event.
        /// 
        protected virtual void OnTick(EventArgs e) { 
            if (onTimer != null) onTimer(this, e);
        } 
 
        /// 
        ///  
        ///    Starts the
        ///       timer.
        /// 
        public void Start() { 
            Enabled = true;
        } 
 
        /// 
        ///  
        ///    Stops the
        ///       timer.
        /// 
        public void Stop() { 
            Enabled = false;
        } 
 
        /// 
        ///  
        ///     returns us as a string.
        /// 
        /// 
        public override string ToString() { 
            string s = base.ToString();
            return s + ", Interval: " + Interval.ToString(CultureInfo.CurrentCulture); 
        } 

 
        private class TimerNativeWindow : NativeWindow {


            // the timer that owns us 
            //
            private Timer _owner; 
 
            // our current id -- this is usally the same as TimerID but we also
            // use it as a flag of when our timer is running. 
            //
            private int   _timerID;

            // arbitrary timer ID. 
            //
            private static int    TimerID = 1; 
 
            // setting this when we are stopping the timer so someone can't restart it in the process.
            // 
            private bool _stoppingTimer;

            internal TimerNativeWindow(Timer owner) {
 
                this._owner = owner;
            } 
 
            ~TimerNativeWindow() {
 



                // note this call will work form the finalizer thread. 
                //
                StopTimer(); 
            } 

            public bool IsTimerRunning { 
                get {

                    return _timerID != 0 && Handle != IntPtr.Zero;
                } 
            }
 
 
            // Ensures that our HWND has been created.
            // 
            private bool EnsureHandle() {
                if (Handle == IntPtr.Zero) {

 
                    // we create a totally vanilla invisible window just for WM_TIMER messages.
                    // 
                    CreateParams cp = new CreateParams(); 
                    cp.Style = 0;
                    cp.ExStyle = 0; 
                    cp.ClassStyle = 0;
                    cp.Caption = GetType().Name;

                    // Message only windows are cheaper and have fewer issues than 
                    // full blown invisible windows.  But, they are only supported
                    // on NT. 
                    if (Environment.OSVersion.Platform == PlatformID.Win32NT) { 
                        cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE;
                    } 

                    CreateHandle(cp);
                }
                Debug.Assert(Handle != IntPtr.Zero, "Timer HWND creation failed!"); 
                return Handle != IntPtr.Zero;
            } 
 
            // Returns true if we need to marshal across threads to access this timer's HWND.
            // 
            private bool GetInvokeRequired(IntPtr hWnd) {
                if (hWnd != IntPtr.Zero) {
                    int pid;
                    int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid); 
                    int currentThread = SafeNativeMethods.GetCurrentThreadId();
                    return(hwndThread != currentThread); 
                } 
                return false;
            } 

            // change the interval of the timer without destroying the HWND.
            //
            public void RestartTimer(int newInterval) { 
                StopTimer(false, IntPtr.Zero);
                StartTimer(newInterval); 
            } 

            // Start the timer with the specified interval. 
            //
            public void StartTimer(int interval) {

                if (_timerID == 0 && !_stoppingTimer) { 
                    if (EnsureHandle()) {
                        _timerID = (int) SafeNativeMethods.SetTimer(new HandleRef(this, Handle), TimerID++, interval, IntPtr.Zero); 
                    } 
                }
            } 

            // stop the timer.
            //
            public void StopTimer() { 

                StopTimer(true, IntPtr.Zero); 
            } 

            // stop the timer and optionally destroy the HWND. 
            //
            public void StopTimer(bool destroyHwnd, IntPtr hWnd) {

 
                if (hWnd == IntPtr.Zero) {
 
                    hWnd = Handle; 
                }
 
                // Fire a message across threads to destroy the timer and HWND on the thread that created it.
                //
                if (GetInvokeRequired(hWnd)) {
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, hWnd), NativeMethods.WM_CLOSE, 0, 0); 
                    return;
                } 
 
                // Locking 'this' here is ok since this is an internal class.  See VSW#464499.
                lock(this) { 

                    if (_stoppingTimer || hWnd == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(new HandleRef(this, hWnd))) {

                        return; 
                    }
 
                    if (_timerID != 0) { 

 
                        try {
                            _stoppingTimer = true;
                            SafeNativeMethods.KillTimer(new HandleRef(this, hWnd), _timerID);
                        } 
                        finally {
                            _timerID = 0; 
                            _stoppingTimer = false; 
                        }
 
                    }

                    if (destroyHwnd) {
                        base.DestroyHandle(); 
                    }
                } 
            } 

            // Destroy the handle, stopping the timer first. 
            //
            public override void DestroyHandle() {
                // don't recurse!
                // 
                StopTimer(false, IntPtr.Zero);
                Debug.Assert(_timerID == 0, "Destroying handle with timerID still set."); 
                base.DestroyHandle(); 
            }
 
            protected override void OnThreadException(Exception e) {
                Application.OnThreadException(e);
            }
 
            public override void ReleaseHandle() {
                // don't recurse! 
                // 
                StopTimer(false, IntPtr.Zero);
                Debug.Assert(_timerID == 0, "Destroying handle with timerID still set."); 

                base.ReleaseHandle();
            }
 
            protected override void WndProc(ref Message m) {
 
                Debug.Assert(m.HWnd == Handle && Handle != IntPtr.Zero, "Timer getting messages for other windows?"); 

                // for timer messages, make sure they're ours (it'll be wierd if they aren't) 
                // and call the timer event.
                //
                if (m.Msg == NativeMethods.WM_TIMER) {
                    //Debug.Assert((int)m.WParam == _timerID, "Why are we getting a timer message that isn't ours?"); 
                    if (unchecked( (int) (long)m.WParam) == _timerID) {
                        _owner.OnTick(EventArgs.Empty); 
                        return; 
                    }
                } 
                else if (m.Msg == NativeMethods.WM_CLOSE) {
                    // this is a posted method from another thread that tells us we need
                    // to kill the timer.  The handle may already be gone, so we specify it here.
                    // 
                    StopTimer(true, m.HWnd);
                    return; 
                } 
                base.WndProc(ref m);
            } 

        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms {
    using System.Threading; 
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Diagnostics; 
    using System.Windows.Forms.Design;
    using System; 
    using System.Globalization; 

    ///  
    /// 
    ///    Implements a Windows-based timer that raises an event at user-defined intervals. This timer is optimized for
    ///       use in Win Forms
    ///       applications and must be used in a window. 
    /// 
    [ 
    DefaultProperty("Interval"), 
    DefaultEvent("Tick"),
    ToolboxItemFilter("System.Windows.Forms"), 
    SRDescription(SR.DescriptionTimer)
    ]
    public class Timer : Component {
 
        /// 
        ///  
        ///  
        private int interval;
 
        /// 
        /// 
        /// 
        private bool enabled; 

        ///  
        ///  
        /// 
        private EventHandler onTimer; 

        /// 
        /// 
        ///  
        private GCHandle timerRoot;
 
 
        // our holder for the HWND that handles our Timer messages.
        // 
        private TimerNativeWindow timerWindow;

        /// 
        ///  
        /// 
        private object userData; 
 
        private object syncObj = new object();
 
        /// 
        /// 
        /// Initializes a new instance of the 
        /// class. 
        /// 
        public Timer() 
        : base() { 
            interval = 100;
        } 

        /// 
        /// 
        /// Initializes a new instance of the  class with the specified container. 
        /// 
        public Timer(IContainer container) : this() { 
            if (container == null) { 
                throw new ArgumentNullException("container");
            } 

            container.Add(this);
        }
 
        /// 
        [ 
        SRCategory(SR.CatData), 
        Localizable(false),
        Bindable(true), 
        SRDescription(SR.ControlTagDescr),
        DefaultValue(null),
        TypeConverter(typeof(StringConverter)),
        ] 
        public object Tag {
            get { 
                return userData; 
            }
            set { 
                userData = value;
            }
        }
 
        /// 
        ///  
        ///    Occurs when the specified timer 
        ///       interval has elapsed and the timer is enabled.
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.TimerTimerDescr)]
        public event EventHandler Tick {
            add {
                onTimer += value; 
            }
            remove { 
                onTimer -= value; 
            }
        } 

       /// 
        /// 
        ///     
        ///       Disposes of the resources (other than memory) used by the timer.
        ///     
        ///  
        protected override void Dispose(bool disposing) {
            if (disposing) { 
                if (timerWindow != null) {
                    timerWindow.StopTimer();
                }
 
                Enabled = false;
            } 
            timerWindow = null; 
            base.Dispose(disposing);
        } 

        /// 
        /// 
        ///     Indicates whether the timer is 
        ///       running.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.TimerEnabledDescr)
        ]
        public virtual bool Enabled {
            get { 
                if (timerWindow == null) {
                    return enabled; 
                } 
                return  timerWindow.IsTimerRunning;
            } 

            set {
                lock(syncObj) {
 
                    if (enabled != value) {
 
                        enabled = value; 

                        // At runtime, enable or disable the corresponding Windows timer 
                        //
                        if (!DesignMode) {
                            if (value) {
 
                                // create the timer window if needed.
                                // 
                                if (timerWindow == null) { 

                                    timerWindow = new TimerNativeWindow(this); 
                                }

                                timerRoot = GCHandle.Alloc(this);
 
                                timerWindow.StartTimer(interval);
                            } 
                            else{ 
                                if (timerWindow != null){
                                    timerWindow.StopTimer(); 
                                }

                                if (timerRoot.IsAllocated) {
                                    timerRoot.Free(); 
                                }
 
                            } 
                        }
 

                    }
                }
 
            }
        } 
 
        /// 
        ///  
        ///    
        ///       Indicates the time, in milliseconds, between timer ticks.
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(100), 
        SRDescription(SR.TimerIntervalDescr) 
        ]
        public int Interval { 
            get {
                return interval;
            }
            set { 
                lock(syncObj) {
                    if (value < 1) 
                        throw new ArgumentOutOfRangeException("Interval", SR.GetString(SR.TimerInvalidInterval, value, (0).ToString(CultureInfo.CurrentCulture))); 

                    if (interval != value) { 
                        interval = value;
                        if (Enabled) {

                            Debug.Assert(DesignMode || timerWindow != null, "Why don't we have a timer HWND?"); 
                            // just change the timer value, don't tear down the timer
                            // itself. 
                            // 
                            if (!DesignMode && timerWindow != null) {
                                timerWindow.RestartTimer(value); 
                            }
                        }
                    }
                } 
            }
        } 
 
        /// 
        ///  
        /// Raises the 
        /// event.
        /// 
        protected virtual void OnTick(EventArgs e) { 
            if (onTimer != null) onTimer(this, e);
        } 
 
        /// 
        ///  
        ///    Starts the
        ///       timer.
        /// 
        public void Start() { 
            Enabled = true;
        } 
 
        /// 
        ///  
        ///    Stops the
        ///       timer.
        /// 
        public void Stop() { 
            Enabled = false;
        } 
 
        /// 
        ///  
        ///     returns us as a string.
        /// 
        /// 
        public override string ToString() { 
            string s = base.ToString();
            return s + ", Interval: " + Interval.ToString(CultureInfo.CurrentCulture); 
        } 

 
        private class TimerNativeWindow : NativeWindow {


            // the timer that owns us 
            //
            private Timer _owner; 
 
            // our current id -- this is usally the same as TimerID but we also
            // use it as a flag of when our timer is running. 
            //
            private int   _timerID;

            // arbitrary timer ID. 
            //
            private static int    TimerID = 1; 
 
            // setting this when we are stopping the timer so someone can't restart it in the process.
            // 
            private bool _stoppingTimer;

            internal TimerNativeWindow(Timer owner) {
 
                this._owner = owner;
            } 
 
            ~TimerNativeWindow() {
 



                // note this call will work form the finalizer thread. 
                //
                StopTimer(); 
            } 

            public bool IsTimerRunning { 
                get {

                    return _timerID != 0 && Handle != IntPtr.Zero;
                } 
            }
 
 
            // Ensures that our HWND has been created.
            // 
            private bool EnsureHandle() {
                if (Handle == IntPtr.Zero) {

 
                    // we create a totally vanilla invisible window just for WM_TIMER messages.
                    // 
                    CreateParams cp = new CreateParams(); 
                    cp.Style = 0;
                    cp.ExStyle = 0; 
                    cp.ClassStyle = 0;
                    cp.Caption = GetType().Name;

                    // Message only windows are cheaper and have fewer issues than 
                    // full blown invisible windows.  But, they are only supported
                    // on NT. 
                    if (Environment.OSVersion.Platform == PlatformID.Win32NT) { 
                        cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE;
                    } 

                    CreateHandle(cp);
                }
                Debug.Assert(Handle != IntPtr.Zero, "Timer HWND creation failed!"); 
                return Handle != IntPtr.Zero;
            } 
 
            // Returns true if we need to marshal across threads to access this timer's HWND.
            // 
            private bool GetInvokeRequired(IntPtr hWnd) {
                if (hWnd != IntPtr.Zero) {
                    int pid;
                    int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid); 
                    int currentThread = SafeNativeMethods.GetCurrentThreadId();
                    return(hwndThread != currentThread); 
                } 
                return false;
            } 

            // change the interval of the timer without destroying the HWND.
            //
            public void RestartTimer(int newInterval) { 
                StopTimer(false, IntPtr.Zero);
                StartTimer(newInterval); 
            } 

            // Start the timer with the specified interval. 
            //
            public void StartTimer(int interval) {

                if (_timerID == 0 && !_stoppingTimer) { 
                    if (EnsureHandle()) {
                        _timerID = (int) SafeNativeMethods.SetTimer(new HandleRef(this, Handle), TimerID++, interval, IntPtr.Zero); 
                    } 
                }
            } 

            // stop the timer.
            //
            public void StopTimer() { 

                StopTimer(true, IntPtr.Zero); 
            } 

            // stop the timer and optionally destroy the HWND. 
            //
            public void StopTimer(bool destroyHwnd, IntPtr hWnd) {

 
                if (hWnd == IntPtr.Zero) {
 
                    hWnd = Handle; 
                }
 
                // Fire a message across threads to destroy the timer and HWND on the thread that created it.
                //
                if (GetInvokeRequired(hWnd)) {
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, hWnd), NativeMethods.WM_CLOSE, 0, 0); 
                    return;
                } 
 
                // Locking 'this' here is ok since this is an internal class.  See VSW#464499.
                lock(this) { 

                    if (_stoppingTimer || hWnd == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(new HandleRef(this, hWnd))) {

                        return; 
                    }
 
                    if (_timerID != 0) { 

 
                        try {
                            _stoppingTimer = true;
                            SafeNativeMethods.KillTimer(new HandleRef(this, hWnd), _timerID);
                        } 
                        finally {
                            _timerID = 0; 
                            _stoppingTimer = false; 
                        }
 
                    }

                    if (destroyHwnd) {
                        base.DestroyHandle(); 
                    }
                } 
            } 

            // Destroy the handle, stopping the timer first. 
            //
            public override void DestroyHandle() {
                // don't recurse!
                // 
                StopTimer(false, IntPtr.Zero);
                Debug.Assert(_timerID == 0, "Destroying handle with timerID still set."); 
                base.DestroyHandle(); 
            }
 
            protected override void OnThreadException(Exception e) {
                Application.OnThreadException(e);
            }
 
            public override void ReleaseHandle() {
                // don't recurse! 
                // 
                StopTimer(false, IntPtr.Zero);
                Debug.Assert(_timerID == 0, "Destroying handle with timerID still set."); 

                base.ReleaseHandle();
            }
 
            protected override void WndProc(ref Message m) {
 
                Debug.Assert(m.HWnd == Handle && Handle != IntPtr.Zero, "Timer getting messages for other windows?"); 

                // for timer messages, make sure they're ours (it'll be wierd if they aren't) 
                // and call the timer event.
                //
                if (m.Msg == NativeMethods.WM_TIMER) {
                    //Debug.Assert((int)m.WParam == _timerID, "Why are we getting a timer message that isn't ours?"); 
                    if (unchecked( (int) (long)m.WParam) == _timerID) {
                        _owner.OnTick(EventArgs.Empty); 
                        return; 
                    }
                } 
                else if (m.Msg == NativeMethods.WM_CLOSE) {
                    // this is a posted method from another thread that tells us we need
                    // to kill the timer.  The handle may already be gone, so we specify it here.
                    // 
                    StopTimer(true, m.HWnd);
                    return; 
                } 
                base.WndProc(ref m);
            } 

        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK