using System; using System.Runtime.InteropServices; namespace Vanara.PInvoke; /// Functions from Avrt.dll. public static partial class Avrt { private const string Lib_Avrt = "Avrt.dll"; /// The relative thread priority of this thread to other threads performing a similar task. [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvSetMmThreadPriority")] public enum AVRT_PRIORITY { /// very low AVRT_PRIORITY_VERYLOW = -2, /// low AVRT_PRIORITY_LOW, /// normal AVRT_PRIORITY_NORMAL, /// high AVRT_PRIORITY_HIGH, /// critical AVRT_PRIORITY_CRITICAL } /// Retrieves the system responsiveness setting used by the multimedia class scheduler service. /// /// A handle to the task. This handle is returned by the AvSetMmThreadCharacteristics or AvSetMmMaxThreadCharacteristics function. /// /// The system responsiveness value. This value can range from 10 to 100 percent. /// /// 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://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avquerysystemresponsiveness AVRTAPI BOOL AvQuerySystemResponsiveness( // [in] HAVRT AvrtHandle, [out] PULONG SystemResponsivenessValue ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvQuerySystemResponsiveness")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvQuerySystemResponsiveness([In] HAVRT AvrtHandle, out uint SystemResponsivenessValue); /// Indicates that a thread is no longer performing work associated with the specified task. /// /// A handle to the task. This handle is returned by the AvSetMmThreadCharacteristics or AvSetMmMaxThreadCharacteristics function. /// /// /// 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. /// /// /// This function must be called from the same thread that called the AvSetMmThreadCharacteristics or AvSetMmMaxThreadCharacteristics /// function to create the handle. Otherwise, the function will fail. /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrevertmmthreadcharacteristics AVRTAPI BOOL // AvRevertMmThreadCharacteristics( [in] HAVRT AvrtHandle ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRevertMmThreadCharacteristics")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRevertMmThreadCharacteristics([In] HAVRT AvrtHandle); /// /// Creates a thread ordering group. /// /// To prevent the server thread for the thread ordering group from being starved if higher priority client threads are running, use the /// AvRtCreateThreadOrderingGroupEx function. /// /// /// A pointer to a context handle. /// /// /// A pointer to a value, in 100-nanosecond increments, that specifies the period for the thread ordering group. Each thread in the /// thread ordering group runs one time during this period. If all threads complete their execution before a period ends, all threads /// wait until the remainder of the period elapses before any are executed again. /// /// /// The possible values for this parameter depend on the platform, but this parameter can be as low as 500 microseconds or as high as /// 0x1FFFFFFFFFFFFFFF. If this parameter is less than 500 microseconds, then it is set to 500 microseconds. If this parameter is greater /// than the maximum, then it is set to 0x1FFFFFFFFFFFFFFF. /// /// /// /// /// A pointer to the unique identifier for the thread ordering group to be created. If this value is not unique to the thread ordering /// service, the function fails. /// /// If the identifier is GUID_NULL on input, the thread ordering service generates and returns a unique identifier. /// /// /// A pointer to a time-out value. All threads within the group should complete their execution within Period plus Timeout. /// /// If a thread fails to complete its processing within the period plus this time-out interval, it is removed from the thread ordering /// group. If the parent fails to complete its processing within the period plus the time-out interval, the thread ordering group is destroyed. /// /// /// The possible values for this parameter depend on the platform, but can be as low as 500 microseconds or as high as /// 0x1FFFFFFFFFFFFFFF. If this parameter is less than 500 microseconds, then it is set to 500 microseconds. If this parameter is greater /// than the maximum, then it is set to 0x1FFFFFFFFFFFFFFF. /// /// If this parameter is NULL or 0, the default is five times the value of Period. /// /// If this parameter is THREAD_ORDER_GROUP_INFINITE_TIMEOUT, the group is created with an infinite time-out interval. This can be useful /// for debugging purposes. /// /// /// /// 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 a thread ordering group with the specified identifier already exists, the function fails and sets the last error to ERROR_ALREADY_EXISTS. /// /// /// /// The calling thread is considered to be the parent thread. Each thread ordering group has one parent thread. Each parent thread can /// have zero or more predecessor threads and zero or more successor threads. A client thread can join a thread ordering group and /// specify whether it is a predecessor or successor using the AvRtJoinThreadOrderingGroup function. /// /// /// The parent thread encloses the code to be executed during each period within a loop that is controlled by the /// AvRtWaitOnThreadOrderingGroup function. /// /// To delete the thread ordering group, call the AvRtDeleteThreadOrderingGroup function. /// /// A thread can create more than one thread ordering group and join more than one thread ordering group. However, a thread cannot join /// the same thread ordering group more than one time. /// /// Examples /// The following snippet creates a thread ordering group. /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrtcreatethreadorderinggroup AVRTAPI BOOL // AvRtCreateThreadOrderingGroup( [out] PHANDLE Context, [in] PLARGE_INTEGER Period, [in, out] GUID *ThreadOrderingGuid, [in, optional] // PLARGE_INTEGER Timeout ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRtCreateThreadOrderingGroup")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRtCreateThreadOrderingGroup(out HANDLE Context, in long Period, ref Guid ThreadOrderingGuid, [In, Optional] in long Timeout); /// Creates a thread ordering group and associates the server thread with a task. /// A pointer to a context handle. /// /// /// A pointer to a value, in 100-nanosecond increments, that specifies the period for the thread ordering group. Each thread in the /// thread ordering group runs one time during this period. If all threads complete their execution before a period ends, all threads /// wait until the remainder of the period elapses before any are executed again. /// /// /// The possible values for this parameter depend on the platform, but this parameter can be as low as 500 microseconds or as high as /// 0x1FFFFFFFFFFFFFFF. If this parameter is less than 500 microseconds, then it is set to 500 microseconds. If this parameter is greater /// than the maximum, then it is set to 0x1FFFFFFFFFFFFFFF. /// /// /// /// /// A pointer to the unique identifier for the thread ordering group to be created. If this value is not unique to the thread ordering /// service, the function fails. /// /// If the identifier is GUID_NULL on input, the thread ordering service generates and returns a unique identifier. /// /// /// A pointer to a time-out value. All threads within the group should complete their execution within Period plus Timeout. /// /// If a thread fails to complete its processing within the period plus this time-out interval, it is removed from the thread ordering /// group. If the parent fails to complete its processing within the period plus the time-out interval, the thread ordering group is destroyed. /// /// /// The possible values for this parameter depend on the platform, but can be as low as 500 microseconds or as high as /// 0x1FFFFFFFFFFFFFFF. If this parameter is less than 500 microseconds, then it is set to 500 microseconds. If this parameter is greater /// than the maximum, then it is set to 0x1FFFFFFFFFFFFFFF. /// /// If this parameter is NULL or 0, the default is five times the value of Period. /// /// If this parameter is THREAD_ORDER_GROUP_INFINITE_TIMEOUT, the group is created with an infinite time-out interval. This can be useful /// for debugging purposes. /// /// /// The name of the task. /// /// 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 a thread ordering group with the specified identifier already exists, the function fails and sets the last error to ERROR_ALREADY_EXISTS. /// /// /// /// The calling thread is considered to be the parent thread. Each thread ordering group has one parent thread. Each parent thread can /// have zero or more predecessor threads and zero or more successor threads. A client thread can join a thread ordering group and /// specify whether it is a predecessor or successor using the AvRtJoinThreadOrderingGroup function. /// /// /// The parent thread encloses the code to be executed during each period within a loop that is controlled by the /// AvRtWaitOnThreadOrderingGroup function. /// /// To delete the thread ordering group, call the AvRtDeleteThreadOrderingGroup function. /// /// A thread can create more than one thread ordering group and join more than one thread ordering group. However, a thread cannot join /// the same thread ordering group more than one time. /// /// /// The parent and client threads of a thread ordering group run at high priorities. However, the server thread that manages the thread /// ordering group runs at normal priority. Therefore, there can be a delay switching from one client thread to another if there are /// other high-priority threads running. The TaskName parameter of this function specifies the task to be associated with the /// server thread. /// /// Examples /// The following snippet creates a thread ordering group. /// /// Note /// /// The avrt.h header defines AvRtCreateThreadOrderingGroupEx as an alias which automatically selects the ANSI or Unicode version of this /// function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not /// encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for /// Function Prototypes. /// /// /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrtcreatethreadorderinggroupexa AVRTAPI BOOL // AvRtCreateThreadOrderingGroupExA( [out] PHANDLE Context, [in] PLARGE_INTEGER Period, [in, out] GUID *ThreadOrderingGuid, [in, // optional] PLARGE_INTEGER Timeout, [in] LPCSTR TaskName ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRtCreateThreadOrderingGroupExA")] [DllImport(Lib_Avrt, SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRtCreateThreadOrderingGroupEx(out HANDLE Context, in long Period, ref Guid ThreadOrderingGuid, [In, Optional] in long Timeout, [MarshalAs(UnmanagedType.LPTStr)] string TaskName); /// /// Deletes the specified thread ordering group created by the caller. It cleans up resources for the thread ordering group, including /// the context information, and returns. /// /// /// A context handle. This handle is returned by the AvRtCreateThreadOrderingGroup function when creating the group. /// /// /// 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. /// /// /// /// This function can only be called successfully by the parent thread for the thread ordering group. If a thread other than the parent /// thread calls this function, the function fails with a last error code of ERROR_INVALID_FUNCTION. /// /// If the parent thread times out and attempts to call this function, the function fails with a last error code of ERROR_INVALID_PARAMETER. /// Examples /// The following code deletes a thread ordering group. /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrtdeletethreadorderinggroup AVRTAPI BOOL // AvRtDeleteThreadOrderingGroup( [in] HANDLE Context ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRtDeleteThreadOrderingGroup")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRtDeleteThreadOrderingGroup([In] HANDLE Context); /// Joins client threads to a thread ordering group. /// A pointer to a context handle. /// A pointer to the unique identifier for the thread ordering group. /// /// The thread order. If this parameter is TRUE, the thread is a predecessor thread that is scheduled to run before the parent /// thread. If this parameter is FALSE, the thread is a successor thread that is scheduled to run after the parent thread. /// /// /// 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. /// /// /// /// The thread encloses the code to be executed during each period within a loop that is controlled by the AvRtWaitOnThreadOrderingGroup function. /// /// /// A thread can create more than one thread ordering group and join more than one thread ordering group. However, a thread cannot join /// the same thread ordering group more than one time. /// /// The number of threads that can join a group is limited only by available system resources. /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrtjointhreadorderinggroup AVRTAPI BOOL AvRtJoinThreadOrderingGroup( // [out] PHANDLE Context, [in] GUID *ThreadOrderingGuid, [in] BOOL Before ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRtJoinThreadOrderingGroup")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRtJoinThreadOrderingGroup(out HANDLE Context, in Guid ThreadOrderingGuid, [MarshalAs(UnmanagedType.Bool)] bool Before); /// Enables client threads to leave a thread ordering group. /// A context handle. This handle is returned by the AvRtJoinThreadOrderingGroup function. /// /// 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. /// /// /// The parent thread for a thread ordering group should not remove itself from the group. /// If a thread times out and attempts to call this function, the function fails with a last error code of ERROR_INVALID_PARAMETER. /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrtleavethreadorderinggroup AVRTAPI BOOL // AvRtLeaveThreadOrderingGroup( [in] HANDLE Context ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRtLeaveThreadOrderingGroup")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRtLeaveThreadOrderingGroup([In] HANDLE Context); /// Enables client threads of a thread ordering group to wait until they should execute. /// /// A context handle. This handle is returned by the AvRtCreateThreadOrderingGroup or AvRtJoinThreadOrderingGroup function. /// /// /// 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. /// /// /// When this function returns, the thread should complete its processing for the period and then call the function again. /// /// If the thread fails to complete its processing during the time-out interval specified by the parent thread when creating the group, /// it is deleted from the thread ordering group. Therefore, when the thread finishes its processing loop, the next call to /// AvRtWaitOnThreadOrderingGroup fails and the last error code is set to ERROR_ACCESS_DENIED. /// /// If the thread ordering group is deleted during the wait, this function eventually times out and return ERROR_ACCESS_DENIED. /// Examples /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avrtwaitonthreadorderinggroup AVRTAPI BOOL // AvRtWaitOnThreadOrderingGroup( [in] HANDLE Context ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvRtWaitOnThreadOrderingGroup")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvRtWaitOnThreadOrderingGroup([In] HANDLE Context); /// Associates the calling thread with the specified tasks. /// /// The name of the first task to be performed. This name must match the name of one of the subkeys of the following key /// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. /// /// /// The name of the second task to be performed. This name must match the name of one of the subkeys of the following key /// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. /// /// /// The unique task identifier. The first time this function is called, this value must be 0 on input. The index value is returned on /// output and can be used as input in subsequent calls. /// /// /// If the function succeeds, it returns a handle to the task. /// If the function fails, it returns 0. To retrieve extended error information, call GetLastError. /// The following are possible error codes. /// /// /// Return code /// Description /// /// /// ERROR_INVALID_TASK_INDEX /// Either TaskIndex is not 0 on the first call or is not recognized value (on subsequent calls). /// /// /// ERROR_INVALID_TASK_NAME /// The specified task does not match any of the tasks stored in the registry. /// /// /// ERROR_PRIVILEGE_NOT_HELD /// The caller does not have sufficient privilege. /// /// /// /// /// The resulting characteristics of the thread performing the tasks reflect the task with the highest priority. /// When the task is completed, call the AvRevertMmThreadCharacteristics function. /// /// Note /// /// The avrt.h header defines AvSetMmMaxThreadCharacteristics as an alias which automatically selects the ANSI or Unicode version of this /// function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not /// encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for /// Function Prototypes. /// /// /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avsetmmmaxthreadcharacteristicsa AVRTAPI HANDLE // AvSetMmMaxThreadCharacteristicsA( [in] LPCSTR FirstTask, [in] LPCSTR SecondTask, [in, out] LPDWORD TaskIndex ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvSetMmMaxThreadCharacteristicsA")] [DllImport(Lib_Avrt, SetLastError = true, CharSet = CharSet.Auto)] public static extern SafeHAVRT AvSetMmMaxThreadCharacteristics([MarshalAs(UnmanagedType.LPTStr)] string FirstTask, [MarshalAs(UnmanagedType.LPTStr)] string SecondTask, ref uint TaskIndex); /// Associates the calling thread with the specified task. /// /// The name of the task to be performed. This name must match the name of one of the subkeys of the following key /// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile\Tasks. /// /// /// The unique task identifier. The first time this function is called, this value must be 0 on input. The index value is returned on /// output and can be used as input in subsequent calls. /// /// /// If the function succeeds, it returns a handle to the task. /// If the function fails, it returns 0. To retrieve extended error information, call GetLastError. /// The following are possible error codes. /// /// /// Return code /// Description /// /// /// ERROR_INVALID_TASK_INDEX /// Either TaskIndex is not 0 on the first call or is not recognized value (on subsequent calls). /// /// /// ERROR_INVALID_TASK_NAME /// The specified task does not match any of the tasks stored in the registry. /// /// /// ERROR_PRIVILEGE_NOT_HELD /// The caller does not have sufficient privilege. /// /// /// /// /// When the task is completed, call the AvRevertMmThreadCharacteristics function. /// /// Note /// /// The avrt.h header defines AvSetMmThreadCharacteristics as an alias which automatically selects the ANSI or Unicode version of this /// function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not /// encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for /// Function Prototypes. /// /// /// // https://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avsetmmthreadcharacteristicsa AVRTAPI HANDLE // AvSetMmThreadCharacteristicsA( [in] LPCSTR TaskName, [in, out] LPDWORD TaskIndex ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvSetMmThreadCharacteristicsA")] [DllImport(Lib_Avrt, SetLastError = true, CharSet = CharSet.Auto)] public static extern SafeHAVRT AvSetMmThreadCharacteristics([MarshalAs(UnmanagedType.LPTStr)] string TaskName, ref uint TaskIndex); /// Adjusts the thread priority of the calling thread relative to other threads performing the same task. /// /// A handle to the task. This handle is returned by the AvSetMmThreadCharacteristics or AvSetMmMaxThreadCharacteristics function. /// /// /// /// The relative thread priority of this thread to other threads performing a similar task. This parameter can be one of the following values. /// /// AVRT_PRIORITY_CRITICAL (2) /// AVRT_PRIORITY_HIGH (1) /// AVRT_PRIORITY_LOW (-1) /// AVRT_PRIORITY_NORMAL (0) /// /// /// 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://learn.microsoft.com/en-us/windows/win32/api/avrt/nf-avrt-avsetmmthreadpriority AVRTAPI BOOL AvSetMmThreadPriority( [in] HANDLE // AvrtHandle, [in] AVRT_PRIORITY Priority ); [PInvokeData("avrt.h", MSDNShortId = "NF:avrt.AvSetMmThreadPriority")] [DllImport(Lib_Avrt, SetLastError = true, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AvSetMmThreadPriority([In] HAVRT AvrtHandle, [In] AVRT_PRIORITY Priority); /// Provides a handle to an AvRt task. [StructLayout(LayoutKind.Sequential)] public readonly struct HAVRT : IHandle { private readonly IntPtr handle; /// Initializes a new instance of the struct. /// An object that represents the pre-existing handle to use. public HAVRT(IntPtr preexistingHandle) => handle = preexistingHandle; /// Returns an invalid handle by instantiating a object with . public static HAVRT NULL => new(IntPtr.Zero); /// Gets a value indicating whether this instance is a null handle. public bool IsNull => handle == IntPtr.Zero; /// Implements the operator !. /// The handle. /// The result of the operator. public static bool operator !(HAVRT h1) => h1.IsNull; /// Performs an explicit conversion from to . /// The handle. /// The result of the conversion. public static explicit operator IntPtr(HAVRT h) => h.handle; /// Performs an implicit conversion from to . /// The pointer to a handle. /// The result of the conversion. public static implicit operator HAVRT(IntPtr h) => new(h); /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(HAVRT h1, HAVRT h2) => !(h1 == h2); /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(HAVRT h1, HAVRT h2) => h1.Equals(h2); /// public override bool Equals(object obj) => obj is HAVRT h && handle == h.handle; /// public override int GetHashCode() => handle.GetHashCode(); /// public IntPtr DangerousGetHandle() => handle; } /// Provides a for that is disposed using . public class SafeHAVRT : 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 SafeHAVRT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { } /// Initializes a new instance of the class. private SafeHAVRT() : base() { } /// Performs an implicit conversion from to . /// The safe handle instance. /// The result of the conversion. public static implicit operator HAVRT(SafeHAVRT h) => h.handle; /// protected override bool InternalReleaseHandle() => AvRevertMmThreadCharacteristics((HAVRT)handle); } }