diff --git a/SystemExtensions/Collections/AVLTree.cs b/SystemExtensions/Collections/AVLTree.cs index 638095c..ad5bb51 100644 --- a/SystemExtensions/Collections/AVLTree.cs +++ b/SystemExtensions/Collections/AVLTree.cs @@ -1,9 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions.Collections { @@ -14,7 +11,7 @@ namespace SystemExtensions.Collections /// /// Provided type. [Serializable] - public class AVLTree : ICollection where T : IComparable + public sealed class AVLTree : ICollection where T : IComparable { #region Fields [Serializable] @@ -36,7 +33,8 @@ namespace SystemExtensions.Collections /// /// Count of items currently stored in the tree. /// - public int Count { + public int Count + { get { return count; @@ -51,7 +49,6 @@ namespace SystemExtensions.Collections /// /// Initializes a new instance of an AVLTree collection. /// - /// public AVLTree() { @@ -83,7 +80,7 @@ namespace SystemExtensions.Collections public bool Contains(T value) { AVLNode node = Find(value, root); - if(node == null) + if (node == null) { return false; } @@ -113,16 +110,16 @@ namespace SystemExtensions.Collections Queue> queue = new Queue>(); queue.Enqueue(root); - while(queue.Count > 0) + while (queue.Count > 0) { AVLNode currentNode = queue.Dequeue(); - if(currentNode.Left != null) + if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); currentNode.Left = null; count--; } - if(currentNode.Right != null) + if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); currentNode.Right = null; @@ -293,7 +290,7 @@ namespace SystemExtensions.Collections } private AVLNode Find(T target, AVLNode current) { - if(current == null) + if (current == null) { return null; } diff --git a/SystemExtensions/Collections/BinaryHeap.cs b/SystemExtensions/Collections/BinaryHeap.cs index 398588e..1b983e1 100644 --- a/SystemExtensions/Collections/BinaryHeap.cs +++ b/SystemExtensions/Collections/BinaryHeap.cs @@ -2,8 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions.Collections { @@ -12,7 +10,7 @@ namespace SystemExtensions.Collections /// /// Provided type. [Serializable] - public class BinaryHeap : IEnumerable where T : IComparable + public sealed class BinaryHeap : IEnumerable where T : IComparable { #region Fields T[] items; @@ -42,10 +40,12 @@ namespace SystemExtensions.Collections /// /// Capacity of the heap. /// - public int Capacity { get => capacity; + public int Capacity + { + get => capacity; set { - if(value > capacity) + if (value > capacity) { Array.Resize(ref items, value); capacity = value; @@ -61,7 +61,6 @@ namespace SystemExtensions.Collections /// /// Constructor for a binary heap data structure. /// - /// Function used to compare the elements. public BinaryHeap() { capacity = 10; @@ -71,7 +70,6 @@ namespace SystemExtensions.Collections /// /// Constructor for a binary heap data structure. /// - /// Function used to compare the elements. /// Initial capacity of the heap. Used for initial alocation of the array. public BinaryHeap(int capacity) { @@ -87,7 +85,7 @@ namespace SystemExtensions.Collections /// Value to be added. public void Add(T value) { - if(count == Capacity - 1) + if (count == Capacity - 1) { Capacity = 2 * Capacity; } @@ -168,7 +166,7 @@ namespace SystemExtensions.Collections /// Enumerator that iterates over the heap. public IEnumerator GetEnumerator() { - for(int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { yield return items[i + 1]; } @@ -183,14 +181,14 @@ namespace SystemExtensions.Collections { T temp = items[index]; int childIndex = 0; - for(; 2*index <= count; index = childIndex) + for (; 2 * index <= count; index = childIndex) { childIndex = 2 * index; - if(childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0) + if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0) { childIndex++; } - if(temp.CompareTo(items[childIndex]) > 0) + if (temp.CompareTo(items[childIndex]) > 0) { items[index] = items[childIndex]; } @@ -206,7 +204,7 @@ namespace SystemExtensions.Collections /// private void BuildHeap() { - for(int i = count / 2; i > 0; i--) + for (int i = count / 2; i > 0; i--) { BubbleDown(i); } diff --git a/SystemExtensions/Collections/FibonacciHeap.cs b/SystemExtensions/Collections/FibonacciHeap.cs index d364727..a36dce0 100644 --- a/SystemExtensions/Collections/FibonacciHeap.cs +++ b/SystemExtensions/Collections/FibonacciHeap.cs @@ -1,9 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions.Collections { @@ -12,7 +9,7 @@ namespace SystemExtensions.Collections /// /// Provided type [Serializable] - public class FibonacciHeap : IEnumerable where T : IComparable + public sealed class FibonacciHeap : IEnumerable where T : IComparable { #region Fields private FibonacciNode root; @@ -44,7 +41,6 @@ namespace SystemExtensions.Collections /// /// Constructor for Fibonacci heap data structure. /// - /// Function used to compare the elements. public FibonacciHeap() { @@ -131,7 +127,7 @@ namespace SystemExtensions.Collections /// Array with values from the heap. public T[] ToArray() { - if(count == 0) + if (count == 0) { return null; } @@ -186,7 +182,7 @@ namespace SystemExtensions.Collections { Queue> queue = new Queue>(); queue.Enqueue(currentNode); - while(queue.Count > 0) + while (queue.Count > 0) { currentNode = queue.Dequeue(); FibonacciNode oldNode = currentNode; @@ -199,8 +195,8 @@ namespace SystemExtensions.Collections } currentNode = currentNode.Previous; } while (currentNode != oldNode); - } - + } + } /// /// Recursively remove the node and its children from the heap. @@ -208,7 +204,7 @@ namespace SystemExtensions.Collections /// Node to be removed. private void Remove(FibonacciNode node) { - if(node != null) + if (node != null) { FibonacciNode current = node; do @@ -230,15 +226,15 @@ namespace SystemExtensions.Collections /// Root of second heap. private FibonacciNode Merge(FibonacciNode node1, FibonacciNode node2) { - if(node1 == null) + if (node1 == null) { return node2; } - if(node2 == null) + if (node2 == null) { return node1; } - if(node1.Value.CompareTo(node2.Value) > 0) + if (node1.Value.CompareTo(node2.Value) > 0) { FibonacciNode temp = node1; node1 = node2; @@ -270,7 +266,7 @@ namespace SystemExtensions.Collections /// Node to be removed from its parent. private void RemoveParent(FibonacciNode node) { - if(node == null) + if (node == null) { return; } @@ -290,7 +286,7 @@ namespace SystemExtensions.Collections private FibonacciNode RemoveMinimum(FibonacciNode node) { RemoveParent(node.Child); - if(node.Next == node) + if (node.Next == node) { node = node.Child; } @@ -300,7 +296,7 @@ namespace SystemExtensions.Collections node.Previous.Next = node.Next; node = Merge(node.Next, node.Child); } - if(node == null) + if (node == null) { return node; } @@ -308,15 +304,15 @@ namespace SystemExtensions.Collections FibonacciNode[] trees = new FibonacciNode[64]; while (true) { - if(trees[node.Degree] != null) + if (trees[node.Degree] != null) { FibonacciNode t = trees[node.Degree]; - if(t == node) + if (t == node) { break; } trees[node.Degree] = null; - if(node.Value.CompareTo(t.Value) < 0) + if (node.Value.CompareTo(t.Value) < 0) { t.Previous.Next = t.Next; t.Next.Previous = t.Previous; @@ -326,7 +322,7 @@ namespace SystemExtensions.Collections { t.Previous.Next = t.Next; t.Next.Previous = t.Previous; - if(node.Next == node) + if (node.Next == node) { t.Next = t.Previous = t; AddChild(t, node); @@ -354,7 +350,7 @@ namespace SystemExtensions.Collections FibonacciNode start = node; do { - if(node.Value.CompareTo(min.Value) < 0) + if (node.Value.CompareTo(min.Value) < 0) { min = node; } @@ -370,7 +366,7 @@ namespace SystemExtensions.Collections /// private FibonacciNode Cut(FibonacciNode root, FibonacciNode node) { - if(node.Next == node) + if (node.Next == node) { node.Parent.Child = null; } @@ -393,26 +389,26 @@ namespace SystemExtensions.Collections /// private FibonacciNode DecreaseKey(FibonacciNode root, FibonacciNode node, T value) { - if(node.Value.CompareTo(value) < 0) + if (node.Value.CompareTo(value) < 0) { return root; } node.Value = value; - if(node.Parent != null) + if (node.Parent != null) { - if(node.Value.CompareTo(node.Parent.Value) < 0) + if (node.Value.CompareTo(node.Parent.Value) < 0) { root = Cut(root, node); FibonacciNode parent = node.Parent; node.Parent = null; - while(parent != null && parent.Marked) + while (parent != null && parent.Marked) { root = Cut(root, parent); node = parent; parent = node.Parent; node.Parent = null; } - if(parent != null && parent.Parent != null) + if (parent != null && parent.Parent != null) { parent.Marked = true; } @@ -420,7 +416,7 @@ namespace SystemExtensions.Collections } else { - if(node.Value.CompareTo(root.Value) < 0) + if (node.Value.CompareTo(root.Value) < 0) { root = node; } @@ -436,18 +432,18 @@ namespace SystemExtensions.Collections private FibonacciNode Find(FibonacciNode root, T value) { FibonacciNode node = root; - if(node == null) + if (node == null) { return null; } do { - if(node.Value.CompareTo(value) == 0) + if (node.Value.CompareTo(value) == 0) { return node; } FibonacciNode ret = Find(node.Child, value); - if(ret != null) + if (ret != null) { return ret; } @@ -462,7 +458,7 @@ namespace SystemExtensions.Collections #endregion } [Serializable] - internal class FibonacciNode + internal sealed class FibonacciNode { #region Fields private FibonacciNode previous; @@ -537,7 +533,7 @@ namespace SystemExtensions.Collections } set { - this.value = value; + this.value = value; } } public int Degree diff --git a/SystemExtensions/Collections/IQueue.cs b/SystemExtensions/Collections/IQueue.cs index c0cbfd1..2078f77 100644 --- a/SystemExtensions/Collections/IQueue.cs +++ b/SystemExtensions/Collections/IQueue.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; namespace SystemExtensions.Collections { diff --git a/SystemExtensions/Collections/PriorityQueue.cs b/SystemExtensions/Collections/PriorityQueue.cs index d4f6b21..b3b186c 100644 --- a/SystemExtensions/Collections/PriorityQueue.cs +++ b/SystemExtensions/Collections/PriorityQueue.cs @@ -1,9 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions.Collections { @@ -13,7 +10,7 @@ namespace SystemExtensions.Collections /// /// Provided type. [Serializable] - public class PriorityQueue : IQueue where T : IComparable + public sealed class PriorityQueue : IQueue where T : IComparable { #region Fields private BinaryHeap binaryHeap; @@ -34,7 +31,6 @@ namespace SystemExtensions.Collections /// /// Constructor for priority queue data structure. /// - /// Function used to compare the elements. public PriorityQueue() { binaryHeap = new BinaryHeap(); diff --git a/SystemExtensions/Collections/SkipList.cs b/SystemExtensions/Collections/SkipList.cs index 66963cd..5ff5534 100644 --- a/SystemExtensions/Collections/SkipList.cs +++ b/SystemExtensions/Collections/SkipList.cs @@ -1,9 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions.Collections { @@ -12,7 +9,7 @@ namespace SystemExtensions.Collections /// /// Provided type. [Serializable] - public class SkipList : ICollection where T : IComparable + public sealed class SkipList : ICollection where T : IComparable { #region Fields [Serializable] @@ -53,11 +50,11 @@ namespace SystemExtensions.Collections /// Maximum level of the skip list. public SkipList(int maxLevel = 10) { - this.maxLevel = maxLevel; + this.maxLevel = maxLevel; random = new Random(); head = new NodeSet(default(T), maxLevel); end = head; - for(int i = 0; i <= maxLevel; i++) + for (int i = 0; i <= maxLevel; i++) { head.Next[i] = end; } @@ -84,7 +81,7 @@ namespace SystemExtensions.Collections NodeSet newNode = new NodeSet(item, newLevel); for (var i = 0; i <= newLevel; i++) { - if(i > curNode.Level) + if (i > curNode.Level) { curNode = head; } @@ -108,7 +105,7 @@ namespace SystemExtensions.Collections NodeSet curNode = head; for (var i = 0; i <= maxLevel; i++) { - if(i > curNode.Level) + if (i > curNode.Level) { curNode = head; } @@ -141,7 +138,7 @@ namespace SystemExtensions.Collections /// public void Clear() { - for(int i = 0; i < maxLevel; i++) + for (int i = 0; i < maxLevel; i++) { head.Next[i] = end; } @@ -154,7 +151,7 @@ namespace SystemExtensions.Collections /// True if item is present in the collection. public bool Contains(T item) { - if(Find(item) != null) + if (Find(item) != null) { return true; } @@ -168,7 +165,7 @@ namespace SystemExtensions.Collections public void CopyTo(T[] array, int arrayIndex) { NodeSet node = head.Next[0]; - while(node != end) + while (node != end) { array[arrayIndex] = node.Key; arrayIndex++; @@ -184,7 +181,7 @@ namespace SystemExtensions.Collections T[] array = new T[count]; int index = 0; NodeSet curNode = head.Next[0]; - while(curNode != end) + while (curNode != end) { array[index] = curNode.Key; index++; @@ -199,7 +196,7 @@ namespace SystemExtensions.Collections public IEnumerator GetEnumerator() { NodeSet curNode = head.Next[0]; - while(curNode != end) + while (curNode != end) { yield return curNode.Key; curNode = curNode.Next[0]; @@ -215,15 +212,15 @@ namespace SystemExtensions.Collections { NodeSet curNode = head; - for(int i = level; i >= 0; i--) + for (int i = level; i >= 0; i--) { - while(curNode.Next[i] != end) + while (curNode.Next[i] != end) { - if(curNode.Next[i].Key.CompareTo(key) > 0) + if (curNode.Next[i].Key.CompareTo(key) > 0) { break; } - else if(curNode.Next[i].Key.CompareTo(key) == 0) + else if (curNode.Next[i].Key.CompareTo(key) == 0) { return curNode.Next[i]; } @@ -232,7 +229,7 @@ namespace SystemExtensions.Collections } curNode = curNode.Next[0]; - if(curNode != end && curNode.Key.CompareTo(key) == 0) + if (curNode != end && curNode.Key.CompareTo(key) == 0) { return curNode; } diff --git a/SystemExtensions/Collections/Treap.cs b/SystemExtensions/Collections/Treap.cs index 3615634..88c1499 100644 --- a/SystemExtensions/Collections/Treap.cs +++ b/SystemExtensions/Collections/Treap.cs @@ -1,9 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions.Collections { @@ -12,7 +9,7 @@ namespace SystemExtensions.Collections /// /// Provided type. [Serializable] - public class Treap : ICollection where T : IComparable + public sealed class Treap : ICollection where T : IComparable { #region Fields [Serializable] @@ -44,14 +41,15 @@ namespace SystemExtensions.Collections return count; } } - - public bool IsReadOnly => throw new NotImplementedException(); + /// + /// Not implemented. + /// + public bool IsReadOnly => false; #endregion #region Constructors /// /// Constructor for treap. /// - /// Comparator method used to compare values. public Treap() { randomGen = new Random(); @@ -134,14 +132,15 @@ namespace SystemExtensions.Collections #region Private Methods private Node InsertNode(Node node, T key) { - if(node == null) { + if (node == null) + { node = new Node(key, randomGen.Next(0, 100)); return node; } else if (key.CompareTo(node.Key) <= 0) { node.Left = InsertNode(node.Left, key); - if(node.Left.Priority > node.Priority) + if (node.Left.Priority > node.Priority) { node = RotateRight(node); } @@ -149,7 +148,7 @@ namespace SystemExtensions.Collections else { node.Right = InsertNode(node.Right, key); - if(node.Right.Priority > node.Priority) + if (node.Right.Priority > node.Priority) { node = RotateLeft(node); } @@ -158,27 +157,27 @@ namespace SystemExtensions.Collections } private Node RemoveNode(Node node, T key) { - if(node == null) + if (node == null) { - return node; + return node; } - if(key.CompareTo(node.Key) < 0) + if (key.CompareTo(node.Key) < 0) { node.Left = RemoveNode(node.Left, key); } - else if(key.CompareTo(node.Key) > 0) + else if (key.CompareTo(node.Key) > 0) { node.Right = RemoveNode(node.Right, key); - } + } else if (node.Left == null) { node = node.Right; } - else if(node.Right == null) + else if (node.Right == null) { node = node.Left; } - else if(node.Left.Priority < node.Right.Priority) + else if (node.Left.Priority < node.Right.Priority) { node = RotateLeft(node); node.Left = RemoveNode(node.Left, key); @@ -206,11 +205,11 @@ namespace SystemExtensions.Collections } private void Clear(Node node) { - if(node.Left != null) + if (node.Left != null) { Clear(node.Left); } - if(node.Right != null) + if (node.Right != null) { Clear(node.Right); } @@ -218,22 +217,22 @@ namespace SystemExtensions.Collections } private Node Find(Node node, T key) { - if(node == null) + if (node == null) { return node; } else { - if(node.Key.CompareTo(key) < 0) + if (node.Key.CompareTo(key) < 0) { Node found = Find(node.Left, key); - if(found == null) + if (found == null) { found = Find(node.Right, key); } return found; } - else if(node.Key.CompareTo(key) > 0) + else if (node.Key.CompareTo(key) > 0) { Node found = Find(node.Right, key); if (found == null) @@ -250,7 +249,7 @@ namespace SystemExtensions.Collections } private void ToArray(Node node, ref T[] array, ref int index) { - if(node != null) + if (node != null) { ToArray(node.Left, ref array, ref index); array[index] = node.Key; @@ -262,15 +261,15 @@ namespace SystemExtensions.Collections { Queue> queue = new Queue>(); queue.Enqueue(currentNode); - while(queue.Count > 0) + while (queue.Count > 0) { currentNode = queue.Dequeue(); yield return currentNode.Key; - if(currentNode.Left != null) + if (currentNode.Left != null) { queue.Enqueue(currentNode.Left); } - if(currentNode.Right != null) + if (currentNode.Right != null) { queue.Enqueue(currentNode.Right); } diff --git a/SystemExtensions/ItemNotFoundException.cs b/SystemExtensions/ItemNotFoundException.cs index def126c..db5a36a 100644 --- a/SystemExtensions/ItemNotFoundException.cs +++ b/SystemExtensions/ItemNotFoundException.cs @@ -1,14 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SystemExtensions { /// /// Custom implementation of an exception. /// + [Serializable] public class ItemNotFoundException : Exception { /// diff --git a/SystemExtensions/Properties/AssemblyInfo.cs b/SystemExtensions/Properties/AssemblyInfo.cs index 327d7c0..493de4d 100644 --- a/SystemExtensions/Properties/AssemblyInfo.cs +++ b/SystemExtensions/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/SystemExtensions/Security/ProcessInformation.cs b/SystemExtensions/Security/ProcessInformation.cs new file mode 100644 index 0000000..1c49ea3 --- /dev/null +++ b/SystemExtensions/Security/ProcessInformation.cs @@ -0,0 +1,793 @@ +using Microsoft.Win32.SafeHandles; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Text.RegularExpressions; + +namespace SystemExtensions.Security +{ + /// + /// Helper class to obtain admin privileges and elevation status. + /// + /// Source code provided on https://code.msdn.microsoft.com/windowsapps/CSUACSelfElevation-644673d3 + public static class ProcessInformation + { + /// + /// The function checks whether the primary access token of the process belongs + /// to user account that is a member of the local Administrators group, even if + /// it currently is not elevated. + /// + /// + /// Returns true if the primary access token of the process belongs to user + /// account that is a member of the local Administrators group. Returns false + /// if the token does not. + /// + /// + /// When any native Windows API call fails, the function throws a Win32Exception + /// with the last error code. + /// + public static bool IsUserInAdminGroup() + { + bool fInAdminGroup = false; + SafeTokenHandle hToken = null; + SafeTokenHandle hTokenToCheck = null; + IntPtr pElevationType = IntPtr.Zero; + IntPtr pLinkedToken = IntPtr.Zero; + int cbSize = 0; + + try + { + // Open the access token of the current process for query and duplicate. + if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, + NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_DUPLICATE, out hToken)) + { + throw new Win32Exception(); + } + + // Determine whether system is running Windows Vista or later operating + // systems (major version >= 6) because they support linked tokens, but + // previous versions (major version < 6) do not. + if (Environment.OSVersion.Version.Major >= 6) + { + // Running Windows Vista or later (major version >= 6). + // Determine token type: limited, elevated, or default. + + // Allocate a buffer for the elevation type information. + cbSize = sizeof(TOKEN_ELEVATION_TYPE); + pElevationType = Marshal.AllocHGlobal(cbSize); + if (pElevationType == IntPtr.Zero) + { + throw new Win32Exception(); + } + + // Retrieve token elevation type information. + if (!NativeMethods.GetTokenInformation(hToken, + TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, + cbSize, out cbSize)) + { + throw new Win32Exception(); + } + + // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET. + TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE) + Marshal.ReadInt32(pElevationType); + + // If limited, get the linked elevated token for further check. + if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) + { + // Allocate a buffer for the linked token. + cbSize = IntPtr.Size; + pLinkedToken = Marshal.AllocHGlobal(cbSize); + if (pLinkedToken == IntPtr.Zero) + { + throw new Win32Exception(); + } + + // Get the linked token. + if (!NativeMethods.GetTokenInformation(hToken, + TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, + cbSize, out cbSize)) + { + throw new Win32Exception(); + } + + // Marshal the linked token value from native to .NET. + IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken); + hTokenToCheck = new SafeTokenHandle(hLinkedToken); + } + } + + // CheckTokenMembership requires an impersonation token. If we just got + // a linked token, it already is an impersonation token. If we did not + // get a linked token, duplicate the original into an impersonation + // token for CheckTokenMembership. + if (hTokenToCheck == null) + { + if (!NativeMethods.DuplicateToken(hToken, + SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, + out hTokenToCheck)) + { + throw new Win32Exception(); + } + } + + // Check if the token to be checked contains admin SID. + WindowsIdentity id = new WindowsIdentity(hTokenToCheck.DangerousGetHandle()); + WindowsPrincipal principal = new WindowsPrincipal(id); + fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator); + } + finally + { + // Centralized cleanup for all allocated resources. + if (hToken != null) + { + hToken.Close(); + hToken = null; + } + if (hTokenToCheck != null) + { + hTokenToCheck.Close(); + hTokenToCheck = null; + } + if (pElevationType != IntPtr.Zero) + { + Marshal.FreeHGlobal(pElevationType); + pElevationType = IntPtr.Zero; + } + if (pLinkedToken != IntPtr.Zero) + { + Marshal.FreeHGlobal(pLinkedToken); + pLinkedToken = IntPtr.Zero; + } + } + + return fInAdminGroup; + } + + + /// + /// The function checks whether the current process is run as administrator. + /// In other words, it dictates whether the primary access token of the + /// process belongs to user account that is a member of the local + /// Administrators group and it is elevated. + /// + /// + /// Returns true if the primary access token of the process belongs to user + /// account that is a member of the local Administrators group and it is + /// elevated. Returns false if the token does not. + /// + public static bool IsRunAsAdmin() + { + WindowsIdentity id = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new WindowsPrincipal(id); + return principal.IsInRole(WindowsBuiltInRole.Administrator); + } + + + /// + /// The function gets the elevation information of the current process. It + /// dictates whether the process is elevated or not. Token elevation is only + /// available on Windows Vista and newer operating systems, thus + /// IsProcessElevated throws a C++ exception if it is called on systems prior + /// to Windows Vista. It is not appropriate to use this function to determine + /// whether a process is run as administartor. + /// + /// + /// Returns true if the process is elevated. Returns false if it is not. + /// + /// + /// When any native Windows API call fails, the function throws a Win32Exception + /// with the last error code. + /// + /// + /// TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation + /// type (TokenElevationTypeDefault / TokenElevationTypeLimited / + /// TokenElevationTypeFull) of the process. It is different from TokenElevation + /// in that, when UAC is turned off, elevation type always returns + /// TokenElevationTypeDefault even though the process is elevated (Integrity + /// Level == High). In other words, it is not safe to say if the process is + /// elevated based on elevation type. Instead, we should use TokenElevation. + /// + public static bool IsProcessElevated() + { + bool fIsElevated = false; + SafeTokenHandle hToken = null; + int cbTokenElevation = 0; + IntPtr pTokenElevation = IntPtr.Zero; + + try + { + // Open the access token of the current process with TOKEN_QUERY. + if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, + NativeMethods.TOKEN_QUERY, out hToken)) + { + throw new Win32Exception(); + } + + // Allocate a buffer for the elevation information. + cbTokenElevation = Marshal.SizeOf(typeof(TOKEN_ELEVATION)); + pTokenElevation = Marshal.AllocHGlobal(cbTokenElevation); + if (pTokenElevation == IntPtr.Zero) + { + throw new Win32Exception(); + } + + // Retrieve token elevation information. + if (!NativeMethods.GetTokenInformation(hToken, + TOKEN_INFORMATION_CLASS.TokenElevation, pTokenElevation, + cbTokenElevation, out cbTokenElevation)) + { + // When the process is run on operating systems prior to Windows + // Vista, GetTokenInformation returns false with the error code + // ERROR_INVALID_PARAMETER because TokenElevation is not supported + // on those operating systems. + throw new Win32Exception(); + } + + // Marshal the TOKEN_ELEVATION struct from native to .NET object. + TOKEN_ELEVATION elevation = (TOKEN_ELEVATION)Marshal.PtrToStructure( + pTokenElevation, typeof(TOKEN_ELEVATION)); + + // TOKEN_ELEVATION.TokenIsElevated is a non-zero value if the token + // has elevated privileges; otherwise, a zero value. + fIsElevated = (elevation.TokenIsElevated != 0); + } + finally + { + // Centralized cleanup for all allocated resources. + if (hToken != null) + { + hToken.Close(); + hToken = null; + } + if (pTokenElevation != IntPtr.Zero) + { + Marshal.FreeHGlobal(pTokenElevation); + pTokenElevation = IntPtr.Zero; + cbTokenElevation = 0; + } + } + + return fIsElevated; + } + + + /// + /// The function gets the integrity level of the current process. Integrity + /// level is only available on Windows Vista and newer operating systems, thus + /// GetProcessIntegrityLevel throws a C++ exception if it is called on systems + /// prior to Windows Vista. + /// + /// + /// Returns the integrity level of the current process. It is usually one of + /// these values: + /// + /// SECURITY_MANDATORY_UNTRUSTED_RID - means untrusted level. It is used + /// by processes started by the Anonymous group. Blocks most write access. + /// (SID: S-1-16-0x0) + /// + /// SECURITY_MANDATORY_LOW_RID - means low integrity level. It is used by + /// Protected Mode Internet Explorer. Blocks write acess to most objects + /// (such as files and registry keys) on the system. (SID: S-1-16-0x1000) + /// + /// SECURITY_MANDATORY_MEDIUM_RID - means medium integrity level. It is + /// used by normal applications being launched while UAC is enabled. + /// (SID: S-1-16-0x2000) + /// + /// SECURITY_MANDATORY_HIGH_RID - means high integrity level. It is used + /// by administrative applications launched through elevation when UAC is + /// enabled, or normal applications if UAC is disabled and the user is an + /// administrator. (SID: S-1-16-0x3000) + /// + /// SECURITY_MANDATORY_SYSTEM_RID - means system integrity level. It is + /// used by services and other system-level applications (such as Wininit, + /// Winlogon, Smss, etc.) (SID: S-1-16-0x4000) + /// + /// + /// + /// When any native Windows API call fails, the function throws a Win32Exception + /// with the last error code. + /// + public static int GetProcessIntegrityLevel() + { + int IL = -1; + SafeTokenHandle hToken = null; + int cbTokenIL = 0; + IntPtr pTokenIL = IntPtr.Zero; + + try + { + // Open the access token of the current process with TOKEN_QUERY. + if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, + NativeMethods.TOKEN_QUERY, out hToken)) + { + throw new Win32Exception(); + } + + // Then we must query the size of the integrity level information + // associated with the token. Note that we expect GetTokenInformation + // to return false with the ERROR_INSUFFICIENT_BUFFER error code + // because we've given it a null buffer. On exit cbTokenIL will tell + // the size of the group information. + if (!NativeMethods.GetTokenInformation(hToken, + TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, IntPtr.Zero, 0, + out cbTokenIL)) + { + int error = Marshal.GetLastWin32Error(); + if (error != NativeMethods.ERROR_INSUFFICIENT_BUFFER) + { + // When the process is run on operating systems prior to + // Windows Vista, GetTokenInformation returns false with the + // ERROR_INVALID_PARAMETER error code because + // TokenIntegrityLevel is not supported on those OS's. + throw new Win32Exception(error); + } + } + + // Now we allocate a buffer for the integrity level information. + pTokenIL = Marshal.AllocHGlobal(cbTokenIL); + if (pTokenIL == IntPtr.Zero) + { + throw new Win32Exception(); + } + + // Now we ask for the integrity level information again. This may fail + // if an administrator has added this account to an additional group + // between our first call to GetTokenInformation and this one. + if (!NativeMethods.GetTokenInformation(hToken, + TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenIL, cbTokenIL, + out cbTokenIL)) + { + throw new Win32Exception(); + } + + // Marshal the TOKEN_MANDATORY_LABEL struct from native to .NET object. + TOKEN_MANDATORY_LABEL tokenIL = (TOKEN_MANDATORY_LABEL) + Marshal.PtrToStructure(pTokenIL, typeof(TOKEN_MANDATORY_LABEL)); + + // Integrity Level SIDs are in the form of S-1-16-0xXXXX. (e.g. + // S-1-16-0x1000 stands for low integrity level SID). There is one + // and only one subauthority. + IntPtr pIL = NativeMethods.GetSidSubAuthority(tokenIL.Label.Sid, 0); + IL = Marshal.ReadInt32(pIL); + } + finally + { + // Centralized cleanup for all allocated resources. + if (hToken != null) + { + hToken.Close(); + hToken = null; + } + if (pTokenIL != IntPtr.Zero) + { + Marshal.FreeHGlobal(pTokenIL); + pTokenIL = IntPtr.Zero; + cbTokenIL = 0; + } + } + + return IL; + } + + /// + /// Elevate process to administration rights. + /// + /// True if the elevation succeeded or false if it failed. + public static bool ElevateProcess() + { + if (!IsRunAsAdmin()) + { + // Launch itself as administrator + ProcessStartInfo proc = new ProcessStartInfo(); + proc.UseShellExecute = true; + proc.WorkingDirectory = Environment.CurrentDirectory; + proc.FileName = Process.GetCurrentProcess().MainModule.FileName; + proc.Verb = "runas"; + + + try + { + Process.Start(proc); + Process.GetCurrentProcess().Close(); // Quit itself + return true; + } + catch + { + // The user refused the elevation. + // Do nothing and return directly ... + return false; + } + } + else + { + return true; + } + } + + /// + /// Gets the application path of the running assembly. + /// + /// String containing the path to the executing assembly. + public static string GetApplicationPath() + { + var exePath = Path.GetDirectoryName(System.Reflection + .Assembly.GetExecutingAssembly().CodeBase); + Regex appPathMatcher = new Regex(@"(? + /// The TOKEN_INFORMATION_CLASS enumeration type contains values that + /// specify the type of information being assigned to or retrieved from + /// an access token. + /// + internal enum TOKEN_INFORMATION_CLASS + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, + MaxTokenInfoClass + } + + /// + /// The WELL_KNOWN_SID_TYPE enumeration type is a list of commonly used + /// security identifiers (SIDs). Programs can pass these values to the + /// CreateWellKnownSid function to create a SID from this list. + /// + internal enum WELL_KNOWN_SID_TYPE + { + WinNullSid = 0, + WinWorldSid = 1, + WinLocalSid = 2, + WinCreatorOwnerSid = 3, + WinCreatorGroupSid = 4, + WinCreatorOwnerServerSid = 5, + WinCreatorGroupServerSid = 6, + WinNtAuthoritySid = 7, + WinDialupSid = 8, + WinNetworkSid = 9, + WinBatchSid = 10, + WinInteractiveSid = 11, + WinServiceSid = 12, + WinAnonymousSid = 13, + WinProxySid = 14, + WinEnterpriseControllersSid = 15, + WinSelfSid = 16, + WinAuthenticatedUserSid = 17, + WinRestrictedCodeSid = 18, + WinTerminalServerSid = 19, + WinRemoteLogonIdSid = 20, + WinLogonIdsSid = 21, + WinLocalSystemSid = 22, + WinLocalServiceSid = 23, + WinNetworkServiceSid = 24, + WinBuiltinDomainSid = 25, + WinBuiltinAdministratorsSid = 26, + WinBuiltinUsersSid = 27, + WinBuiltinGuestsSid = 28, + WinBuiltinPowerUsersSid = 29, + WinBuiltinAccountOperatorsSid = 30, + WinBuiltinSystemOperatorsSid = 31, + WinBuiltinPrintOperatorsSid = 32, + WinBuiltinBackupOperatorsSid = 33, + WinBuiltinReplicatorSid = 34, + WinBuiltinPreWindows2000CompatibleAccessSid = 35, + WinBuiltinRemoteDesktopUsersSid = 36, + WinBuiltinNetworkConfigurationOperatorsSid = 37, + WinAccountAdministratorSid = 38, + WinAccountGuestSid = 39, + WinAccountKrbtgtSid = 40, + WinAccountDomainAdminsSid = 41, + WinAccountDomainUsersSid = 42, + WinAccountDomainGuestsSid = 43, + WinAccountComputersSid = 44, + WinAccountControllersSid = 45, + WinAccountCertAdminsSid = 46, + WinAccountSchemaAdminsSid = 47, + WinAccountEnterpriseAdminsSid = 48, + WinAccountPolicyAdminsSid = 49, + WinAccountRasAndIasServersSid = 50, + WinNTLMAuthenticationSid = 51, + WinDigestAuthenticationSid = 52, + WinSChannelAuthenticationSid = 53, + WinThisOrganizationSid = 54, + WinOtherOrganizationSid = 55, + WinBuiltinIncomingForestTrustBuildersSid = 56, + WinBuiltinPerfMonitoringUsersSid = 57, + WinBuiltinPerfLoggingUsersSid = 58, + WinBuiltinAuthorizationAccessSid = 59, + WinBuiltinTerminalServerLicenseServersSid = 60, + WinBuiltinDCOMUsersSid = 61, + WinBuiltinIUsersSid = 62, + WinIUserSid = 63, + WinBuiltinCryptoOperatorsSid = 64, + WinUntrustedLabelSid = 65, + WinLowLabelSid = 66, + WinMediumLabelSid = 67, + WinHighLabelSid = 68, + WinSystemLabelSid = 69, + WinWriteRestrictedCodeSid = 70, + WinCreatorOwnerRightsSid = 71, + WinCacheablePrincipalsGroupSid = 72, + WinNonCacheablePrincipalsGroupSid = 73, + WinEnterpriseReadonlyControllersSid = 74, + WinAccountReadonlyControllersSid = 75, + WinBuiltinEventLogReadersGroup = 76, + WinNewEnterpriseReadonlyControllersSid = 77, + WinBuiltinCertSvcDComAccessGroup = 78 + } + + /// + /// The SECURITY_IMPERSONATION_LEVEL enumeration type contains values + /// that specify security impersonation levels. Security impersonation + /// levels govern the degree to which a server process can act on behalf + /// of a client process. + /// + internal enum SECURITY_IMPERSONATION_LEVEL + { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation + } + + /// + /// The TOKEN_ELEVATION_TYPE enumeration indicates the elevation type of + /// token being queried by the GetTokenInformation function or set by + /// the SetTokenInformation function. + /// + internal enum TOKEN_ELEVATION_TYPE + { + TokenElevationTypeDefault = 1, + TokenElevationTypeFull, + TokenElevationTypeLimited + } + + /// + /// The structure represents a security identifier (SID) and its + /// attributes. SIDs are used to uniquely identify users or groups. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct SID_AND_ATTRIBUTES + { + public IntPtr Sid; + public UInt32 Attributes; + } + + /// + /// The structure indicates whether a token has elevated privileges. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct TOKEN_ELEVATION + { + public Int32 TokenIsElevated; + } + + /// + /// The structure specifies the mandatory integrity level for a token. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct TOKEN_MANDATORY_LABEL + { + public SID_AND_ATTRIBUTES Label; + } + + /// + /// Represents a wrapper class for a token handle. + /// + internal class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeTokenHandle() : base(true) + { + } + + internal SafeTokenHandle(IntPtr handle) : base(true) + { + base.SetHandle(handle); + } + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool CloseHandle(IntPtr handle); + + protected override bool ReleaseHandle() + { + return CloseHandle(base.handle); + } + } + + internal class NativeMethods + { + // Token Specific Access Rights + + public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000; + public const UInt32 STANDARD_RIGHTS_READ = 0x00020000; + public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001; + public const UInt32 TOKEN_DUPLICATE = 0x0002; + public const UInt32 TOKEN_IMPERSONATE = 0x0004; + public const UInt32 TOKEN_QUERY = 0x0008; + public const UInt32 TOKEN_QUERY_SOURCE = 0x0010; + public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020; + public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040; + public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080; + public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100; + public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY); + public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | + TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | + TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | + TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID); + + + public const Int32 ERROR_INSUFFICIENT_BUFFER = 122; + + + // Integrity Levels + + public const Int32 SECURITY_MANDATORY_UNTRUSTED_RID = 0x00000000; + public const Int32 SECURITY_MANDATORY_LOW_RID = 0x00001000; + public const Int32 SECURITY_MANDATORY_MEDIUM_RID = 0x00002000; + public const Int32 SECURITY_MANDATORY_HIGH_RID = 0x00003000; + public const Int32 SECURITY_MANDATORY_SYSTEM_RID = 0x00004000; + + + /// + /// The function opens the access token associated with a process. + /// + /// + /// A handle to the process whose access token is opened. + /// + /// + /// Specifies an access mask that specifies the requested types of + /// access to the access token. + /// + /// + /// Outputs a handle that identifies the newly opened access token + /// when the function returns. + /// + /// + [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenProcessToken(IntPtr hProcess, + UInt32 desiredAccess, out SafeTokenHandle hToken); + + + /// + /// The function creates a new access token that duplicates one + /// already in existence. + /// + /// + /// A handle to an access token opened with TOKEN_DUPLICATE access. + /// + /// + /// Specifies a SECURITY_IMPERSONATION_LEVEL enumerated type that + /// supplies the impersonation level of the new token. + /// + /// + /// Outputs a handle to the duplicate token. + /// + /// + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public extern static bool DuplicateToken( + SafeTokenHandle ExistingTokenHandle, + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + out SafeTokenHandle DuplicateTokenHandle); + + + /// + /// The function retrieves a specified type of information about an + /// access token. The calling process must have appropriate access + /// rights to obtain the information. + /// + /// + /// A handle to an access token from which information is retrieved. + /// + /// + /// Specifies a value from the TOKEN_INFORMATION_CLASS enumerated + /// type to identify the type of information the function retrieves. + /// + /// + /// A pointer to a buffer the function fills with the requested + /// information. + /// + /// + /// Specifies the size, in bytes, of the buffer pointed to by the + /// TokenInformation parameter. + /// + /// + /// A pointer to a variable that receives the number of bytes needed + /// for the buffer pointed to by the TokenInformation parameter. + /// + /// + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + SafeTokenHandle hToken, + TOKEN_INFORMATION_CLASS tokenInfoClass, + IntPtr pTokenInfo, + Int32 tokenInfoLength, + out Int32 returnLength); + + + /// + /// Sets the elevation required state for a specified button or + /// command link to display an elevated icon. + /// + public const UInt32 BCM_SETSHIELD = 0x160C; + + + /// + /// Sends the specified message to a window or windows. The function + /// calls the window procedure for the specified window and does not + /// return until the window procedure has processed the message. + /// + /// + /// Handle to the window whose window procedure will receive the + /// message. + /// + /// Specifies the message to be sent. + /// + /// Specifies additional message-specific information. + /// + /// + /// Specifies additional message-specific information. + /// + /// + [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] + public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam); + + + /// + /// The function returns a pointer to a specified subauthority in a + /// security identifier (SID). The subauthority value is a relative + /// identifier (RID). + /// + /// + /// A pointer to the SID structure from which a pointer to a + /// subauthority is to be returned. + /// + /// + /// Specifies an index value identifying the subauthority array + /// element whose address the function will return. + /// + /// + /// If the function succeeds, the return value is a pointer to the + /// specified SID subauthority. To get extended error information, + /// call GetLastError. If the function fails, the return value is + /// undefined. The function fails if the specified SID structure is + /// not valid or if the index value specified by the nSubAuthority + /// parameter is out of bounds. + /// + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr GetSidSubAuthority(IntPtr pSid, UInt32 nSubAuthority); + } + } +} diff --git a/SystemExtensions/SystemExtensions.csproj b/SystemExtensions/SystemExtensions.csproj index 0fbb5c7..d28d10a 100644 --- a/SystemExtensions/SystemExtensions.csproj +++ b/SystemExtensions/SystemExtensions.csproj @@ -9,7 +9,7 @@ Properties SystemExtensions SystemExtensions - v4.6.1 + v4.7.2 512 true @@ -54,6 +54,7 @@ + diff --git a/SystemExtensions/Threading/PriorityThreadPool.cs b/SystemExtensions/Threading/PriorityThreadPool.cs index dd9febc..02cf0af 100644 --- a/SystemExtensions/Threading/PriorityThreadPool.cs +++ b/SystemExtensions/Threading/PriorityThreadPool.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; using SystemExtensions.Collections; namespace SystemExtensions.Threading @@ -239,7 +236,7 @@ namespace SystemExtensions.Threading { threadpool = new List(); tasks = new PriorityQueue(); - for(int i = 0; i < lowest; i++) + for (int i = 0; i < lowest; i++) { WorkerThread worker = new WorkerThread(); worker.thread = new Thread(() => @@ -304,7 +301,7 @@ namespace SystemExtensions.Threading worker.thread.Start(); threadpool.Add(worker); } - } + } #endregion #region Public Methods /// @@ -315,7 +312,7 @@ namespace SystemExtensions.Threading /// Priority of task. Affects its position into the queue. public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority) { - while (!Monitor.TryEnter(tasksLock)); + while (!Monitor.TryEnter(tasksLock)) ; tasks.Enqueue(new QueueEntry(taskPriority, waitCallback, callbackState)); Monitor.Exit(tasksLock); } @@ -384,7 +381,7 @@ namespace SystemExtensions.Threading if (statistics.Initialized) { double loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds; - if(statistics.LoopFrequency == 0) + if (statistics.LoopFrequency == 0) { statistics.LoopFrequency = loopDuration; } @@ -403,10 +400,10 @@ namespace SystemExtensions.Threading //This part of code adjusts the performance counter. Ideally, the value should be 0. - if(tasks.Count > 0) + if (tasks.Count > 0) { statistics.PerformanceCounter++; - if(statistics.PerformanceCounter > 5) + if (statistics.PerformanceCounter > 5) { statistics.PerformanceCounter = 5; } @@ -414,18 +411,18 @@ namespace SystemExtensions.Threading else { statistics.PerformanceCounter--; - if(statistics.PerformanceCounter < -10) + if (statistics.PerformanceCounter < -10) { statistics.PerformanceCounter = -10; } } //This part of code adjusts thread priorities based on the current performance of the threadpool - if(tasks.Count > 0) + if (tasks.Count > 0) { //If there are tasks pending, find a thread with priority under Normal and upgrade its priority. Thread t = FindThreadWithLowPriority(); - if(t != null) + if (t != null) { UpgradeThreadPriority(t); } @@ -434,7 +431,7 @@ namespace SystemExtensions.Threading { //If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority. Thread t = FindThreadWithAcceptablePriority(); - if(t != null) + if (t != null) { DowngradeThreadPriority(t); } @@ -460,7 +457,7 @@ namespace SystemExtensions.Threading threadpool.Add(worker); } } - else if(statistics.PerformanceCounter <= -10) + else if (statistics.PerformanceCounter <= -10) { if (threadpool.Count > maxThreads / 4) { @@ -489,9 +486,9 @@ namespace SystemExtensions.Threading /// Thread with low priority. private Thread FindThreadWithLowPriority() { - foreach(WorkerThread t in threadpool) + foreach (WorkerThread t in threadpool) { - if(t.thread.Priority == ThreadPriority.Lowest || t.thread.Priority == ThreadPriority.BelowNormal) + if (t.thread.Priority == ThreadPriority.Lowest || t.thread.Priority == ThreadPriority.BelowNormal) { return t.thread; } diff --git a/SystemExtensionsTests/SystemExtensionsTests.csproj b/SystemExtensionsTests/SystemExtensionsTests.csproj index 74d98d4..72d2c9c 100644 --- a/SystemExtensionsTests/SystemExtensionsTests.csproj +++ b/SystemExtensionsTests/SystemExtensionsTests.csproj @@ -9,7 +9,7 @@ Properties SystemExtensionsTests SystemExtensionsTests - v4.6.1 + v4.7.2 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0