using System; using System.Runtime.InteropServices; namespace Vanara.PInvoke { public static partial class Kernel32 { /// /// An application-defined function that serves as the starting address for a timer callback or a registered wait callback. Specify /// this address when calling the CreateTimerQueueTimer, RegisterWaitForSingleObject function. /// /// /// The thread data passed to the function using a parameter of the CreateTimerQueueTimer or RegisterWaitForSingleObject function. /// /// /// If this parameter is TRUE, the wait timed out. If this parameter is FALSE, the wait event has been signaled. (This parameter is /// always TRUE for timer callbacks.) /// // https://msdn.microsoft.com/en-us/library/windows/desktop/ms687066(v=vs.85).aspx [PInvokeData("WinBase.h", MSDNShortId = "ms687066")] [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void WaitOrTimerCallback(IntPtr lpParameter, [MarshalAs(UnmanagedType.U1)] bool TimerOrWaitFired); /// The flags that control execution. public enum WT { /// /// By default, the callback function is queued to a non-I/O worker thread. /// /// The callback function is queued to a thread that uses I/O completion ports, which means they cannot perform an alertable /// wait. Therefore, if I/O completes and generates an APC, the APC might wait indefinitely because there is no guarantee that /// the thread will enter an alertable wait state after the callback completes. /// /// WT_EXECUTEDEFAULT = 0x00000000, /// /// This flag is not used. /// /// Windows Server 2003 and Windows XP: The callback function is queued to an I/O worker thread. This flag should be used if the /// function should be executed in a thread that waits in an alertable state. I/O worker threads were removed starting with /// Windows Vista and Windows Server 2008. /// /// WT_EXECUTEINIOTHREAD = 0x00000001, /// Undocumented. WT_EXECUTEINUITHREAD = 0x00000002, /// /// The callback function is invoked by the wait thread itself. This flag should be used only for short tasks or it could affect /// other wait operations. /// /// Deadlocks can occur if some other thread acquires an exclusive lock and calls the UnregisterWait or UnregisterWaitEx function /// while the callback function is trying to acquire the same lock. /// /// WT_EXECUTEINWAITTHREAD = 0x00000004, /// The timer will be set to the signaled state only once. If this flag is set, the Period parameter must be zero. WT_EXECUTEONLYONCE = 0x00000008, /// /// The callback function is invoked by the timer thread itself. This flag should be used only for short tasks or it could affect /// other timer operations. /// The callback function is queued as an APC. It should not perform alertable wait operations. /// WT_EXECUTEINTIMERTHREAD = 0x00000020, /// /// The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. /// WT_EXECUTELONGFUNCTION = 0x00000010, /// Undocumented. WT_EXECUTEINPERSISTENTIOTHREAD = 0x00000040, /// /// The callback function is queued to a thread that never terminates. It does not guarantee that the same thread is used each /// time. This flag should be used only for short tasks or it could affect other timer operations. This flag must be set if the /// thread calls functions that use APCs. For more information, see Asynchronous Procedure Calls. /// /// Note that currently no worker thread is truly persistent, although worker threads do not terminate if there are any pending /// I/O requests. /// /// WT_EXECUTEINPERSISTENTTHREAD = 0x00000080, /// /// Callback functions will use the current access token, whether it is a process or impersonation token. If this flag is not /// specified, callback functions execute only with the process token. /// Windows XP: This flag is not supported until Windows XP SP2 and Windows Server 2003. /// WT_TRANSFER_IMPERSONATION = 0x00000100, /// /// The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. /// WT_EXECUTEINLONGTHREAD = 0x00000010, /// The timer will be set to the signaled state only once. If this flag is set, the Period parameter must be zero. WT_EXECUTEDELETEWAIT = 0x00000008, } /// /// Associates the I/O completion port owned by the thread pool with the specified file handle. On completion of an I/O request /// involving this file, a non-I/O worker thread will execute the specified callback function. /// /// /// A handle to the file opened for overlapped I/O completion. This handle is returned by the CreateFile function, with the /// FILE_FLAG_OVERLAPPED flag. /// /// /// /// A pointer to the callback function to be executed in a non-I/O worker thread when the I/O operation is complete. This callback /// function must not call the TerminateThread function. /// /// For more information about the completion routine, see FileIOCompletionRoutine. /// /// This parameter must be zero. /// /// If the function succeeds, the return value is nonzero. /// /// If the function fails, the return value is zero. To get extended error information, call the GetLastError function. The /// value returned is an NTSTATUS error code. To retrieve the corresponding system error code, use the /// RtlNtStatusToDosError function. /// /// // BOOL WINAPI BindIoCompletionCallback( _In_ HANDLE FileHandle, _In_ LPOVERLAPPED_COMPLETION_ROUTINE Function, _In_ ULONG Flags); https://msdn.microsoft.com/en-us/library/windows/desktop/aa363484(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "aa363484")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool BindIoCompletionCallback([In] HFILE FileHandle, FileIOCompletionRoutine Function, [Optional] uint Flags); /// Updates a timer-queue timer that was created by the CreateTimerQueueTimer function. /// /// A handle to the timer queue. This handle is returned by the CreateTimerQueue function. /// If this parameter is NULL, the timer is associated with the default timer queue. /// /// A handle to the timer-queue timer. This handle is returned by the CreateTimerQueueTimer function. /// The time after which the timer should expire, in milliseconds. /// /// The period of the timer, in milliseconds. If this parameter is zero, the timer is signaled once. If this parameter is greater /// than zero, the timer is periodic. A periodic timer automatically reactivates each time the period elapses, until the timer is /// canceled using the DeleteTimerQueueTimer function or reset using ChangeTimerQueueTimer. /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// // BOOL WINAPI ChangeTimerQueueTimer( _In_opt_ HANDLE TimerQueue, _Inout_ HANDLE Timer, _In_ ULONG DueTime, _In_ ULONG Period); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682004(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "ms682004")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ChangeTimerQueueTimer([In] TimerQueueHandle TimerQueue, TimerQueueTimerHandle Timer, uint DueTime, uint Period); /// /// Creates a queue for timers. Timer-queue timers are lightweight objects that enable you to specify a callback function to be /// called at a specified time. /// /// /// /// If the function succeeds, the return value is a handle to the timer queue. This handle can be used only in functions that require /// a handle to a timer queue. /// /// If the function fails, the return value is NULL. To get extended error information, call GetLastError. /// // HANDLE WINAPI CreateTimerQueue(void); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682483(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "ms682483")] public static extern SafeTimerQueueHandle CreateTimerQueue(); /// /// Creates a timer-queue timer. This timer expires at the specified due time, then after every specified period. When the timer /// expires, the callback function is called. /// /// /// A pointer to a buffer that receives a handle to the timer-queue timer on return. When this handle has expired and is no longer /// required, release it by calling DeleteTimerQueueTimer. /// /// /// A handle to the timer queue. This handle is returned by the CreateTimerQueue function. /// If this parameter is NULL, the timer is associated with the default timer queue. /// /// /// A pointer to the application-defined function of type WAITORTIMERCALLBACK to be executed when the timer expires. For more /// information, see WaitOrTimerCallback. /// /// A single parameter value that will be passed to the callback function. /// /// The amount of time in milliseconds relative to the current time that must elapse before the timer is signaled for the first time. /// /// /// The period of the timer, in milliseconds. If this parameter is zero, the timer is signaled once. If this parameter is greater /// than zero, the timer is periodic. A periodic timer automatically reactivates each time the period elapses, until the timer is canceled. /// /// /// This parameter can be one or more of the following values from WinNT.h. /// /// /// /// Value /// Meaning /// /// /// WT_EXECUTEDEFAULT0x00000000 /// By default, the callback function is queued to a non-I/O worker thread. /// /// /// WT_EXECUTEINTIMERTHREAD0x00000020 /// /// The callback function is invoked by the timer thread itself. This flag should be used only for short tasks or it could affect /// other timer operations. The callback function is queued as an APC. It should not perform alertable wait operations. /// /// /// /// WT_EXECUTEINIOTHREAD0x00000001 /// /// This flag is not used.Windows Server 2003 and Windows XP: The callback function is queued to an I/O worker thread. This flag /// should be used if the function should be executed in a thread that waits in an alertable state. I/O worker threads were removed /// starting with Windows Vista and Windows Server 2008. /// /// /// /// WT_EXECUTEINPERSISTENTTHREAD0x00000080 /// /// The callback function is queued to a thread that never terminates. It does not guarantee that the same thread is used each time. /// This flag should be used only for short tasks or it could affect other timer operations. This flag must be set if the thread /// calls functions that use APCs. For more information, see Asynchronous Procedure Calls.Note that currently no worker thread is /// truly persistent, although no worker thread will terminate if there are any pending I/O requests. /// /// /// /// WT_EXECUTELONGFUNCTION0x00000010 /// The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. /// /// /// WT_EXECUTEONLYONCE0x00000008 /// The timer will be set to the signaled state only once. If this flag is set, the Period parameter must be zero. /// /// /// WT_TRANSFER_IMPERSONATION0x00000100 /// /// Callback functions will use the current access token, whether it is a process or impersonation token. If this flag is not /// specified, callback functions execute only with the process token.Windows XP: This flag is not supported until Windows XP with /// SP2 and Windows Server 2003. /// /// /// /// /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// // BOOL WINAPI CreateTimerQueueTimer( _Out_ PHANDLE phNewTimer, _In_opt_ HANDLE TimerQueue, _In_ WAITORTIMERCALLBACK Callback, // _In_opt_ PVOID Parameter, _In_ DWORD DueTime, _In_ DWORD Period, _In_ ULONG Flags); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682485(v=vs.85).aspx [PInvokeData("WinBase.h", MSDNShortId = "ms682485")] [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CreateTimerQueueTimer(out TimerQueueTimerHandle phNewTimer, [In] TimerQueueHandle TimerQueue, WaitOrTimerCallback Callback, [In, Optional] IntPtr Parameter, uint DueTime, [Optional] uint Period, [Optional] WT Flags); /// Deletes a timer queue. Any pending timers in the queue are canceled and deleted. /// A handle to the timer queue. This handle is returned by the CreateTimerQueue function. /// /// /// A handle to the event object to be signaled when the function is successful and all callback functions have completed. This /// parameter can be NULL. /// /// If this parameter is INVALID_HANDLE_VALUE, the function waits for all callback functions to complete before returning. /// /// If this parameter is NULL, the function marks the timer for deletion and returns immediately. However, most callers should /// wait for the callback function to complete so they can perform any needed cleanup. /// /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// // BOOL WINAPI DeleteTimerQueueEx( _In_ HANDLE TimerQueue, _In_opt_ HANDLE CompletionEvent); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682568(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "ms682568")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteTimerQueueEx([In] TimerQueueHandle TimerQueue, [In] SafeEventHandle CompletionEvent); /// /// Removes a timer from the timer queue and optionally waits for currently running timer callback functions to complete before /// deleting the timer. /// /// /// A handle to the timer queue. This handle is returned by the CreateTimerQueue function. /// If the timer was created using the default timer queue, this parameter should be NULL. /// /// A handle to the timer-queue timer. This handle is returned by the CreateTimerQueueTimer function. /// /// /// A handle to the event object to be signaled when the system has canceled the timer and all callback functions have completed. /// This parameter can be NULL. /// /// /// If this parameter is INVALID_HANDLE_VALUE, the function waits for any running timer callback functions to complete before returning. /// /// /// If this parameter is NULL, the function marks the timer for deletion and returns immediately. If the timer has already /// expired, the timer callback function will run to completion. However, there is no notification sent when the timer callback /// function has completed. Most callers should not use this option, and should wait for running timer callback functions to complete /// so they can perform any needed cleanup. /// /// /// /// If the function succeeds, the return value is nonzero. /// /// If the function fails, the return value is zero. To get extended error information, call GetLastError. If the error code /// is ERROR_IO_PENDING, it is not necessary to call this function again. For any other error, you should retry the call. /// /// // BOOL WINAPI DeleteTimerQueueTimer( _In_opt_ HANDLE TimerQueue, _In_ HANDLE Timer, _In_opt_ HANDLE CompletionEvent); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682569(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "ms682569")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteTimerQueueTimer([In] TimerQueueHandle TimerQueue, [In] TimerQueueTimerHandle Timer, [In] SafeEventHandle CompletionEvent); /// Queues a work item to a worker thread in the thread pool. /// /// A pointer to the application-defined callback function of type LPTHREAD_START_ROUTINE to be executed by the thread in the thread /// pool. This value represents the starting address of the thread. This callback function must not call the TerminateThread function. /// For more information, see ThreadProc. /// /// A single parameter value to be passed to the thread function. /// The flags that control execution. This parameter can be one or more of the following values. /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684957(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] [PInvokeData("WinBase.h", MSDNShortId = "ms684957")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueueUserWorkItem(ThreadProc Function, [In] IntPtr Context, WT Flags); /// /// /// Directs a wait thread in the thread pool to wait on the object. The wait thread queues the specified callback function to the /// thread pool when one of the following occurs: /// /// /// /// The specified object is in the signaled state. /// /// /// The time-out interval elapses. /// /// /// /// A pointer to a variable that receives a wait handle on return. Note that a wait handle cannot be used in functions that require /// an object handle, such as CloseHandle. /// A handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section. /// If this handle is closed while the wait is still pending, the function's behavior is undefined. /// The handles must have the SYNCHRONIZE access right. For more information, see Standard Access Rights. /// A pointer to the application-defined function of type WAITORTIMERCALLBACK to be executed when hObject is in the signaled /// state, or dwMilliseconds elapses. For more information, see WaitOrTimerCallback. /// A single value that is passed to the callback function. /// The time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. /// If dwMilliseconds is zero, the function tests the object's state and returns immediately. If dwMilliseconds is INFINITE, /// the function's time-out interval never elapses. /// This parameter can be one or more of the following values. /// For information about using these values with objects that remain signaled, see the Remarks section. /// /// /// Value /// Meaning /// /// /// WT_EXECUTEDEFAULT 0x00000000 /// By default, the callback function is queued to a non-I/O worker thread. /// /// /// WT_EXECUTEINIOTHREAD 0x00000001 /// /// This flag is not used. Windows Server 2003 and Windows XP: The callback function is queued to an I/O worker thread. This flag /// should be used if the function should be executed in a thread that waits in an alertable state. I/O worker threads were removed /// starting with Windows Vista and Windows Server 2008. /// /// /// /// WT_EXECUTEINPERSISTENTTHREAD 0x00000080 /// /// The callback function is queued to a thread that never terminates. It does not guarantee that the same thread is used each time. /// This flag should be used only for short tasks or it could affect other wait operations. This flag must be set if the thread calls /// functions that use APCs. For more information, see Asynchronous Procedure Calls. Note that currently no worker thread is truly /// persistent, although no worker thread will terminate if there are any pending I/O requests. /// /// /// /// WT_EXECUTEINWAITTHREAD 0x00000004 /// /// The callback function is invoked by the wait thread itself. This flag should be used only for short tasks or it could affect /// other wait operations. Deadlocks can occur if some other thread acquires an exclusive lock and calls the UnregisterWait or /// UnregisterWaitEx function while the callback function is trying to acquire the same lock. /// /// /// /// WT_EXECUTELONGFUNCTION 0x00000010 /// The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. /// /// /// WT_EXECUTEONLYONCE 0x00000008 /// /// The thread will no longer wait on the handle after the callback function has been called once. Otherwise, the timer is reset /// every time the wait operation completes until the wait operation is canceled. /// /// /// /// WT_TRANSFER_IMPERSONATION 0x00000100 /// /// Callback functions will use the current access token, whether it is a process or impersonation token. If this flag is not /// specified, callback functions execute only with the process token. Windows XP: This flag is not supported until Windows XP with /// SP2 and Windows Server 2003. /// /// /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// /// /// /// New wait threads are created automatically when required. The wait operation is performed by a wait thread from the thread pool. /// The callback routine is executed by a worker thread when the object's state becomes signaled or the time-out interval elapses. If /// dwFlags is not WT_EXECUTEONLYONCE, the timer is reset every time the event is signaled or the time-out interval elapses. /// /// /// When the wait is completed, you must call the UnregisterWait or UnregisterWaitEx function to cancel the wait operation. (Even /// wait operations that use WT_EXECUTEONLYONCE must be canceled.) Do not make a blocking call to either of these functions /// from within the callback function. /// /// /// Note that you should not pulse an event object passed to RegisterWaitForSingleObject, because the wait thread might not /// detect that the event is signaled before it is reset. You should not register an object that remains signaled (such as a manual /// reset event or terminated process) unless you set the WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD flag. For other /// flags, the callback function might be called too many times before the event is reset. /// /// /// The function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled /// state caused the wait condition to be satisfied. For example, the count of a semaphore object is decreased by one. /// /// The RegisterWaitForSingleObject function can wait for the following objects: /// /// /// Change notification /// /// /// Console input /// /// /// Event /// /// /// Memory resource notification /// /// /// Mutex /// /// /// Process /// /// /// Semaphore /// /// /// Thread /// /// /// Waitable timer /// /// /// For more information, see Synchronization Objects. /// /// By default, the thread pool has a maximum of 500 threads. To raise this limit, use the WT_SET_MAX_THREADPOOL_THREAD macro /// defined in WinNT.h. /// /// /// Use this macro when specifying the dwFlags parameter. The macro parameters are the desired flags and the new limit (up to /// (2<<16)-1 threads). However, note that your application can improve its performance by keeping the number of worker threads low. /// /// /// The work item and all functions it calls must be thread-pool safe. Therefore, you cannot call an asynchronous call that requires /// a persistent thread, such as the RegNotifyChangeKeyValue function, from the default callback environment. Instead, set the thread /// pool maximum equal to the thread pool minimum using the SetThreadpoolThreadMaximum and SetThreadpoolThreadMinimum functions, or /// create your own thread using the CreateThread function. (For the original thread pool API, specify /// WT_EXECUTEINPERSISTENTTHREAD using the QueueUserWorkItem function.) /// /// /// To compile an application that uses this function, define _WIN32_WINNT as 0x0500 or later. For more information, see Using /// the Windows Headers. /// /// // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerwaitforsingleobject // BOOL RegisterWaitForSingleObject( PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags ); [PInvokeData("winbase.h", MSDNShortId = "d0cd8b28-6e20-449a-94dd-cca2be46b812")] public static bool RegisterWaitForSingleObject(out SafeRegisteredWaitHandle phNewWaitObject, ISyncHandle hObject, WaitOrTimerCallback Callback, IntPtr Context, uint dwMilliseconds, WT dwFlags) => RegisterWaitForSingleObject(out phNewWaitObject, hObject?.DangerousGetHandle() ?? IntPtr.Zero, Callback, Context, dwMilliseconds, dwFlags); /// Gets a value that combines flags values with a new maximum threadpool thread count limit. /// The desired flags. /// The threadpool thread count limit. The default is 500. /// A value that has been augmented with the limit. public static WT WT_SET_MAX_THREADPOOL_THREADS(WT Flags, ushort Limit) => Flags | (WT)((uint)Limit << 16); /// Cancels a registered wait operation issued by the RegisterWaitForSingleObject function. /// The wait handle. This handle is returned by the RegisterWaitForSingleObject function. /// /// A handle to the event object to be signaled when the wait operation has been unregistered. This parameter can be NULL. /// If this parameter is INVALID_HANDLE_VALUE, the function waits for all callback functions to complete before returning. /// /// If this parameter is NULL, the function marks the timer for deletion and returns immediately. However, most callers should /// wait for the callback function to complete so they can perform any needed cleanup. /// /// /// If the caller provides this event and the function succeeds or the function fails with ERROR_IO_PENDING, do not close the /// event until it is signaled. /// /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// // BOOL WINAPI UnregisterWaitEx( _In_ HANDLE WaitHandle, _In_opt_ HANDLE CompletionEvent); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686876(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [PInvokeData("LibLoaderAPI.h", MSDNShortId = "ms686876")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool UnregisterWaitEx([In] IntPtr WaitHandle, [In] SafeEventHandle CompletionEvent); [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool RegisterWaitForSingleObject(out SafeRegisteredWaitHandle phNewWaitObject, [In] IntPtr hObject, WaitOrTimerCallback Callback, [In] IntPtr Context, uint dwMilliseconds, WT dwFlags); /// Provides a handle to a timer queue. [StructLayout(LayoutKind.Sequential)] public struct TimerQueueHandle : IHandle { private IntPtr handle; /// Initializes a new instance of the struct. /// An object that represents the pre-existing handle to use. public TimerQueueHandle(IntPtr preexistingHandle) => handle = preexistingHandle; /// Returns an invalid handle by instantiating a object with . public static TimerQueueHandle NULL => new TimerQueueHandle(IntPtr.Zero); /// Gets a value indicating whether this instance is a null handle. public bool IsNull => handle == IntPtr.Zero; /// Performs an explicit conversion from to . /// The handle. /// The result of the conversion. public static explicit operator IntPtr(TimerQueueHandle h) => h.handle; /// Performs an implicit conversion from to . /// The pointer to a handle. /// The result of the conversion. public static implicit operator TimerQueueHandle(IntPtr h) => new TimerQueueHandle(h); /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(TimerQueueHandle h1, TimerQueueHandle h2) => !(h1 == h2); /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(TimerQueueHandle h1, TimerQueueHandle h2) => h1.Equals(h2); /// public override bool Equals(object obj) => obj is TimerQueueHandle h ? handle == h.handle : false; /// public override int GetHashCode() => handle.GetHashCode(); /// public IntPtr DangerousGetHandle() => handle; } /// Provides a handle to a timer queue timer. [StructLayout(LayoutKind.Sequential)] public struct TimerQueueTimerHandle : IHandle { private IntPtr handle; /// Initializes a new instance of the struct. /// An object that represents the pre-existing handle to use. public TimerQueueTimerHandle(IntPtr preexistingHandle) => handle = preexistingHandle; /// Returns an invalid handle by instantiating a object with . public static TimerQueueTimerHandle NULL => new TimerQueueTimerHandle(IntPtr.Zero); /// Gets a value indicating whether this instance is a null handle. public bool IsNull => handle == IntPtr.Zero; /// Performs an explicit conversion from to . /// The handle. /// The result of the conversion. public static explicit operator IntPtr(TimerQueueTimerHandle h) => h.handle; /// Performs an implicit conversion from to . /// The pointer to a handle. /// The result of the conversion. public static implicit operator TimerQueueTimerHandle(IntPtr h) => new TimerQueueTimerHandle(h); /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(TimerQueueTimerHandle h1, TimerQueueTimerHandle h2) => !(h1 == h2); /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(TimerQueueTimerHandle h1, TimerQueueTimerHandle h2) => h1.Equals(h2); /// public override bool Equals(object obj) => obj is TimerQueueTimerHandle h ? handle == h.handle : false; /// public override int GetHashCode() => handle.GetHashCode(); /// public IntPtr DangerousGetHandle() => handle; } /// /// Provides a to a timer queue that releases a created TimerQueueHandle instance at disposal using CloseHandle. /// public class SafeTimerQueueHandle : SafeHANDLE { /// Initializes a new instance of the class and assigns an existing handle. /// An object that represents the pre-existing handle to use. /// /// to reliably release the handle during the finalization phase; otherwise, (not recommended). /// public SafeTimerQueueHandle(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { } private SafeTimerQueueHandle() : base() { } /// Gets or sets the completion event associated with the disposal or closure of this timer queue. /// /// /// A handle to the event object to be signaled when the function is successful and all callback functions have completed. This /// parameter can be . /// /// /// If this parameter is , the function waits for all callback functions to complete before returning. /// /// /// If this parameter is , the function marks the timer for deletion and returns immediately. However, most /// callers should wait for the callback function to complete so they can perform any needed cleanup. /// /// public SafeEventHandle CompletionEvent { get; set; } /// Performs an implicit conversion from to . /// The safe handle instance. /// The result of the conversion. public static implicit operator TimerQueueHandle(SafeTimerQueueHandle h) => h.handle; /// protected override bool InternalReleaseHandle() => DeleteTimerQueueEx(this, CompletionEvent ?? SafeEventHandle.Null); } } }