using System;
using System.Runtime.InteropServices;

namespace Vanara.PInvoke
{
	public static partial class Kernel32
	{
		/// <summary>
		/// 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.
		/// </summary>
		/// <param name="lpParameter">
		/// The thread data passed to the function using a parameter of the CreateTimerQueueTimer or RegisterWaitForSingleObject function.
		/// </param>
		/// <param name="TimerOrWaitFired">
		/// 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.)
		/// </param>
		// 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);

		/// <summary>The flags that control execution.</summary>
		public enum WT
		{
			/// <summary>
			/// By default, the callback function is queued to a non-I/O worker thread.
			/// <para>
			/// 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.
			/// </para>
			/// </summary>
			WT_EXECUTEDEFAULT = 0x00000000,

			/// <summary>
			/// This flag is not used.
			/// <para>
			/// 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.
			/// </para>
			/// </summary>
			WT_EXECUTEINIOTHREAD = 0x00000001,

			/// <summary>Undocumented.</summary>
			WT_EXECUTEINUITHREAD = 0x00000002,

			/// <summary>
			/// 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.
			/// <para>
			/// 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.
			/// </para>
			/// </summary>
			WT_EXECUTEINWAITTHREAD = 0x00000004,

			/// <summary>The timer will be set to the signaled state only once. If this flag is set, the Period parameter must be zero.</summary>
			WT_EXECUTEONLYONCE = 0x00000008,

			/// <summary>
			/// 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.
			/// <para>The callback function is queued as an APC. It should not perform alertable wait operations.</para>
			/// </summary>
			WT_EXECUTEINTIMERTHREAD = 0x00000020,

			/// <summary>
			/// The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.
			/// </summary>
			WT_EXECUTELONGFUNCTION = 0x00000010,

			/// <summary>Undocumented.</summary>
			WT_EXECUTEINPERSISTENTIOTHREAD = 0x00000040,

			/// <summary>
			/// 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.
			/// <para>
			/// Note that currently no worker thread is truly persistent, although worker threads do not terminate if there are any pending
			/// I/O requests.
			/// </para>
			/// </summary>
			WT_EXECUTEINPERSISTENTTHREAD = 0x00000080,

			/// <summary>
			/// 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.
			/// <para>Windows XP: This flag is not supported until Windows XP SP2 and Windows Server 2003.</para>
			/// </summary>
			WT_TRANSFER_IMPERSONATION = 0x00000100,

			/// <summary>
			/// The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.
			/// </summary>
			WT_EXECUTEINLONGTHREAD = 0x00000010,

			/// <summary>The timer will be set to the signaled state only once. If this flag is set, the Period parameter must be zero.</summary>
			WT_EXECUTEDELETEWAIT = 0x00000008,
		}

		/// <summary>
		/// 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.
		/// </summary>
		/// <param name="FileHandle">
		/// A handle to the file opened for overlapped I/O completion. This handle is returned by the <c>CreateFile</c> function, with the
		/// <c>FILE_FLAG_OVERLAPPED</c> flag.
		/// </param>
		/// <param name="Function">
		/// <para>
		/// 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 <c>TerminateThread</c> function.
		/// </para>
		/// <para>For more information about the completion routine, see <c>FileIOCompletionRoutine</c>.</para>
		/// </param>
		/// <param name="Flags">This parameter must be zero.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>
		/// If the function fails, the return value is zero. To get extended error information, call the <c>GetLastError</c> function. The
		/// value returned is an <c>NTSTATUS</c> error code. To retrieve the corresponding system error code, use the
		/// <c>RtlNtStatusToDosError</c> function.
		/// </para>
		/// </returns>
		// 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);

		/// <summary>Updates a timer-queue timer that was created by the <c>CreateTimerQueueTimer</c> function.</summary>
		/// <param name="TimerQueue">
		/// <para>A handle to the timer queue. This handle is returned by the <c>CreateTimerQueue</c> function.</para>
		/// <para>If this parameter is <c>NULL</c>, the timer is associated with the default timer queue.</para>
		/// </param>
		/// <param name="Timer">A handle to the timer-queue timer. This handle is returned by the <c>CreateTimerQueueTimer</c> function.</param>
		/// <param name="DueTime">The time after which the timer should expire, in milliseconds.</param>
		/// <param name="Period">
		/// 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 <c>DeleteTimerQueueTimer</c> function or reset using <c>ChangeTimerQueueTimer</c>.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// 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);

