diff --git a/PInvoke/Kernel32/ThreadPoolApiSet.cs b/PInvoke/Kernel32/ThreadPoolApiSet.cs
index 0b13f146..821cc1ec 100644
--- a/PInvoke/Kernel32/ThreadPoolApiSet.cs
+++ b/PInvoke/Kernel32/ThreadPoolApiSet.cs
@@ -13,40 +13,7 @@ namespace Vanara.PInvoke
/// Optional application-defined data specified during creation of the object.
/// Optional application-defined data specified using CloseThreadpoolCleanupGroupMembers.
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate void PTP_CLEANUP_GROUP_CANCEL_CALLBACK(IntPtr ObjectContext, IntPtr CleanupContext);
-
- /// Applications implement this callback if they call the TrySubmitThreadpoolCallback function to start a worker thread.
- ///
- /// A TP_CALLBACK_INSTANCE structure that defines the callback instance. Applications do not modify the members of this structure.
- ///
- /// The application-defined data.
- [UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate void PTP_SIMPLE_CALLBACK(PTP_CALLBACK_INSTANCE Instance, IntPtr Context);
-
- ///
- /// Applications implement this callback if they call the SetThreadpoolTimer function to start a worker thread for the timer object.
- ///
- ///
- /// A TP_CALLBACK_INSTANCE structure that defines the callback instance. Applications do not modify the members of this structure.
- ///
- /// The application-defined data.
- /// A TP_TIMER structure that defines the timer object that generated the callback.
- [UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate void PTP_TIMER_CALLBACK(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, PTP_TIMER Timer);
-
- ///
- /// Applications implement this callback if they call the SetThreadpoolWait function to start a worker thread for the wait object.
- ///
- ///
- /// A TP_CALLBACK_INSTANCE structure that defines the callback instance. Applications do not modify the members of this structure.
- ///
- /// The application-defined data.
- /// A TP_WAIT structure that defines the wait object that generated the callback.
- ///
- /// The result of the wait operation. This parameter can be one of the following values from WaitForMultipleObjects: WAIT_OBJECT_0, WAIT_TIMEOUT
- ///
- [UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate void PTP_WAIT_CALLBACK(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, PTP_WAIT Wait, uint WaitResult);
+ public delegate void CleanupGroupCancelCallback(IntPtr ObjectContext, IntPtr CleanupContext);
///
/// Applications implement this callback if they call the StartThreadpoolIo function to start a worker thread for the I/O completion object.
@@ -66,9 +33,42 @@ namespace Vanara.PInvoke
/// The number of bytes transferred during the I/O operation that has completed.
/// A TP_IO structure that defines the I/O completion object that generated the callback.
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate void PTP_WIN32_IO_CALLBACK(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, IntPtr Overlapped, uint IoResult,
+ public delegate void IoCompletionCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, IntPtr Overlapped, uint IoResult,
UIntPtr NumberOfBytesTransferred, PTP_IO Io);
+ /// Applications implement this callback if they call the TrySubmitThreadpoolCallback function to start a worker thread.
+ ///
+ /// A TP_CALLBACK_INSTANCE structure that defines the callback instance. Applications do not modify the members of this structure.
+ ///
+ /// The application-defined data.
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ public delegate void SimpleCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context);
+
+ ///
+ /// Applications implement this callback if they call the SetThreadpoolTimer function to start a worker thread for the timer object.
+ ///
+ ///
+ /// A TP_CALLBACK_INSTANCE structure that defines the callback instance. Applications do not modify the members of this structure.
+ ///
+ /// The application-defined data.
+ /// A TP_TIMER structure that defines the timer object that generated the callback.
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ public delegate void TimerCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, PTP_TIMER Timer);
+
+ ///
+ /// Applications implement this callback if they call the SetThreadpoolWait function to start a worker thread for the wait object.
+ ///
+ ///
+ /// A TP_CALLBACK_INSTANCE structure that defines the callback instance. Applications do not modify the members of this structure.
+ ///
+ /// The application-defined data.
+ /// A TP_WAIT structure that defines the wait object that generated the callback.
+ ///
+ /// The result of the wait operation. This parameter can be one of the following values from WaitForMultipleObjects: WAIT_OBJECT_0, WAIT_TIMEOUT
+ ///
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ public delegate void WaitCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, PTP_WAIT Wait, uint WaitResult);
+
///
/// Applications implement this callback if they call the SubmitThreadpoolWork function to start a worker thread for the work object.
///
@@ -78,7 +78,7 @@ namespace Vanara.PInvoke
/// The application-defined data.
/// A TP_WORK structure that defines the work object that generated the callback.
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
- public delegate void PTP_WORK_CALLBACK(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, PTP_WORK Work);
+ public delegate void WorkCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, PTP_WORK Work);
[Flags]
public enum TP_CALLBACK_ENV_FLAGS
@@ -175,7 +175,7 @@ namespace Vanara.PInvoke
// PVOID pvCleanupContext); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682036(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms682036")]
- public static extern void CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, [MarshalAs(UnmanagedType.Bool)] bool fCancelPendingCallbacks, IntPtr pvCleanupContext);
+ public static extern void CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, [MarshalAs(UnmanagedType.Bool)] bool fCancelPendingCallbacks, [Optional] IntPtr pvCleanupContext);
/// Releases the specified I/O completion object.
///
@@ -224,12 +224,28 @@ namespace Vanara.PInvoke
/// If the function succeeds, it returns a TP_POOL structure representing the newly allocated thread pool. Applications do not
/// modify the members of this structure.
///
- /// If function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ /// If function fails, it returns NULL. To retrieve extended error information, call GetLastError.
///
- // PTP_POOL WINAPI CreateThreadpool( _Reserved_ PVOID reserved); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682456(v=vs.85).aspx
+ ///
+ ///
+ /// After creating the new thread pool, you should call SetThreadpoolThreadMaximum to specify the maximum number of threads that the
+ /// pool can allocate and SetThreadpoolThreadMinimum to specify the minimum number of threads available in the pool.
+ ///
+ ///
+ /// To use the pool, you must associate the pool with a callback environment. To create the callback environment, call
+ /// InitializeThreadpoolEnvironment. Then, call SetThreadpoolCallbackPool to associate the pool with the callback environment.
+ ///
+ /// To release the thread pool, call CloseThreadpool.
+ /// To compile an application that uses this function, define _WIN32_WINNT as 0x0600 or higher.
+ /// Examples
+ /// For an example, see Using the Thread Pool Functions.
+ ///
+ // https://docs.microsoft.com/en-us/windows/win32/api/threadpoolapiset/nf-threadpoolapiset-createthreadpool PTP_POOL
+ // CreateThreadpool( PVOID reserved );
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
- [PInvokeData("WinBase.h", MSDNShortId = "ms682456")]
- public static extern PTP_POOL CreateThreadpool(IntPtr reserved = default);
+ [PInvokeData("threadpoolapiset.h", MSDNShortId = "cc00d7bf-ac52-44ff-a6a8-76c8eaace5e6")]
+ // public static extern PTP_POOL CreateThreadpool(IntPtr reserved);
+ public static extern SafePTP_POOL CreateThreadpool(IntPtr reserved = default);
/// Creates a cleanup group that applications can use to track one or more thread pool callbacks.
///
@@ -242,7 +258,7 @@ namespace Vanara.PInvoke
// PTP_CLEANUP_GROUP WINAPI CreateThreadpoolCleanupGroup(void); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682462(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms682462")]
- public static extern PTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup();
+ public static extern SafePTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup();
/// Creates a new I/O completion object.
/// The file handle to bind to this I/O completion object.
@@ -264,11 +280,11 @@ namespace Vanara.PInvoke
///
/// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
///
- // PTP_IO WINAPI CreateThreadpoolIo( _In_ HANDLE fl, _In_ PTP_WIN32_IO_CALLBACK pfnio, _Inout_opt_ PVOID pv, _In_opt_
+ // PTP_IO WINAPI CreateThreadpoolIo( _In_ HANDLE fl, _In_ IoCompletionCallback pfnio, _Inout_opt_ PVOID pv, _In_opt_
// PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682464(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms682464")]
- public static extern PTP_IO CreateThreadpoolIo(HFILE fl, PTP_WIN32_IO_CALLBACK pfnio, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+ public static extern SafePTP_IO CreateThreadpoolIo(HFILE fl, IoCompletionCallback pfnio, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
/// Creates a new timer object.
/// The callback function to call each time the timer object expires. For details, see TimerCallback.
@@ -287,10 +303,10 @@ namespace Vanara.PInvoke
///
/// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
///
- // PTP_TIMER WINAPI CreateThreadpoolTimer( _In_ PTP_TIMER_CALLBACK pfnti, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682466(v=vs.85).aspx
+ // PTP_TIMER WINAPI CreateThreadpoolTimer( _In_ TimerCallback pfnti, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682466(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms682466")]
- public static extern PTP_TIMER CreateThreadpoolTimer(PTP_TIMER_CALLBACK pfnti, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+ public static extern SafePTP_TIMER CreateThreadpoolTimer(TimerCallback pfnti, [Optional] IntPtr pv, [Optional] PTP_CALLBACK_ENVIRON pcbe);
/// Creates a new wait object.
/// The callback function to call when the wait completes or times out. For details, see WaitCallback.
@@ -309,10 +325,10 @@ namespace Vanara.PInvoke
///
/// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
///
- // PTP_WAIT WINAPI CreateThreadpoolWait( _In_ PTP_WAIT_CALLBACK pfnwa, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682474(v=vs.85).aspx
+ // PTP_WAIT WINAPI CreateThreadpoolWait( _In_ WaitCallback pfnwa, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682474(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms682474")]
- public static extern PTP_WAIT CreateThreadpoolWait(PTP_WAIT_CALLBACK pfnwa, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+ public static extern SafePTP_WAIT CreateThreadpoolWait(WaitCallback pfnwa, [Optional] IntPtr pv, [Optional] PTP_CALLBACK_ENVIRON pcbe);
/// Creates a new work object.
///
@@ -334,10 +350,10 @@ namespace Vanara.PInvoke
///
/// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
///
- // PTP_WORK WINAPI CreateThreadpoolWork( _In_ PTP_WORK_CALLBACK pfnwk, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682478(v=vs.85).aspx
+ // PTP_WORK WINAPI CreateThreadpoolWork( _In_ WorkCallback pfnwk, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682478(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms682478")]
- public static extern PTP_WORK CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+ public static extern SafePTP_WORK CreateThreadpoolWork(WorkCallback pfnwk, [Optional] IntPtr pv, [Optional] PTP_CALLBACK_ENVIRON pcbe);
///
/// Removes the association between the currently executing callback function and the object that initiated the callback. The current
@@ -457,7 +473,7 @@ namespace Vanara.PInvoke
// VOID SetThreadpoolCallbackCleanupGroup( _Inout_ PTP_CALLBACK_ENVIRON pcbe, _In_ PTP_CLEANUP_GROUP ptpcg, _In_opt_
// PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686255(v=vs.85).aspx
[PInvokeData("WinBase.h", MSDNShortId = "ms686255")]
- public static void SetThreadpoolCallbackCleanupGroup(this PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg, PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)
+ public static void SetThreadpoolCallbackCleanupGroup(this PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg, [Optional] CleanupGroupCancelCallback pfng)
{
pcbe.CleanupGroup = ptpcg;
pcbe.CleanupGroupCancelCallback = pfng;
@@ -621,7 +637,7 @@ namespace Vanara.PInvoke
// msWindowLength); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686271(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms686271")]
- public static extern void SetThreadpoolTimer(PTP_TIMER pti, in FILETIME pftDueTime, uint msPeriod, uint msWindowLength);
+ public static extern void SetThreadpoolTimer(PTP_TIMER pti, in FILETIME pftDueTime, [Optional] uint msPeriod, [Optional] uint msWindowLength);
///
/// Sets the timer object—, replacing the previous timer, if any. A worker thread calls the timer object's callback after the
@@ -659,7 +675,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("Threadpoolapiset.h", MSDNShortId = "dn894018")]
[return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool SetThreadpoolTimerEx(PTP_TIMER pti, in FILETIME pftDueTime, uint msPeriod, uint msWindowLength);
+ public static extern bool SetThreadpoolTimerEx(PTP_TIMER pti, in FILETIME pftDueTime, [Optional] uint msPeriod, [Optional] uint msWindowLength);
///
/// Sets the wait object—replacing the previous wait object, if any. A worker thread calls the wait object's callback function after
@@ -694,6 +710,72 @@ namespace Vanara.PInvoke
[PInvokeData("WinBase.h", MSDNShortId = "ms686273")]
public static extern void SetThreadpoolWait(PTP_WAIT pwa, SafeEventHandle h, in FILETIME pftTimeout);
+ ///
+ /// Sets the wait object—replacing the previous wait object, if any. A worker thread calls the wait object's callback function after
+ /// the handle becomes signaled or after the specified timeout expires.
+ ///
+ ///
+ /// A pointer to a TP_WAIT structure that defines the wait object. The CreateThreadpoolWait function returns this structure.
+ ///
+ ///
+ /// A handle.
+ ///
+ /// If this parameter is NULL, the wait object will cease to queue new callbacks (but callbacks already queued will still occur).
+ ///
+ /// If this parameter is not NULL, it must refer to a valid waitable object.
+ ///
+ /// If this handle is closed while the wait is still pending, the function's behavior is undefined. If the wait is still pending and
+ /// the handle must be closed, use CloseThreadpoolWait to cancel the wait and then close the handle.
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to a FILETIME structure that specifies the absolute or relative time at which the wait operation should time
+ /// out. If this parameter points to a positive value, it indicates the absolute time since January 1, 1601 (UTC), in 100-nanosecond
+ /// intervals. If this parameter points to a negative value, it indicates the amount of time to wait relative to the current time.
+ /// For more information about time values, see File Times.
+ ///
+ /// If this parameter points to 0, the wait times out immediately. If this parameter is NULL, the wait will not time out.
+ ///
+ /// This function does not return a value.
+ // VOID WINAPI SetThreadpoolWait( _Inout_ PTP_WAIT pwa, _In_opt_ HANDLE h, _In_opt_ PFILETIME pftTimeout); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686273(v=vs.85).aspx
+ [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
+ [PInvokeData("WinBase.h", MSDNShortId = "ms686273")]
+ public static extern void SetThreadpoolWait(PTP_WAIT pwa, SafeEventHandle h, [Optional] IntPtr pftTimeout);
+
+ ///
+ /// Sets the wait object—replacing the previous wait object, if any. A worker thread calls the wait object's callback function after
+ /// the handle becomes signaled or after the specified timeout expires.
+ ///
+ ///
+ /// A pointer to a TP_WAIT structure that defines the wait object. The CreateThreadpoolWait function returns this structure.
+ ///
+ ///
+ /// A handle.
+ ///
+ /// If this parameter is NULL, the wait object will cease to queue new callbacks (but callbacks already queued will still occur).
+ ///
+ /// If this parameter is not NULL, it must refer to a valid waitable object.
+ ///
+ /// If this handle is closed while the wait is still pending, the function's behavior is undefined. If the wait is still pending and
+ /// the handle must be closed, use CloseThreadpoolWait to cancel the wait and then close the handle.
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to a FILETIME structure that specifies the absolute or relative time at which the wait operation should time
+ /// out. If this parameter points to a positive value, it indicates the absolute time since January 1, 1601 (UTC), in 100-nanosecond
+ /// intervals. If this parameter points to a negative value, it indicates the amount of time to wait relative to the current time.
+ /// For more information about time values, see File Times.
+ ///
+ /// If this parameter points to 0, the wait times out immediately. If this parameter is NULL, the wait will not time out.
+ ///
+ /// This function does not return a value.
+ // VOID WINAPI SetThreadpoolWait( _Inout_ PTP_WAIT pwa, _In_opt_ HANDLE h, _In_opt_ PFILETIME pftTimeout); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686273(v=vs.85).aspx
+ [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
+ [PInvokeData("WinBase.h", MSDNShortId = "ms686273")]
+ public static extern void SetThreadpoolWait(PTP_WAIT pwa, [Optional] IntPtr h, [Optional] IntPtr pftTimeout);
+
///
/// Sets the wait object—replacing the previous wait object, if any. A worker thread calls the wait object's callback function after
/// the handle becomes signaled or after the specified timeout expires.
@@ -770,11 +852,11 @@ namespace Vanara.PInvoke
/// If the function succeeds, it returns TRUE.
/// If the function fails, it returns FALSE. To retrieve extended error information, call GetLastError.
///
- // BOOL WINAPI TrySubmitThreadpoolCallback( _In_ PTP_SIMPLE_CALLBACK pfns, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686862(v=vs.85).aspx
+ // BOOL WINAPI TrySubmitThreadpoolCallback( _In_ SimpleCallback pfns, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686862(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("WinBase.h", MSDNShortId = "ms686862")]
[return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool TrySubmitThreadpoolCallback(PTP_SIMPLE_CALLBACK pfns, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+ public static extern bool TrySubmitThreadpoolCallback(SimpleCallback pfns, [Optional] IntPtr pv, [Optional] PTP_CALLBACK_ENVIRON pcbe);
///
/// Waits for outstanding I/O completion callbacks to complete and optionally cancels pending callbacks that have not yet started to execute.
@@ -828,46 +910,367 @@ namespace Vanara.PInvoke
[PInvokeData("WinBase.h", MSDNShortId = "ms687053")]
public static extern void WaitForThreadpoolWorkCallbacks(PTP_WORK pwk, [MarshalAs(UnmanagedType.Bool)] bool fCancelPendingCallbacks);
+ /// Creates a new timer object.
+ /// The callback function to call each time the timer object expires. For details, see TimerCallback.
+ /// Optional application-defined data to pass to the callback function.
+ ///
+ ///
+ /// A TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback. The
+ /// InitializeThreadpoolEnvironment function returns this structure.
+ ///
+ /// If this parameter is NULL, the callback executes in the default callback environment. For more information, see InitializeThreadpoolEnvironment.
+ ///
+ ///
+ ///
+ /// If the function succeeds, it returns a TP_TIMER structure that defines the timer object. Applications do not modify the
+ /// members of this structure.
+ ///
+ /// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ ///
+ // PTP_TIMER WINAPI CreateThreadpoolTimer( _In_ TimerCallback pfnti, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682466(v=vs.85).aspx
+ [DllImport(Lib.Kernel32, SetLastError = true, EntryPoint = "CreateThreadpoolTimer")]
+ [PInvokeData("WinBase.h", MSDNShortId = "ms682466")]
+ internal static extern PTP_TIMER InternalCreateThreadpoolTimer(TimerCallback pfnti, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+
+ /// Creates a new wait object.
+ /// The callback function to call when the wait completes or times out. For details, see WaitCallback.
+ /// Optional application-defined data to pass to the callback function.
+ ///
+ ///
+ /// A TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback. The
+ /// InitializeThreadpoolEnvironment function returns this structure.
+ ///
+ /// If this parameter is NULL, the callback executes in the default callback environment. For more information, see InitializeThreadpoolEnvironment.
+ ///
+ ///
+ ///
+ /// If the function succeeds, it returns a TP_WAIT structure that defines the wait object. Applications do not modify the
+ /// members of this structure.
+ ///
+ /// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ ///
+ // PTP_WAIT WINAPI CreateThreadpoolWait( _In_ WaitCallback pfnwa, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682474(v=vs.85).aspx
+ [DllImport(Lib.Kernel32, SetLastError = true, EntryPoint = "CreateThreadpoolWait")]
+ [PInvokeData("WinBase.h", MSDNShortId = "ms682474")]
+ internal static extern PTP_WAIT InternalCreateThreadpoolWait(WaitCallback pfnwa, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+
+ /// Creates a new work object.
+ ///
+ /// The callback function. A worker thread calls this callback each time you call SubmitThreadpoolWork to post the work
+ /// object. For details, see WorkCallback.
+ ///
+ /// Optional application-defined data to pass to the callback function.
+ ///
+ ///
+ /// A TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback. The
+ /// InitializeThreadpoolEnvironment function returns this structure.
+ ///
+ /// If this parameter is NULL, the callback executes in the default callback environment. For more information, see InitializeThreadpoolEnvironment.
+ ///
+ ///
+ ///
+ /// If the function succeeds, it returns a TP_WORK structure that defines the work object. Applications do not modify the
+ /// members of this structure.
+ ///
+ /// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ ///
+ // PTP_WORK WINAPI CreateThreadpoolWork( _In_ WorkCallback pfnwk, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe); https://msdn.microsoft.com/en-us/library/windows/desktop/ms682478(v=vs.85).aspx
+ [DllImport(Lib.Kernel32, SetLastError = true, EntryPoint = "CreateThreadpoolWork")]
+ [PInvokeData("WinBase.h", MSDNShortId = "ms682478")]
+ internal static extern PTP_WORK InternalCreateThreadpoolWork(WorkCallback pfnwk, IntPtr pv, PTP_CALLBACK_ENVIRON pcbe);
+
[StructLayout(LayoutKind.Sequential)]
public struct PTP_CALLBACK_INSTANCE
{
private readonly IntPtr handle;
}
+ /// Provides a handle to a pool cleanup group.
[StructLayout(LayoutKind.Sequential)]
- public struct PTP_CLEANUP_GROUP
+ public struct PTP_CLEANUP_GROUP : IHandle
{
- private readonly IntPtr handle;
+ private IntPtr handle;
+
+ /// Initializes a new instance of the struct.
+ /// An object that represents the pre-existing handle to use.
+ public PTP_CLEANUP_GROUP(IntPtr preexistingHandle) => handle = preexistingHandle;
+
+ /// Returns an invalid handle by instantiating a object with .
+ public static PTP_CLEANUP_GROUP NULL => new PTP_CLEANUP_GROUP(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(PTP_CLEANUP_GROUP h) => h.handle;
+
+ /// Performs an implicit conversion from to .
+ /// The pointer to a handle.
+ /// The result of the conversion.
+ public static implicit operator PTP_CLEANUP_GROUP(IntPtr h) => new PTP_CLEANUP_GROUP(h);
+
+ /// Implements the operator !=.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator !=(PTP_CLEANUP_GROUP h1, PTP_CLEANUP_GROUP h2) => !(h1 == h2);
+
+ /// Implements the operator ==.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator ==(PTP_CLEANUP_GROUP h1, PTP_CLEANUP_GROUP h2) => h1.Equals(h2);
+
+ ///
+ public override bool Equals(object obj) => obj is PTP_CLEANUP_GROUP h ? handle == h.handle : false;
+
+ ///
+ public override int GetHashCode() => handle.GetHashCode();
+
+ ///
+ public IntPtr DangerousGetHandle() => handle;
}
+ /// Provides a handle to a threadpool IO.
[StructLayout(LayoutKind.Sequential)]
- public struct PTP_IO
+ public struct PTP_IO : IHandle
{
- private readonly IntPtr handle;
+ private IntPtr handle;
+
+ /// Initializes a new instance of the struct.
+ /// An object that represents the pre-existing handle to use.
+ public PTP_IO(IntPtr preexistingHandle) => handle = preexistingHandle;
+
+ /// Returns an invalid handle by instantiating a object with .
+ public static PTP_IO NULL => new PTP_IO(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(PTP_IO h) => h.handle;
+
+ /// Performs an implicit conversion from to .
+ /// The pointer to a handle.
+ /// The result of the conversion.
+ public static implicit operator PTP_IO(IntPtr h) => new PTP_IO(h);
+
+ /// Implements the operator !=.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator !=(PTP_IO h1, PTP_IO h2) => !(h1 == h2);
+
+ /// Implements the operator ==.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator ==(PTP_IO h1, PTP_IO h2) => h1.Equals(h2);
+
+ ///
+ public override bool Equals(object obj) => obj is PTP_IO h ? handle == h.handle : false;
+
+ ///
+ public override int GetHashCode() => handle.GetHashCode();
+
+ ///
+ public IntPtr DangerousGetHandle() => handle;
}
+ /// Provides a handle to a thread pool.
[StructLayout(LayoutKind.Sequential)]
- public struct PTP_POOL
+ public struct PTP_POOL : IHandle
{
- private readonly IntPtr handle;
+ private IntPtr handle;
+
+ /// Initializes a new instance of the struct.
+ /// An object that represents the pre-existing handle to use.
+ public PTP_POOL(IntPtr preexistingHandle) => handle = preexistingHandle;
+
+ /// Returns an invalid handle by instantiating a object with .
+ public static PTP_POOL NULL => new PTP_POOL(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(PTP_POOL h) => h.handle;
+
+ /// Performs an implicit conversion from to .
+ /// The pointer to a handle.
+ /// The result of the conversion.
+ public static implicit operator PTP_POOL(IntPtr h) => new PTP_POOL(h);
+
+ /// Implements the operator !=.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator !=(PTP_POOL h1, PTP_POOL h2) => !(h1 == h2);
+
+ /// Implements the operator ==.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator ==(PTP_POOL h1, PTP_POOL h2) => h1.Equals(h2);
+
+ ///
+ public override bool Equals(object obj) => obj is PTP_POOL h ? handle == h.handle : false;
+
+ ///
+ public override int GetHashCode() => handle.GetHashCode();
+
+ ///
+ public IntPtr DangerousGetHandle() => handle;
}
+ /// Provides a handle to a threadpool timer.
[StructLayout(LayoutKind.Sequential)]
- public struct PTP_TIMER
+ public struct PTP_TIMER : IHandle
{
- private readonly IntPtr handle;
+ private IntPtr handle;
+
+ /// Initializes a new instance of the struct.
+ /// An object that represents the pre-existing handle to use.
+ public PTP_TIMER(IntPtr preexistingHandle) => handle = preexistingHandle;
+
+ /// Returns an invalid handle by instantiating a object with .
+ public static PTP_TIMER NULL => new PTP_TIMER(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(PTP_TIMER h) => h.handle;
+
+ /// Performs an implicit conversion from to .
+ /// The pointer to a handle.
+ /// The result of the conversion.
+ public static implicit operator PTP_TIMER(IntPtr h) => new PTP_TIMER(h);
+
+ /// Implements the operator !=.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator !=(PTP_TIMER h1, PTP_TIMER h2) => !(h1 == h2);
+
+ /// Implements the operator ==.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator ==(PTP_TIMER h1, PTP_TIMER h2) => h1.Equals(h2);
+
+ ///
+ public override bool Equals(object obj) => obj is PTP_TIMER h ? handle == h.handle : false;
+
+ ///
+ public override int GetHashCode() => handle.GetHashCode();
+
+ ///
+ public IntPtr DangerousGetHandle() => handle;
}
+ /// Provides a handle to a threadpool wait.
[StructLayout(LayoutKind.Sequential)]
- public struct PTP_WAIT
+ public struct PTP_WAIT : IHandle
{
- private readonly IntPtr handle;
+ private IntPtr handle;
+
+ /// Initializes a new instance of the struct.
+ /// An object that represents the pre-existing handle to use.
+ public PTP_WAIT(IntPtr preexistingHandle) => handle = preexistingHandle;
+
+ /// Returns an invalid handle by instantiating a object with .
+ public static PTP_WAIT NULL => new PTP_WAIT(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(PTP_WAIT h) => h.handle;
+
+ /// Performs an implicit conversion from to .
+ /// The pointer to a handle.
+ /// The result of the conversion.
+ public static implicit operator PTP_WAIT(IntPtr h) => new PTP_WAIT(h);
+
+ /// Implements the operator !=.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator !=(PTP_WAIT h1, PTP_WAIT h2) => !(h1 == h2);
+
+ /// Implements the operator ==.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator ==(PTP_WAIT h1, PTP_WAIT h2) => h1.Equals(h2);
+
+ ///
+ public override bool Equals(object obj) => obj is PTP_WAIT h ? handle == h.handle : false;
+
+ ///
+ public override int GetHashCode() => handle.GetHashCode();
+
+ ///
+ public IntPtr DangerousGetHandle() => handle;
}
+ /// Provides a handle to a threadpool work.
[StructLayout(LayoutKind.Sequential)]
- public struct PTP_WORK
+ public struct PTP_WORK : IHandle
{
- private readonly IntPtr handle;
+ private IntPtr handle;
+
+ /// Initializes a new instance of the struct.
+ /// An object that represents the pre-existing handle to use.
+ public PTP_WORK(IntPtr preexistingHandle) => handle = preexistingHandle;
+
+ /// Returns an invalid handle by instantiating a object with .
+ public static PTP_WORK NULL => new PTP_WORK(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(PTP_WORK h) => h.handle;
+
+ /// Performs an implicit conversion from to .
+ /// The pointer to a handle.
+ /// The result of the conversion.
+ public static implicit operator PTP_WORK(IntPtr h) => new PTP_WORK(h);
+
+ /// Implements the operator !=.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator !=(PTP_WORK h1, PTP_WORK h2) => !(h1 == h2);
+
+ /// Implements the operator ==.
+ /// The first handle.
+ /// The second handle.
+ /// The result of the operator.
+ public static bool operator ==(PTP_WORK h1, PTP_WORK h2) => h1.Equals(h2);
+
+ ///
+ public override bool Equals(object obj) => obj is PTP_WORK h ? handle == h.handle : false;
+
+ ///
+ public override int GetHashCode() => handle.GetHashCode();
+
+ ///
+ public IntPtr DangerousGetHandle() => handle;
}
/// Used to set the stack reserve and commit sizes for new threads in a thread pool.
@@ -882,7 +1285,8 @@ namespace Vanara.PInvoke
public SizeT StackCommit;
}
- /// Defines a callback environment.`
+ /// Defines a callback environment.
+ /// `
[PInvokeData("threadpoolapiset.h")]
[StructLayout(LayoutKind.Sequential)]
public class PTP_CALLBACK_ENVIRON
@@ -890,10 +1294,10 @@ namespace Vanara.PInvoke
internal uint Version;
internal PTP_POOL Pool;
internal PTP_CLEANUP_GROUP CleanupGroup;
- internal PTP_CLEANUP_GROUP_CANCEL_CALLBACK CleanupGroupCancelCallback;
+ internal CleanupGroupCancelCallback CleanupGroupCancelCallback;
internal HINSTANCE RaceDll;
internal HACTCTX _ActivationContext;
- internal PTP_SIMPLE_CALLBACK _FinalizationCallback;
+ internal SimpleCallback _FinalizationCallback;
internal TP_CALLBACK_ENV_FLAGS Flags;
internal TP_CALLBACK_PRIORITY CallbackPriority;
internal uint Size;
@@ -911,11 +1315,221 @@ namespace Vanara.PInvoke
/// Indicates a function to call when the callback environment is finalized.
/// Pointer to a TP_SIMPLE_CALLBACK structure indicating a function to call when the callback environment is finalized.
- public PTP_SIMPLE_CALLBACK FinalizationCallback { set => _FinalizationCallback = value; }
+ public SimpleCallback FinalizationCallback { set => _FinalizationCallback = value; }
/// Assigns an activation context to the callback environment.
/// Pointer to an _ACTIVATION_CONTEXT structure.
public HACTCTX ActivationContext { set => _ActivationContext = value; }
}
+
+ /// Provides a for that is disposed using .
+ public class SafePTP_CLEANUP_GROUP : 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 SafePTP_CLEANUP_GROUP(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
+
+ /// Initializes a new instance of the class.
+ private SafePTP_CLEANUP_GROUP() : base() { }
+
+ /// Gets or sets a value indicating whether to call CloseThreadpoolCleanupGroupMembers on disposal.
+ public bool AutoCloseMembers { get; set; }
+
+ /// Performs an implicit conversion from to .
+ /// The safe handle instance.
+ /// The result of the conversion.
+ public static implicit operator PTP_CLEANUP_GROUP(SafePTP_CLEANUP_GROUP h) => h.handle;
+
+ ///
+ /// Releases the members of this cleanup group, waits for all callback functions to complete, and optionally cancels any
+ /// outstanding callback functions.
+ ///
+ ///
+ /// If this parameter is TRUE, the function cancels outstanding callbacks that have not yet started. If this parameter is FALSE,
+ /// the function waits for outstanding callback functions to complete.
+ ///
+ ///
+ /// The application-defined data to pass to the application's cleanup group callback function. You can specify the callback
+ /// function when you call SetThreadpoolCallbackCleanupGroup.
+ ///
+ /// This function does not return a value.
+ public void CloseMembers(bool fCancelPendingCallbacks, [Optional] IntPtr pvCleanupContext) => CloseThreadpoolCleanupGroupMembers(handle, fCancelPendingCallbacks, pvCleanupContext);
+
+ /// Creates a new timer object.
+ /// The callback function to call each time the timer object expires. For details, see TimerCallback.
+ /// Optional application-defined data to pass to the callback function.
+ ///
+ ///
+ /// A TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback. The
+ /// InitializeThreadpoolEnvironment function returns this structure.
+ ///
+ /// If this parameter is NULL, the callback executes in the default callback environment. For more information, see InitializeThreadpoolEnvironment.
+ ///
+ ///
+ ///
+ /// If the function succeeds, it returns a TP_TIMER structure that defines the timer object. Applications do not modify
+ /// the members of this structure.
+ ///
+ /// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ ///
+ public PTP_TIMER CreateTimer(TimerCallback pfnti, IntPtr pv = default, PTP_CALLBACK_ENVIRON pcbe = null) => InternalCreateThreadpoolTimer(pfnti, pv, pcbe);
+
+ /// Creates a new wait object.
+ /// The callback function to call when the wait completes or times out. For details, see WaitCallback.
+ /// Optional application-defined data to pass to the callback function.
+ ///
+ ///
+ /// A TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback. The
+ /// InitializeThreadpoolEnvironment function returns this structure.
+ ///
+ /// If this parameter is NULL, the callback executes in the default callback environment. For more information, see InitializeThreadpoolEnvironment.
+ ///
+ ///
+ ///
+ /// If the function succeeds, it returns a TP_WAIT structure that defines the wait object. Applications do not modify the
+ /// members of this structure.
+ ///
+ /// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ ///
+ public PTP_WAIT CreateWait(WaitCallback pfnwa, IntPtr pv = default, PTP_CALLBACK_ENVIRON pcbe = null) => InternalCreateThreadpoolWait(pfnwa, pv, pcbe);
+
+ /// Creates a new work object.
+ ///
+ /// The callback function. A worker thread calls this callback each time you call SubmitThreadpoolWork to post the work
+ /// object. For details, see WorkCallback.
+ ///
+ /// Optional application-defined data to pass to the callback function.
+ ///
+ ///
+ /// A TP_CALLBACK_ENVIRON structure that defines the environment in which to execute the callback. The
+ /// InitializeThreadpoolEnvironment function returns this structure.
+ ///
+ /// If this parameter is NULL, the callback executes in the default callback environment. For more information, see InitializeThreadpoolEnvironment.
+ ///
+ ///
+ ///
+ /// If the function succeeds, it returns a TP_WORK structure that defines the work object. Applications do not modify the
+ /// members of this structure.
+ ///
+ /// If the function fails, it returns NULL. To retrieve extended error information, call GetLastError.
+ ///
+ public PTP_WORK CreateWork(WorkCallback pfnwk, IntPtr pv = default, PTP_CALLBACK_ENVIRON pcbe = null) => InternalCreateThreadpoolWork(pfnwk, pv, pcbe);
+
+ ///
+ protected override bool InternalReleaseHandle() { if (AutoCloseMembers) CloseMembers(false); CloseThreadpoolCleanupGroup(handle); return true; }
+ }
+
+ /// Provides a for that is disposed using .
+ public class SafePTP_IO : 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 SafePTP_IO(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
+
+ /// Initializes a new instance of the class.
+ private SafePTP_IO() : base() { }
+
+ /// Performs an implicit conversion from to .
+ /// The safe handle instance.
+ /// The result of the conversion.
+ public static implicit operator PTP_IO(SafePTP_IO h) => h.handle;
+
+ ///
+ protected override bool InternalReleaseHandle() { CloseThreadpoolIo(handle); return true; }
+ }
+
+ /// Provides a for that is disposed using .
+ public class SafePTP_POOL : 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 SafePTP_POOL(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
+
+ /// Initializes a new instance of the class.
+ private SafePTP_POOL() : base() { }
+
+ /// Performs an implicit conversion from to .
+ /// The safe handle instance.
+ /// The result of the conversion.
+ public static implicit operator PTP_POOL(SafePTP_POOL h) => h.handle;
+
+ ///
+ protected override bool InternalReleaseHandle() { CloseThreadpool(handle); return true; }
+ }
+
+ /// Provides a for that is disposed using .
+ public class SafePTP_TIMER : 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 SafePTP_TIMER(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
+
+ /// Initializes a new instance of the class.
+ private SafePTP_TIMER() : base() { }
+
+ /// Performs an implicit conversion from to .
+ /// The safe handle instance.
+ /// The result of the conversion.
+ public static implicit operator PTP_TIMER(SafePTP_TIMER h) => h.handle;
+
+ ///
+ protected override bool InternalReleaseHandle() { CloseThreadpoolTimer(handle); return true; }
+ }
+
+ /// Provides a for that is disposed using .
+ public class SafePTP_WAIT : 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 SafePTP_WAIT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
+
+ /// Initializes a new instance of the class.
+ private SafePTP_WAIT() : base() { }
+
+ /// Performs an implicit conversion from to .
+ /// The safe handle instance.
+ /// The result of the conversion.
+ public static implicit operator PTP_WAIT(SafePTP_WAIT h) => h.handle;
+
+ ///
+ protected override bool InternalReleaseHandle() { CloseThreadpoolWait(handle); return true; }
+ }
+
+ /// Provides a for that is disposed using .
+ public class SafePTP_WORK : 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 SafePTP_WORK(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
+
+ /// Initializes a new instance of the class.
+ private SafePTP_WORK() : base() { }
+
+ /// Performs an implicit conversion from to .
+ /// The safe handle instance.
+ /// The result of the conversion.
+ public static implicit operator PTP_WORK(SafePTP_WORK h) => h.handle;
+
+ ///
+ protected override bool InternalReleaseHandle() { CloseThreadpoolWork(handle); return true; }
+ }
}
}
\ No newline at end of file
diff --git a/UnitTests/PInvoke/Kernel32/Kernel32.csproj b/UnitTests/PInvoke/Kernel32/Kernel32.csproj
index 5f786b81..f9c265e9 100644
--- a/UnitTests/PInvoke/Kernel32/Kernel32.csproj
+++ b/UnitTests/PInvoke/Kernel32/Kernel32.csproj
@@ -48,6 +48,7 @@
+
diff --git a/UnitTests/PInvoke/Kernel32/ThreadPoolApiSetTests.cs b/UnitTests/PInvoke/Kernel32/ThreadPoolApiSetTests.cs
new file mode 100644
index 00000000..b4da02ce
--- /dev/null
+++ b/UnitTests/PInvoke/Kernel32/ThreadPoolApiSetTests.cs
@@ -0,0 +1,152 @@
+using NUnit.Framework;
+using System;
+using System.Diagnostics;
+using Vanara.Extensions;
+using static Vanara.PInvoke.Kernel32;
+
+namespace Vanara.PInvoke.Tests
+{
+ [TestFixture]
+ public class ThreadPoolApiSetTests
+ {
+ [Test]
+ public void QuerySetThreadpoolStackInformationTest()
+ {
+ using (var pool = CreateThreadpool())
+ {
+ Assert.That(pool, ResultIs.ValidHandle);
+ Assert.That(QueryThreadpoolStackInformation(pool, out var si), ResultIs.Successful);
+ Assert.That(si.StackReserve.Value, Is.Not.Zero);
+ Assert.That(SetThreadpoolStackInformation(pool, si), ResultIs.Successful);
+ }
+ }
+
+ [Test]
+ public void ThreadpoolIoWorkTimerTest()
+ {
+ InitializeThreadpoolEnvironment(out var CallBackEnviron);
+
+ // Create a custom, dedicated thread pool.
+ using (var pool = CreateThreadpool())
+ {
+ Assert.That(pool, ResultIs.ValidHandle);
+
+ // The thread pool is made persistent simply by setting both the minimum and maximum threads to 1.
+ SetThreadpoolThreadMaximum(pool, 1);
+ Assert.That(SetThreadpoolThreadMinimum(pool, 1), ResultIs.Successful);
+
+ // Create a cleanup group for this thread pool.
+ using (var cleanupgroup = CreateThreadpoolCleanupGroup())
+ {
+ Assert.That(cleanupgroup, ResultIs.ValidHandle);
+ cleanupgroup.AutoCloseMembers = true;
+
+ // Associate the callback environment with our thread pool.
+ CallBackEnviron.SetThreadpoolCallbackPool(pool);
+
+ // Associate the cleanup group with our thread pool. Objects created with the same callback environment as the cleanup
+ // group become members of the cleanup group.
+ CallBackEnviron.SetThreadpoolCallbackCleanupGroup(cleanupgroup, null);
+
+ // Create work with the callback environment.
+ var work = cleanupgroup.CreateWork(MyWorkCallback, default, CallBackEnviron);
+ Assert.That(work, ResultIs.ValidHandle);
+
+ // Submit the work to the pool. Because this was a pre-allocated work item (using CreateThreadpoolWork), it is guaranteed
+ // to execute.
+ SubmitThreadpoolWork(work);
+
+ // Create a timer with the same callback environment.
+ var timer = cleanupgroup.CreateTimer(MyTimerCallback, default, CallBackEnviron);
+ Assert.That(timer, ResultIs.ValidHandle);
+
+ // Set the timer to fire in one second.
+ var FileDueTime = TimeSpan.FromSeconds(-1).ToFileTimeStruct();
+ Assert.That(SetThreadpoolTimerEx(timer, FileDueTime, 0, 0), Is.False);
+ Assert.That(IsThreadpoolTimerSet(timer), Is.True);
+
+ using (var hFile = CreateFile(@"C:\Temp\help.ico", FileAccess.FILE_GENERIC_READ, System.IO.FileShare.Read, null, System.IO.FileMode.Open, FileFlagsAndAttributes.FILE_FLAG_OVERLAPPED))
+ using (var io = CreateThreadpoolIo(hFile, MyIoCallback, default, CallBackEnviron))
+ {
+ Assert.That(io, ResultIs.ValidHandle);
+ StartThreadpoolIo(io);
+ WaitForThreadpoolIoCallbacks(io, true);
+ }
+
+ // Delay for the timer to be fired
+ Sleep(1500);
+ }
+ }
+
+ void MyIoCallback(PTP_CALLBACK_INSTANCE Instance, IntPtr Context, IntPtr Overlapped, uint IoResult, UIntPtr NumberOfBytesTransferred, PTP_IO Io)
+ {
+ Debug.Write("MyIoCallback: I/O has fired.\n");
+ CancelThreadpoolIo(Io);
+ }
+
+ // Thread pool timer callback function template
+ void MyTimerCallback(PTP_CALLBACK_INSTANCE a, IntPtr b, PTP_TIMER c) => Debug.Write("MyTimerCallback: timer has fired.\n");
+
+ // This is the thread pool work callback function.
+ void MyWorkCallback(PTP_CALLBACK_INSTANCE a, IntPtr b, PTP_WORK c)
+ {
+ CallbackMayRunLong(a);
+ Debug.Write("MyWorkCallback: Task performed.\n");
+ }
+ }
+
+ [Test]
+ public void ThreadpoolWaitTest()
+ {
+ SafeEventHandle retEvent;
+ // Create an auto-reset event.
+ using (var hEvent = CreateEvent(null, false, false, null))
+ using (retEvent = CreateEvent(null, false, false, null))
+ {
+ Assert.That(hEvent, ResultIs.ValidHandle);
+
+ using (var Wait = CreateThreadpoolWait(MyWaitCallback))
+ {
+ Assert.That(Wait, ResultIs.ValidHandle);
+
+ // Need to re-register the event with the wait object each time before signaling the event to trigger the wait callback.
+ for (var i = 0; i < 5; i++)
+ {
+ SetThreadpoolWait(Wait, hEvent);
+
+ SetEvent(hEvent);
+
+ // Delay for the waiter thread to act if necessary.
+ Sleep(500);
+
+ // Block here until the callback function is done executing.
+ WaitForThreadpoolWaitCallbacks(Wait, false);
+
+ // Ensure that callback return event is signaled.
+ WaitForSingleObject(retEvent, INFINITE);
+ }
+
+ SetThreadpoolWait(Wait);
+ }
+ }
+
+ // Thread pool wait callback function template
+ void MyWaitCallback(PTP_CALLBACK_INSTANCE a, IntPtr b, PTP_WAIT c, uint d)
+ {
+ Debug.Write("MyWaitCallback: wait is over.\n");
+ Sleep(200);
+ SetEventWhenCallbackReturns(a, retEvent);
+ }
+ }
+
+ [Test]
+ public void TrySubmitThreadpoolCallbackTest()
+ {
+ Assert.That(TrySubmitThreadpoolCallback((i, c) =>
+ {
+ Debug.WriteLine("SimpleCallback from TrySubmitThreadpoolCallback");
+ DisassociateCurrentThreadFromCallback(i);
+ }), Is.True); ;
+ }
+ }
+}
\ No newline at end of file