using System; using System.Threading; namespace PaintDotNet.SystemLayer { /// /// Encapsulates an array of WaitHandles and methods for waiting on them. /// This class does not take ownership of the WaitHandles; you must still /// Dispose() them yourself. /// /// /// This class exists because System.Threading.WaitHandle.Wait[Any|All] will throw an exception /// in an STA apartment. So we must P/Invoke down to WaitForMultipleObjects(). /// public sealed class WaitHandleArray { private WaitHandle[] waitHandles; private IntPtr[] nativeHandles; /// /// The minimum value that may be passed to the constructor for initialization. /// public const int MinimumCount = 1; /// /// The maximum value that may be passed to the construct for initialization. /// public const int MaximumCount = 64; // WaitForMultipleObjects() can only wait on up to 64 objects at once /// /// Gets or sets the WaitHandle at the specified index. /// public WaitHandle this[int index] { get { return this.waitHandles[index]; } set { this.waitHandles[index] = value; this.nativeHandles[index] = value.SafeWaitHandle.DangerousGetHandle(); } } /// /// Gets the length of the array. /// public int Length { get { return this.waitHandles.Length; } } /// /// Initializes a new instance of the WaitHandleArray class. /// /// The size of the array. public WaitHandleArray(int count) { if (count < 1 || count > 64) { throw new ArgumentOutOfRangeException("count", "must be between 1 and 64, inclusive"); } this.waitHandles = new WaitHandle[count]; this.nativeHandles = new IntPtr[count]; } private uint WaitForAll(uint dwTimeout) { return SafeNativeMethods.WaitForMultipleObjects(this.nativeHandles, true, dwTimeout); } /// /// Waits for all of the WaitHandles to be signaled. /// public void WaitAll() { WaitForAll(NativeConstants.INFINITE); } public bool AreAllSignaled() { return AreAllSignaled(0); } public bool AreAllSignaled(uint msTimeout) { uint result = WaitForAll(msTimeout); if (result >= NativeConstants.WAIT_OBJECT_0 && result < NativeConstants.WAIT_OBJECT_0 + this.Length) { return true; } else { return false; } } /// /// Waits for any of the WaitHandles to be signaled. /// /// /// The index of the first item in the array that completed the wait operation. /// If this value is outside the bounds of the array, it is an indication of an /// error. /// public int WaitAny() { int returnVal = (int)SafeNativeMethods.WaitForMultipleObjects(this.nativeHandles, false, NativeConstants.INFINITE); return returnVal; } } }