		/// <summary>
		/// 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.
		/// </summary>
		/// <returns>
		/// <para>
		/// 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.
		/// </para>
		/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// 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();

		/// <summary>
		/// 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.
		/// </summary>
		/// <param name="phNewTimer">
		/// 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 <c>DeleteTimerQueueTimer</c>.
		/// </param>
		/// <param name="TimerQueue">
		/// <para>A handle to the timer queue. This handle is returned by the <c>CreateTimerQueue</c> function.</para>
		/// <para>If this parameter is <c>NULL</c>, the timer is associated with the default timer queue.</para>
		/// </param>
		/// <param name="Callback">
		/// A pointer to the application-defined function of type <c>WAITORTIMERCALLBACK</c> to be executed when the timer expires. For more
		/// information, see <c>WaitOrTimerCallback</c>.
		/// </param>
		/// <param name="Parameter">A single parameter value that will be passed to the callback function.</param>
		/// <param name="DueTime">
		/// The amount of time in milliseconds relative to the current time that must elapse before the timer is signaled for the first time.
		/// </param>
		/// <param name="Period">
		/// 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.
		/// </param>
		/// <param name="Flags">
		/// <para>This parameter can be one or more of the following values from WinNT.h.</para>
		/// <para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>WT_EXECUTEDEFAULT0x00000000</term>
		/// <term>By default, the callback function is queued to a non-I/O worker thread.</term>
		/// </item>
		/// <item>
		/// <term>WT_EXECUTEINTIMERTHREAD0x00000020</term>
		/// <term>
		/// 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.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WT_EXECUTEINIOTHREAD0x00000001</term>
		/// <term>
		/// 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.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WT_EXECUTEINPERSISTENTTHREAD0x00000080</term>
		/// <term>
		/// 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.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WT_EXECUTELONGFUNCTION0x00000010</term>
		/// <term>The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.</term>
		/// </item>
		/// <item>
		/// <term>WT_EXECUTEONLYONCE0x00000008</term>
		/// <term>The timer will be set to the signaled state only once. If this flag is set, the Period parameter must be zero.</term>
		/// </item>
		/// <item>
		/// <term>WT_TRANSFER_IMPERSONATION0x00000100</term>
		/// <term>
		/// 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.
		/// </term>
		/// </item>
		/// </list>
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// 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);

		/// <summary>Deletes a timer queue. Any pending timers in the queue are canceled and deleted.</summary>
		/// <param name="TimerQueue">A handle to the timer queue. This handle is returned by the <c>CreateTimerQueue</c> function.</param>
		/// <param name="CompletionEvent">
		/// <para>
		/// A handle to the event object to be signaled when the function is successful and all callback functions have completed. This
		/// parameter can be <c>NULL</c>.
		/// </para>
		/// <para>If this parameter is <c>INVALID_HANDLE_VALUE</c>, the function waits for all callback functions to complete before returning.</para>
		/// <para>
		/// If this parameter is <c>NULL</c>, 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.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// 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);

		/// <summary>
		/// Removes a timer from the timer queue and optionally waits for currently running timer callback functions to complete before
		/// deleting the timer.
		/// </summary>
		/// <param name="TimerQueue">
		/// <para>A handle to the timer queue. This handle is returned by the <c>CreateTimerQueue</c> function.</para>
		/// <para>If the timer was created using the default timer queue, this parameter should be <c>NULL</c>.</para>
		/// </param>
		/// <param name="Timer">A handle to the timer-queue timer. This handle is returned by the <c>CreateTimerQueueTimer</c> function.</param>
		/// <param name="CompletionEvent">
		/// <para>
		/// 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 <c>NULL</c>.
		/// </para>
		/// <para>
		/// If this parameter is <c>INVALID_HANDLE_VALUE</c>, the function waits for any running timer callback functions to complete before returning.
		/// </para>
		/// <para>
		/// If this parameter is <c>NULL</c>, 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.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>
		/// If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>. If the error code
		/// is <c>ERROR_IO_PENDING</c>, it is not necessary to call this function again. For any other error, you should retry the call.
		/// </para>
		/// </returns>
		// 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);

		/// <summary>Queues a work item to a worker thread in the thread pool.</summary>
		/// <param name="Function">
		/// 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.
		/// <para>For more information, see ThreadProc.</para>
		/// </param>
		/// <param name="Context">A single parameter value to be passed to the thread function.</param>
		/// <param name="Flags">The flags that control execution. This parameter can be one or more of the following values.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// 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);

