Last active
June 4, 2024 10:57
-
-
Save KOZ60/bc903f37b8938b075087ade91d324672 to your computer and use it in GitHub Desktop.
WaitableTimer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Runtime.InteropServices; | |
using System.Threading; | |
using Microsoft.Win32.SafeHandles; | |
[DesignerCategory("code")] | |
public class WaitableTimer : Component | |
{ | |
private static object eventElapsed = new object(); | |
private long intervalTicks; | |
private bool enabled; | |
private readonly WaitbleTimerSlim hTimer; | |
private readonly EventWaitHandle cancelHandle = new ManualResetEvent(false); | |
private Thread thread; | |
public WaitableTimer() { | |
hTimer = new WaitbleTimerSlim(); | |
} | |
public WaitableTimer(IContainer container) : this() { | |
if (container == null) { | |
throw new ArgumentNullException("container"); | |
} | |
container.Add(this); | |
} | |
protected override void Dispose(bool disposing) { | |
base.Dispose(disposing); | |
hTimer.Dispose(); | |
cancelHandle.Dispose(); | |
} | |
public void Start() { | |
Enabled = true; | |
} | |
public void Stop() { | |
Enabled = false; | |
} | |
public bool Enabled { | |
get { | |
return enabled; | |
} | |
set { | |
if (enabled != value) { | |
enabled = value; | |
if (!DesignMode) { | |
if (value) { | |
cancelHandle.Reset(); | |
thread = new Thread(new ParameterizedThreadStart(Loop)); | |
thread.Start(this); | |
} else { | |
cancelHandle.Set(); | |
thread.Join(); | |
thread = null; | |
} | |
} | |
} | |
} | |
} | |
public long IntervalTicks { | |
get { | |
return intervalTicks; | |
} | |
set { | |
if (value < 0) { | |
throw new ArgumentException(); | |
} | |
intervalTicks = value; | |
} | |
} | |
public decimal IntervalMillisecond { | |
get { | |
return IntervalTicks / TimeSpan.TicksPerMillisecond; | |
} | |
set { | |
IntervalTicks = (long)(value * TimeSpan.TicksPerMillisecond); | |
} | |
} | |
protected virtual void OnElapsed(EventArgs e) { | |
var handler = (EventHandler)Events[eventElapsed]; | |
handler?.Invoke(this, e); | |
} | |
public event EventHandler Elapsed { | |
add { | |
Events.AddHandler(eventElapsed, value); | |
} | |
remove { | |
Events.RemoveHandler(eventElapsed, value); | |
} | |
} | |
private const int WAIT_1 = 1; | |
private static void Loop(object args) { | |
var owner = (WaitableTimer)args; | |
WaitHandle[] handles = new WaitHandle[] { owner.cancelHandle, owner.hTimer }; | |
long ticks = owner.IntervalTicks; | |
DateTime utc = DateTime.UtcNow; | |
long dueTime = utc.ToFileTimeUtc() + ticks; | |
owner.hTimer.SetWaitableTimer(dueTime, 0); | |
while (WaitHandle.WaitAny(handles) == WAIT_1) { | |
owner.OnElapsed(EventArgs.Empty); | |
dueTime += ticks; | |
owner.hTimer.SetWaitableTimer(dueTime, 0); | |
} | |
} | |
} | |
public class WaitbleTimerSlim : WaitHandle | |
{ | |
public WaitbleTimerSlim() { | |
var hTimer = CreateWaitableTimer(IntPtr.Zero, false, null); | |
if (hTimer == null || hTimer.IsInvalid) { | |
throw new Win32Exception(); | |
} | |
SafeWaitHandle = hTimer; | |
} | |
public void SetWaitableTimer(long dueTime, int period) { | |
if (!SetWaitableTimer(SafeWaitHandle, | |
ref dueTime, | |
period, | |
IntPtr.Zero, | |
IntPtr.Zero, false)) { | |
throw new Win32Exception(); | |
} | |
} | |
public void Cancel() { | |
if (!CancelWaitableTimer(SafeWaitHandle)) { | |
throw new Win32Exception(); | |
} | |
} | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] | |
private static extern SafeWaitHandle CreateWaitableTimer( | |
IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
private static extern bool SetWaitableTimer( | |
SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, | |
IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
private static extern bool CancelWaitableTimer(SafeWaitHandle hTimer); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment