c# waitable timer - wake up event fires instantly

336 views Asked by At

The following code example (from here) creates a waitable timer and set the system in hibernation mode. After resuming back I expected an event with executable code:

class WakeUpTimer
    {
        [DllImport("kernel32.dll")]
        public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes,
                                                          bool bManualReset,
                                                        string lpTimerName);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWaitableTimer(SafeWaitHandle hTimer,
                                                    [In] ref long pDueTime,
                                                              int lPeriod,
                                                           IntPtr pfnCompletionRoutine,
                                                           IntPtr lpArgToCompletionRoutine,
                                                             bool fResume);

        public event EventHandler Woken;

        private BackgroundWorker bgWorker = new BackgroundWorker();

        public WakeUpTimer()
        {
            bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
            bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
        }

        public void SetWakeUpTime(DateTime time)
        {
            bgWorker.RunWorkerAsync(time.ToFileTime());
        }

        void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (Woken != null)
            {
                Woken(this, new EventArgs());
            }
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            long waketime = (long)e.Argument;

            using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, this.GetType().Assembly.GetName().Name.ToString() + "Timer"))
            {
                if (SetWaitableTimer(handle, ref waketime, 0, IntPtr.Zero, IntPtr.Zero, true))
                {
                    using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset))
                    {
                        wh.SafeWaitHandle = handle;
                        wh.WaitOne();
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
        }

    }

Usage of this class is as follows:

private void setHibernation(DateTime dateTime)
        {
            WakeUpTimer wakeUpTimer = new WakeUpTimer();
            wakeUpTimer.Woken += backFromHibernate;
            wakeUpTimer.SetWakeUpTime(dateTime);
            Application.SetSuspendState(PowerState.Hibernate, false, false);
            Debug.WriteLine("---Hibernation starts at " + DateTime.Now + " ---");
        }

private void backFromHibernate(object sender, EventArgs e)
{
     Debug.WriteLine("I execute this now " + DateTime.Now);
}

As I tested before this scenario several times, the code in the method backFromHibernation is executed immediately (1 sec after setSupsendState duo to debug logs).

Am I wrong or should the method be called when the system is back up from hibernation?

Would appriciate some help, would need such an event - fired automatically after wake up.

EDIT: Set hibernation for 2 min, all works great system comes up automatically.

0

There are 0 answers