		/// <summary>
		/// <para>
		/// 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:
		/// </para>
		/// <list type="bullet">
		///   <item>
		///     <term>The specified object is in the signaled state.</term>
		///   </item>
		///   <item>
		///     <term>The time-out interval elapses.</term>
		///   </item>
		/// </list>
		/// </summary>
		/// <param name="phNewWaitObject">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.</param>
		/// <param name="hObject"><para>A handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.</para>
		/// <para>If this handle is closed while the wait is still pending, the function's behavior is undefined.</para>
		/// <para>The handles must have the <c>SYNCHRONIZE</c> access right. For more information, see Standard Access Rights.</para></param>
		/// <param name="Callback">A pointer to the application-defined function of type <c>WAITORTIMERCALLBACK</c> to be executed when hObject is in the signaled
		/// state, or dwMilliseconds elapses. For more information, see WaitOrTimerCallback.</param>
		/// <param name="Context">A single value that is passed to the callback function.</param>
		/// <param name="dwMilliseconds">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 <c>INFINITE</c>,
		/// the function's time-out interval never elapses.</param>
		/// <param name="dwFlags"><para>This parameter can be one or more of the following values.</para>
		/// <para>For information about using these values with objects that remain signaled, see the Remarks section.</para>
		/// <list type="table">
		///   <listheader>
		///     <term>Value</term>
		///     <term>Meaning</term>
		///   </listheader>
		///   <item>
		///     <term>WT_EXECUTEDEFAULT 0x00000000</term>
		///     <term>By default, the callback function is queued to a non-I/O worker thread.</term>
		///   </item>
		///   <item>
		///     <term>WT_EXECUTEINIOTHREAD 0x00000001</term>
		///     <term>
		/// 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.
		/// </term>
		///   </item>
		///   <item>
		///     <term>WT_EXECUTEINPERSISTENTTHREAD 0x00000080</term>
		///     <term>
		/// 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.
		/// </term>
		///   </item>
		///   <item>
		///     <term>WT_EXECUTEINWAITTHREAD 0x00000004</term>
		///     <term>
		/// 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.
		/// </term>
		///   </item>
		///   <item>
		///     <term>WT_EXECUTELONGFUNCTION 0x00000010</term>
		///     <term>The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.</term>
		///   </item>
		///   <item>
		///     <term>WT_EXECUTEONLYONCE 0x00000008</term>
		///     <term>
		/// 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.
		/// </term>
		///   </item>
		///   <item>
		///     <term>WT_TRANSFER_IMPERSONATION 0x00000100</term>
		///     <term>
		/// 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.
		/// </term>
		///   </item>
		/// </list></param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// 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 <c>WT_EXECUTEONLYONCE</c>, the timer is reset every time the event is signaled or the time-out interval elapses.
		/// </para>
		/// <para>
		/// When the wait is completed, you must call the UnregisterWait or UnregisterWaitEx function to cancel the wait operation. (Even
		/// wait operations that use <c>WT_EXECUTEONLYONCE</c> must be canceled.) Do not make a blocking call to either of these functions
		/// from within the callback function.
		/// </para>
		/// <para>
		/// Note that you should not pulse an event object passed to <c>RegisterWaitForSingleObject</c>, 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 <c>WT_EXECUTEONLYONCE</c> or <c>WT_EXECUTEINWAITTHREAD</c> flag. For other
		/// flags, the callback function might be called too many times before the event is reset.
		/// </para>
		/// <para>
		/// 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.
		/// </para>
		/// <para>The <c>RegisterWaitForSingleObject</c> function can wait for the following objects:</para>
		/// <list type="bullet">
		///   <item>
		///     <term>Change notification</term>
		///   </item>
		///   <item>
		///     <term>Console input</term>
		///   </item>
		///   <item>
		///     <term>Event</term>
		///   </item>
		///   <item>
		///     <term>Memory resource notification</term>
		///   </item>
		///   <item>
		///     <term>Mutex</term>
		///   </item>
		///   <item>
		///     <term>Process</term>
		///   </item>
		///   <item>
		///     <term>Semaphore</term>
		///   </item>
		///   <item>
		///     <term>Thread</term>
		///   </item>
		///   <item>
		///     <term>Waitable timer</term>
		///   </item>
		/// </list>
		/// <para>For more information, see Synchronization Objects.</para>
		/// <para>
		/// By default, the thread pool has a maximum of 500 threads. To raise this limit, use the <c>WT_SET_MAX_THREADPOOL_THREAD</c> macro
		/// defined in WinNT.h.
		/// </para>
		/// <para>
		/// Use this macro when specifying the dwFlags parameter. The macro parameters are the desired flags and the new limit (up to
		/// (2&lt;&lt;16)-1 threads). However, note that your application can improve its performance by keeping the number of worker threads low.
		/// </para>
		/// <para>
		/// 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
		/// <c>WT_EXECUTEINPERSISTENTTHREAD</c> using the QueueUserWorkItem function.)
		/// </para>
		/// <para>
		/// To compile an application that uses this function, define <c>_WIN32_WINNT</c> as 0x0500 or later. For more information, see Using
		/// the Windows Headers.
		/// </para>
		/// </remarks>
		// 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);

		/// <summary>Gets a value that combines <see cref="WT"/> flags values with a new maximum threadpool thread count limit.</summary>
		/// <param name="Flags">The desired flags.</param>
		/// <param name="Limit">The threadpool thread count limit. The default is 500.</param>
		/// <returns>A <see cref="WT"/> value that has been augmented with the limit.</returns>
		public static WT WT_SET_MAX_THREADPOOL_THREADS(WT Flags, ushort Limit) => Flags | (WT)((uint)Limit << 16);

		/// <summary>Cancels a registered wait operation issued by the <c>RegisterWaitForSingleObject</c> function.</summary>
		/// <param name="WaitHandle">The wait handle. This handle is returned by the <c>RegisterWaitForSingleObject</c> function.</param>
		/// <param name="CompletionEvent">
		/// <para>A handle to the event object to be signaled when the wait operation has been unregistered. This parameter can be <c>NULL</c>.</para>
		/// <para>If this parameter is <c>INVALID_HANDLE_VALUE</c>, the function waits for all callback functions to complete before returning.</para>
		/// <para>
		/// If this parameter is <c>NULL</c>, 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.
		/// </para>
		/// <para>
		/// If the caller provides this event and the function succeeds or the function fails with <c>ERROR_IO_PENDING</c>, do not close the
		/// event until it is signaled.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
		/// </returns>
		// 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);

		/// <summary>Provides a handle to a timer queue.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct TimerQueueHandle : IHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="TimerQueueHandle"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public TimerQueueHandle(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="TimerQueueHandle"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static TimerQueueHandle NULL => new TimerQueueHandle(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="TimerQueueHandle"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(TimerQueueHandle h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="TimerQueueHandle"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator TimerQueueHandle(IntPtr h) => new TimerQueueHandle(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(TimerQueueHandle h1, TimerQueueHandle h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(TimerQueueHandle h1, TimerQueueHandle h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is TimerQueueHandle h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>Provides a handle to a timer queue timer.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct TimerQueueTimerHandle : IHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="TimerQueueTimerHandle"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public TimerQueueTimerHandle(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="TimerQueueTimerHandle"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static TimerQueueTimerHandle NULL => new TimerQueueTimerHandle(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="TimerQueueTimerHandle"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(TimerQueueTimerHandle h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="TimerQueueTimerHandle"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator TimerQueueTimerHandle(IntPtr h) => new TimerQueueTimerHandle(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(TimerQueueTimerHandle h1, TimerQueueTimerHandle h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(TimerQueueTimerHandle h1, TimerQueueTimerHandle h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is TimerQueueTimerHandle h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>
		/// Provides a <see cref="SafeHandle"/> to a timer queue that releases a created TimerQueueHandle instance at disposal using CloseHandle.
		/// </summary>
		public class SafeTimerQueueHandle : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="TimerQueueHandle"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeTimerQueueHandle(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			private SafeTimerQueueHandle() : base() { }

			/// <summary>Gets or sets the completion event associated with the disposal or closure of this timer queue.</summary>
			/// <value>
			/// <para>
			/// A handle to the event object to be signaled when the function is successful and all callback functions have completed. This
			/// parameter can be <see langword="null"/>.
			/// </para>
			/// <para>
			/// If this parameter is <see cref="SafeEventHandle.InvalidHandle"/>, the function waits for all callback functions to complete before returning.
			/// </para>
			/// <para>
			/// If this parameter is <see langword="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.
			/// </para>
			/// </value>
			public SafeEventHandle CompletionEvent { get; set; }

			/// <summary>Performs an implicit conversion from <see cref="SafeTimerQueueHandle"/> to <see cref="TimerQueueHandle"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator TimerQueueHandle(SafeTimerQueueHandle h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => DeleteTimerQueueEx(this, CompletionEvent ?? SafeEventHandle.Null);
		}
	}
}