TDArray.cs

Simple Concurrent Array Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
[Serializable]
public class TDArray<T> : IEnumerable<T>
{
    private          T[]               _array;
    private volatile MonitorActionFunc _maf;
    public volatile  int               Count;
    public TDArray(int cap)
    {
        _array = new T[cap];
        _maf   = new MonitorActionFunc();
        Count  = 0;
    }
    public int Length
    {
        get
        {
            var tmpThis = this;
            return tmpThis._maf.Lock(tmpThis, () => _array.Length);
        }
    }
    public T this[int index]
    {
        get
        {
            var array   = _array;
            var idx = index;
            var tmpThis = this;
            return tmpThis._maf.Lock(tmpThis, () =>
            {
                if (idx > array.Length)
                    throw new Exception("Error: Index out of range.");
                return array[idx];
            });
        }
        set
        {
            var tmpThis = this;
            var idx     = index;
            tmpThis._maf.Lock(tmpThis, () =>
            {
                if (idx >= _array.Length)
                    Array.Resize(ref _array, idx * 2);
                _array[idx] = value;
            });
        }
    }
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T item)
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            if (Count >= _array.Length)
                Array.Resize(ref _array, _array.Length + _array.Length / 4 * 3);
            _array[Count] = item;
            Interlocked.Increment(ref Count);
        });
    }
    public void Clear()
    {
        var tmpThis = this;
        tmpThis._maf.Lock(tmpThis, () =>
        {
            Array.Clear(_array, 0, _array.Length);
            Count = 0;
        });
    }
    public IEnumerator<T> GetEnumerator()
    {
        var tmpThis = this;
        return tmpThis._maf.Lock(tmpThis, () =>
        {
            return GetEnum();
        });
    }
    private IEnumerator<T> GetEnum()
    {
        var array = _array;
        var count = Count;
        for (var i = 0; i < count; i++)
            yield return array[i];
    }
}

BigIntegerPrime.cs

Generate or Test BigInteger Primes

using System;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
public class BigIntegerPrime
{
    private readonly int _bitWidth;
    private readonly int[] _lowPrimes =
    {
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
        157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
        317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
        499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677,
        683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881,
        883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
    };
    private readonly BigIntegerRng _rng;
    private readonly BigInteger    _twosixtyfour = "18446744073709551616".BigIntegerBase10();
    private readonly uint[]        _w0           = {2};
    private readonly uint[]        _w1           = {2, 3};
    private readonly uint[]        _w10          = {2, 3, 5, 7, 11, 13, 17, 19, 23};
    private readonly uint[]        _w11          = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
    private readonly uint[]        _w12          = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
    private readonly uint[]        _w2           = {31, 73};
    private readonly uint[]        _w3           = {2, 3, 5};
    private readonly uint[]        _w4           = {2, 3, 5, 7};
    private readonly uint[]        _w5           = {2, 7, 61};
    private readonly uint[]        _w6           = {2, 13, 23, 1662803};
    private readonly uint[]        _w7           = {2, 3, 5, 7, 11};
    private readonly uint[]        _w8           = {2, 3, 5, 7, 11, 13};
    private readonly uint[]        _w9           = {2, 3, 5, 7, 11, 13, 17};
    private          BigInteger    _nextPrime;
    public BigIntegerPrime(int BitWidthHint)
    {
        _rng          = new BigIntegerRng(BitWidthHint);
        _rng.Unsigned = true;
        _rng.OddsOnly = true;
        _bitWidth     = BitWidthHint;
    }
    public bool IsPrime(BigInteger candidate)
    {
        if (candidate == 1)
            return false;
        if (candidate == 2 || candidate == 3 || candidate == 5)
            return true;
        if (candidate <= 1000)
            return CheckLowPrimes(candidate);
        if (!PrimeCheckM10LD(candidate))
            return false;
        if (!PrimeCheckM6(candidate))
            return false;
        if (!TrialDivision(candidate))
            return false;
        if (candidate < 2047)
        {
            if (!MillerRabin(candidate, _w0))
                return false;
        }
        else if (candidate > 2047 && candidate <= 1373653)
        {
            if (!MillerRabin(candidate, _w1))
                return false;
        }
        else if (candidate > 1373653 && candidate <= 9080191)
        {
            if (!MillerRabin(candidate, _w2))
                return false;
        }
        else if (candidate > 9080191 && candidate <= 25326001)
        {
            if (!MillerRabin(candidate, _w3))
                return false;
        }
        else if (candidate > 25326001 && candidate <= 3215031751)
        {
            if (!MillerRabin(candidate, _w4))
                return false;
        }
        else if (candidate > 3215031751 && candidate <= 4759123141)
        {
            if (!MillerRabin(candidate, _w5))
                return false;
        }
        else if (candidate > 4759123141 && candidate <= 1122004669633)
        {
            if (!MillerRabin(candidate, _w6))
                return false;
        }
        else if (candidate > 1122004669633 && candidate <= 2152302898747)
        {
            if (!MillerRabin(candidate, _w7))
                return false;
        }
        else if (candidate > 2152302898747 && candidate <= 3474749660383)
        {
            if (!MillerRabin(candidate, _w8))
                return false;
        }
        else if (candidate > 3474749660383 && candidate <= 341550071728321)
        {
            if (!MillerRabin(candidate, _w9))
                return false;
        }
        else if (candidate > 341550071728321 && candidate <= 3825123056546413051)
        {
            if (!MillerRabin(candidate, _w10))
                return false;
        }
        else if (candidate > 3825123056546413051 && candidate < _twosixtyfour)
        {
            if (!MillerRabin(candidate, _w11))
                return false;
        }
        else if (candidate > _twosixtyfour)
        {
            if (!MillerRabin(candidate, _w12))
                return false;
        }
        return true;
    }
    private bool MillerRabin(BigInteger candidate, uint[] w)
    {
        var s = 0;
        var d = candidate - BigInteger.One;
        while ((d & 1) == 0)
        {
            d >>= 1;
            s++;
        }
        if (s == 0)
            return false;
        var nmo = candidate - BigInteger.One;
        for (var i = 0; i < w.Length; ++i)
        {
            BigInteger a;
            if (candidate > _twosixtyfour)
                a = _rng.Next(3, nmo);
            else
                a = w[i];
            var x = BigInteger.ModPow(a, d, candidate);
            if (x == 1 || x == nmo)
                continue;
            for (var r = 1; r < s; ++r)
            {
                x = BigInteger.ModPow(x, 2, candidate);
                if (x == 1)
                    return false;
                if (x == nmo)
                    break;
            }
            if (x == nmo)
                continue;
            return false;
        }
        return true;
    }
    private bool TrialDivision(BigInteger candidate)
    {
        for (var i = 0; i < _lowPrimes.Length; i++)
        {
            var p = _lowPrimes[i];
            if (i < p)
            {
                if (candidate % p != 0)
                    continue;
                return false;
            }
            break;
        }
        return true;
    }
    private static bool PrimeCheckM10LD(BigInteger n)
    {
        var d1 = (int) (n % 10);
        return d1 == 1 || d1 == 3 || d1 == 7 || d1 == 9;
    }
    private static bool PrimeCheckM6(BigInteger n)
    {
        var d1 = (int) (n % 6);
        return d1 == 1 || d1 == 5;
    }
    private bool CheckLowPrimes(BigInteger val)
    {
        foreach (var v in _lowPrimes)
            if (val == v)
                return true;
        return false;
    }
    private void NextPrime(int t)
    {
        if (t > Environment.ProcessorCount - 1)
            return;
        var MaxValue = (BigInteger.One << _bitWidth) - 1;
        while (true)
        {
            if (_nextPrime != 0)
                return;
            var n = _rng.NextFast(_bitWidth);
            if (_nextPrime != 0)
                return;
            if (n == 1)
                continue;
            if (n > MaxValue)
                continue;
            if (!IsPrime(n))
                continue;
            _nextPrime = n;
        }
    }
    public BigInteger GetPrime()
    {
        void invoke()
        {
            Parallel.Invoke(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount},
                () => NextPrime(1),
                () => NextPrime(2),
                () => NextPrime(3),
                () => NextPrime(4),
                () => NextPrime(5),
                () => NextPrime(6),
                () => NextPrime(7),
                () => NextPrime(8),
                () => NextPrime(9),
                () => NextPrime(10),
                () => NextPrime(11),
                () => NextPrime(12),
                () => NextPrime(13),
                () => NextPrime(14),
                () => NextPrime(15),
                () => NextPrime(16)
            );
        }
        _nextPrime = 0;
        var thread = new Thread(invoke) {Priority = ThreadPriority.Highest};
        thread.Start();
        thread.Join();
        return _nextPrime;
    }
}

BigIntegerRng.cs

Fast Balanced Distribution BigInteger Rng

using System;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
[Serializable]
public class BigIntegerRng : RandomNumberGenerator
{
    private int                      _bitWidth;
    private byte[]                   _buffer;
    public  RNGCryptoServiceProvider _crng;
    private BigDecimal               _dBi;
    private BigInteger               _upperLimit;
    public BigIntegerRng(int bitWidthHint)
    {
        _crng       = new RNGCryptoServiceProvider();
        _upperLimit = (BigInteger.One << bitWidthHint) - 1;
        _dBi        = new BigDecimal(1) / _upperLimit;
        _buffer     = new byte[bitWidthHint >> 3];
        _bitWidth   = bitWidthHint;
    }
    public bool OddsOnly
    {
        get;
        set;
    }
    public bool Unsigned
    {
        get;
        set;
    }
    private BigDecimal Sample(BigDecimal weight)
    {
        BigInteger Internal()
        {
            _crng.GetBytes(_buffer);
            return new BigInteger(!Unsigned ? _buffer : _buffer.Concat(new byte[] {0}).ToArray());
        }
        var        rat  = Internal() * _dBi;
        BigDecimal tens = 10;
        if (weight != 0 && weight > .9)
        {
            if (rat < weight)
            {
                var or = rat / tens + weight;
                while (or > 1)
                {
                    tens *= 10;
                    or   =  rat / tens + weight;
                }
                return or;
            }
            return rat;
        }
        return rat;
    }
    public BigInteger Next(BigInteger minValue, BigInteger maxValue)
    {
        BestBitWidth(maxValue);
        var sa = Sample(0);
        var fi = (BigDecimal) (maxValue - minValue + minValue);
        var n  = (BigInteger) (sa * fi);
        n = !OddsOnly ? n : n | 1;
        return n < minValue ? SpecialRange(minValue, maxValue) : n;
    }
    private BigInteger SpecialRange(BigInteger minValue, BigInteger maxValue)
    {
        BigInteger res;
        var        fi     = (BigDecimal) (maxValue - minValue + minValue);
        var        weight = (BigDecimal) minValue / _upperLimit;
        do
        {
            var n = (BigInteger) (Sample(weight) * fi);
            res = !OddsOnly ? n : n | 1;
        } while (res > maxValue || res < minValue);
        return res;
    }
    private void BestBitWidth(BigInteger maxValue)
    {
        var bitWidth = maxValue.GetBitWidth();
        if (_bitWidth != bitWidth)
        {
            _upperLimit = (BigInteger.One << bitWidth) - 1;
            _dBi        = new BigDecimal(1) / _upperLimit;
            _buffer     = new byte[bitWidth >> 3];
            _bitWidth   = bitWidth;
        }
    }
    public BigInteger Next(BigInteger maxValue)
    {
        return Next(0, maxValue);
    }
    public BigInteger Next()
    {
        return Next(0, _upperLimit);
    }
    public BigDecimal NextBigDecimal()
    {
        return Sample(0) * _upperLimit;
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public BigInteger NextFast(int bitWidth)
    {
        if (_bitWidth != bitWidth)
        {
            _buffer   = new byte[bitWidth >> 3];
            _bitWidth = bitWidth;
        }
        _crng.GetBytes(_buffer);
        return new BigInteger(!Unsigned ? _buffer : _buffer.Concat(new byte[] {0}).ToArray());
    }
}

BigDecimal.cs

Arbitrary Precision Signed BigDecimal

using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[DebuggerDisplay("{DDisplay}")]
public class BigDecimal : IComparable, IComparable<BigDecimal>, IEquatable<BigDecimal>
{
    private const           int          MaxFactorials    = 200;
    public static           int          MaxPrecision     = 4096 / 64 * 20; //308;
    private static readonly BigInteger   DoublePrecision  = BigInteger.Pow(10, 308);
    private static readonly BigInteger   DoubleMaxValue   = (BigInteger) double.MaxValue;
    private static readonly BigInteger   DoubleMinValue   = (BigInteger) double.MinValue;
    private static readonly BigInteger   DecimalPrecision = BigInteger.Pow(10, 28);
    private static readonly BigInteger   DecimalMaxValue  = (BigInteger) decimal.MaxValue;
    private static readonly BigInteger   DecimalMinValue  = (BigInteger) decimal.MinValue;
    private static          BigDecimal[] Factorials;
    private                 int          _scale;
    private                 BigInteger   _unscaledValue;
    public BigDecimal() : this(0, 0)
    {
    }
    public BigDecimal(BigInteger value) : this(value, 0)
    {
    }
    public BigDecimal(FixedBigInteger value) : this((BigInteger) value, 0)
    {
    }
    public BigDecimal(BigInteger value, int scale)
    {
        _unscaledValue = value;
        Scale          = scale;
    }
    public BigDecimal(long value) : this(value, 0)
    {
    }
    public BigDecimal(double value) : this((decimal) value)
    {
    }
    public BigDecimal(float value) : this((decimal) value)
    {
    }
    public BigDecimal(byte[] value)
    {
        var number = new byte[value.Length - 4];
        var flags  = new byte[4];
        Array.Copy(value, 0,                number, 0, number.Length);
        Array.Copy(value, value.Length - 4, flags,  0, 4);
        _unscaledValue = new BigInteger(number);
        Scale          = BitConverter.ToInt32(flags, 0);
    }
    public BigDecimal(BigRational value)
    {
        var num       = (BigDecimal) value.Numerator;
        var den       = (BigDecimal) value.Denominator;
        var bigDecRes = num / den;
        _unscaledValue = bigDecRes._unscaledValue;
        Scale          = bigDecRes.Scale;
    }
    public BigDecimal(decimal value)
    {
        var bytes = new byte[16];
        var bits  = decimal.GetBits(value);
        var lo    = bits[0];
        var mid   = bits[1];
        var hi    = bits[2];
        var flags = bits[3];
        bytes[0]  = (byte) lo;
        bytes[1]  = (byte) (lo >> 8);
        bytes[2]  = (byte) (lo >> 0x10);
        bytes[3]  = (byte) (lo >> 0x18);
        bytes[4]  = (byte) mid;
        bytes[5]  = (byte) (mid >> 8);
        bytes[6]  = (byte) (mid >> 0x10);
        bytes[7]  = (byte) (mid >> 0x18);
        bytes[8]  = (byte) hi;
        bytes[9]  = (byte) (hi >> 8);
        bytes[10] = (byte) (hi >> 0x10);
        bytes[11] = (byte) (hi >> 0x18);
        bytes[12] = (byte) flags;
        bytes[13] = (byte) (flags >> 8);
        bytes[14] = (byte) (flags >> 0x10);
        bytes[15] = (byte) (flags >> 0x18);
        var unscaledValueBytes = new byte[12];
        Array.Copy(bytes, unscaledValueBytes, unscaledValueBytes.Length);
        var unscaledValue = new BigInteger(unscaledValueBytes);
        var scale         = bytes[14];
        if (bytes[15] == 128)
            unscaledValue *= BigInteger.MinusOne;
        _unscaledValue = unscaledValue;
        Scale          = scale;
    }
    public BigDecimal(string value)
    {
        if (!value.ContainsOnly("0123456789+-.eE"))
            throw new Exception($"Input value must only contain these '0123456789+-.eE', value'{value}");
        var len      = value.Length;
        var start    = 0;
        var point    = 0;
        var dot      = -1;
        var negative = false;
        if (value[0] == '+')
        {
            ++start;
            ++point;
        }
        else if (value[0] == '-')
        {
            ++start;
            ++point;
            negative = true;
        }
        while (point < len)
        {
            var c = value[point];
            if (c == '.')
            {
                if (dot >= 0)
                    throw new Exception($"There are multiple '.'s in the value {value}");
                dot = point;
            }
            else if (c == 'e' || c == 'E')
            {
                break;
            }
            ++point;
        }
        string val;
        if (dot >= 0)
        {
            val   = value.Substring(start, dot) + value.Substring(dot + 1, point - (dot + 1));
            Scale = point                       - 1 - dot;
        }
        else
        {
            val   = value.Substring(start, point);
            Scale = 0;
        }
        if (val.Length == 0)
            throw new Exception($"There are no digits in the value {value}");
        if (negative)
            val = "-" + val;
        _unscaledValue = val.BigIntegerBase10();
        if (point < len)
            try
            {
                point++;
                switch (value[point])
                {
                    case '+':
                    {
                        point++;
                        if (point >= len)
                            throw new Exception($"No exponent following e or E. Value {value}");
                        var scale = value.Substring(point);
                        Scale -= int.Parse(scale);
                        return;
                    }
                    case '-':
                    {
                        point++;
                        if (point >= len)
                            throw new Exception($"No exponent following e or E. Value {value}");
                        var scale = value.Substring(point);
                        Scale += int.Parse(scale);
                        return;
                    }
                    default:
                        throw new Exception($"Malformed exponent in value {value}");
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Malformed exponent in value {value}");
            }
    }
    private string DDisplay => ToString();
    public static BigDecimal Zero
    {
        get;
    } = new BigDecimal(BigInteger.Zero);
    public static BigDecimal One
    {
        get;
    } = new BigDecimal(BigInteger.One);
    public static BigDecimal MinusOne
    {
        get;
    } = new BigDecimal(BigInteger.MinusOne);
    public bool IsEven       => _unscaledValue.IsEven;
    public bool IsOne        => _unscaledValue.IsOne;
    public bool IsPowerOfTwo => _unscaledValue.IsPowerOfTwo;
    public bool IsZero       => _unscaledValue.IsZero;
    public int  Sign         => _unscaledValue.Sign;
    public int Scale
    {
        get => _scale;
        private set => _scale = value;
    }
    public BigInteger UnscaledValue  => _unscaledValue;
    public BigDecimal WholePart      => BigInteger.Divide(_unscaledValue, BigInteger.Pow(10, Scale));
    public BigDecimal FractionalPart => this - WholePart;
    int IComparable.CompareTo(object obj)
    {
        if (obj == null)
            return 1;
        if (!(obj is BigDecimal))
            throw new Exception("Argument must be of type BigDecimal.");
        return Compare(this, (BigDecimal) obj);
    }
    public int CompareTo(BigDecimal other)
    {
        return Compare(this, other);
    }
    public bool Equals(BigDecimal other)
    {
        if (other is null)
            return false;
        return _unscaledValue == other._unscaledValue && Scale == other.Scale;
    }
    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        if (!(obj is BigDecimal))
            return false;
        return Equals((BigDecimal) obj);
    }
    public static BigDecimal Round(BigDecimal number, int decimalPlaces)
    {
        BigDecimal power = BigInteger.Pow(10, decimalPlaces);
        number *= power;
        return number >= 0 ? (BigInteger) (number + 0.5) / power : (BigInteger) (number - 0.5) / power;
    }
    public void Round(int decimalPlaces)
    {
        var        number = this;
        BigDecimal power  = BigInteger.Pow(10, decimalPlaces);
        number *= power;
        var n = number >= 0 ? (BigInteger) (number + 0.5) / power : (BigInteger) (number - 0.5) / power;
        _unscaledValue = n._unscaledValue;
        Scale          = n.Scale;
    }
    public override int GetHashCode()
    {
        return UnscaledValue.GetHashCode() ^ Scale.GetHashCode();
    }
    public string ToString()
    {
        var number = _unscaledValue.ToString("G");
        if (Scale > 0 && WholePart != 0 && number.Length - Scale >= 0)
            return number.Insert(number.Length - Scale, ".");
        StringBuilder buf;
        var           intString      = _unscaledValue.ToString();
        var           insertionPoint = intString.Length - Scale;
        if (insertionPoint == 0)
            return (Sign < 0 ? "-0." : "0.") + intString;
        if (insertionPoint > 0)
        {
            buf = new StringBuilder(intString);
            buf.Insert(insertionPoint, '.');
            if (Sign < 0)
                buf.Insert(0, '-');
        }
        else
        {
            buf = new StringBuilder(3 - insertionPoint + intString.Length);
            buf.Append(Sign < 0 ? "-0." : "0.");
            for (var i = 0; i < -insertionPoint; i++)
                buf.Append('0');
            buf.Append(intString);
        }
        if (Scale == 0)
            buf.Append("0");
        return buf.ToString();
    }
    public static BigDecimal Parse(string value)
    {
        return new BigDecimal(value);
    }
    public byte[] ToByteArray()
    {
        var unscaledValue = _unscaledValue.ToByteArray();
        var scale         = BitConverter.GetBytes(Scale);
        var bytes         = new byte[unscaledValue.Length + scale.Length];
        Array.Copy(unscaledValue, 0, bytes, 0,                    unscaledValue.Length);
        Array.Copy(scale,         0, bytes, unscaledValue.Length, scale.Length);
        return bytes;
    }
    public (byte[] unscaledValue, byte[] scale) ToByteArrays()
    {
        return (_unscaledValue.ToByteArray(), BitConverter.GetBytes(Scale));
    }
    public static BigDecimal Abs(BigDecimal value)
    {
        return value._unscaledValue.Sign < 0 ? -value : value;
    }
    public static BigDecimal Negate(BigDecimal value)
    {
        return new BigDecimal(BigInteger.Negate(value._unscaledValue), value.Scale);
    }
    public static BigDecimal Add(BigDecimal x, BigDecimal y)
    {
        return x + y;
    }
    public static BigDecimal Subtract(BigDecimal x, BigDecimal y)
    {
        return x - y;
    }
    public static BigDecimal Multiply(BigDecimal x, BigDecimal y)
    {
        return x * y;
    }
    public static BigDecimal Divide(BigDecimal dividend, BigDecimal divisor)
    {
        return dividend / divisor;
    }
    public static BigDecimal Pow(BigDecimal baseValue, BigInteger exponent)
    {
        if (exponent.Sign == 0)
            return One;
        if (exponent.Sign < 0)
        {
            if (baseValue == Zero)
                throw new Exception("Cannot raise zero to a negative power.");
            baseValue = One / baseValue;
            exponent  = BigInteger.Negate(exponent);
        }
        var result = baseValue;
        while (exponent > BigInteger.One)
        {
            result *= baseValue;
            exponent--;
        }
        return result;
    }
    public static int Compare(BigDecimal r1, BigDecimal r2)
    {
        return (r1 - r2)._unscaledValue.Sign;
    }
    public static bool operator ==(BigDecimal x, BigDecimal y)
    {
        return x.Equals(y);
    }
    public static bool operator !=(BigDecimal x, BigDecimal y)
    {
        return !x.Equals(y);
    }
    public static bool operator <(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) < 0;
    }
    public static bool operator <=(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) <= 0;
    }
    public static bool operator >(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) > 0;
    }
    public static bool operator >=(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) >= 0;
    }
    public static BigDecimal operator +(BigDecimal value)
    {
        return value;
    }
    public static BigDecimal operator -(BigDecimal value)
    {
        return new BigDecimal(-value._unscaledValue, value.Scale);
    }
    public static BigDecimal operator ++(BigDecimal value)
    {
        return value + One;
    }
    public static BigDecimal operator --(BigDecimal value)
    {
        return value - One;
    }
    public static BigDecimal operator +(BigDecimal left, BigDecimal right)
    {
        BigDecimal ret;
        if (left.Scale >= right.Scale)
        {
            ret = left;
        }
        else
        {
            var value = left._unscaledValue * BigInteger.Pow(10, right.Scale - left.Scale);
            ret = new BigDecimal(value, right.Scale);
        }
        BigDecimal ret1;
        if (right.Scale >= left.Scale)
        {
            ret1 = right;
        }
        else
        {
            var value1 = right._unscaledValue * BigInteger.Pow(10, left.Scale - right.Scale);
            ret1 = new BigDecimal(value1, left.Scale);
        }
        return new BigDecimal(ret._unscaledValue + ret1._unscaledValue, ret.Scale);
    }
    public static BigDecimal operator -(BigDecimal left, BigDecimal right)
    {
        BigDecimal ret;
        if (left.Scale >= right.Scale)
        {
            ret = left;
        }
        else
        {
            var value = left._unscaledValue * BigInteger.Pow(10, right.Scale - left.Scale);
            ret = new BigDecimal(value, right.Scale);
        }
        BigDecimal ret1;
        if (right.Scale >= left.Scale)
        {
            ret1 = right;
        }
        else
        {
            var value1 = right._unscaledValue * BigInteger.Pow(10, left.Scale - right.Scale);
            ret1 = new BigDecimal(value1, left.Scale);
        }
        return new BigDecimal(ret._unscaledValue - ret1._unscaledValue, ret.Scale);
    }
    public static BigDecimal operator *(BigDecimal left, BigDecimal right)
    {
        return new BigDecimal(left._unscaledValue * right._unscaledValue, left.Scale + right.Scale);
    }
    public static BigDecimal operator /(BigDecimal left, BigDecimal right)
    {
        var value = left._unscaledValue;
        var scale = left.Scale;
        while (scale > 0 && value % 10 == 0)
        {
            value /= 10;
            scale--;
        }
        var v1     = new BigDecimal(value, scale);
        var value1 = right._unscaledValue;
        var scale1 = right.Scale;
        while (scale1 > 0 && value1 % 10 == 0)
        {
            value1 /= 10;
            scale1--;
        }
        var v2 = new BigDecimal(value1, scale1);
        while (v1.Scale > 0 || v2.Scale > 0)
        {
            if (v1.Scale > 0)
                v1 = new BigDecimal(v1._unscaledValue, v1.Scale - 1);
            else
                v1 = new BigDecimal(v1._unscaledValue * 10, 0);
            if (v2.Scale > 0)
                v2 = new BigDecimal(v2._unscaledValue, v2.Scale - 1);
            else
                v2 = new BigDecimal(v2._unscaledValue * 10, 0);
        }
        var factor  = 0;
        var v1Value = v1._unscaledValue;
        while (factor < MaxPrecision && v1Value % v2._unscaledValue != 0)
        {
            v1Value *= 10;
            factor++;
        }
        return new BigDecimal(v1Value / v2._unscaledValue, factor);
    }
    public static BigDecimal operator %(BigDecimal left, BigDecimal right)
    {
        var value = left._unscaledValue;
        var scale = left.Scale;
        while (scale > 0 && value % 10 == 0)
        {
            value /= 10;
            scale--;
        }
        var v1     = new BigDecimal(value, scale);
        var value1 = right._unscaledValue;
        var scale1 = right.Scale;
        while (scale1 > 0 && value1 % 10 == 0)
        {
            value1 /= 10;
            scale1--;
        }
        var v2 = new BigDecimal(value1, scale1);
        while (v1.Scale > 0 || v2.Scale > 0)
        {
            if (v1.Scale > 0)
                v1 = new BigDecimal(v1._unscaledValue, v1.Scale - 1);
            else
                v1 = new BigDecimal(v1._unscaledValue * 10, 0);
            if (v2.Scale > 0)
                v2 = new BigDecimal(v2._unscaledValue, v2.Scale - 1);
            else
                v2 = new BigDecimal(v2._unscaledValue * 10, 0);
        }
        return new BigDecimal(v1._unscaledValue % v2._unscaledValue);
    }
    public static explicit operator sbyte(BigDecimal value)
    {
        return (sbyte) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator ushort(BigDecimal value)
    {
        return (ushort) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator uint(BigDecimal value)
    {
        return (uint) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator ulong(BigDecimal value)
    {
        return (ulong) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator byte(BigDecimal value)
    {
        return (byte) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator short(BigDecimal value)
    {
        return (short) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator int(BigDecimal value)
    {
        return (int) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator long(BigDecimal value)
    {
        return (long) BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale - 1));
    }
    public static explicit operator BigInteger(BigDecimal value)
    {
        return BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
    }
    public static explicit operator FixedBigInteger(BigDecimal value)
    {
        return FixedBigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
    }
    public static explicit operator float(BigDecimal value)
    {
        return (float) (double) value;
    }
    public static explicit operator double(BigDecimal value)
    {
        var factor = BigInteger.Pow(10, value.Scale);
        if (SafeCastToDouble(value._unscaledValue) && SafeCastToDouble(factor))
            return (double) value._unscaledValue / (double) factor;
        var dnv = value._unscaledValue * DoublePrecision / factor;
        if (dnv.IsZero)
            return value.Sign < 0 ? BitConverter.Int64BitsToDouble(unchecked((long) 0x8000000000000000)) : 0d;
        double result   = 0;
        var    isDouble = false;
        var    scale    = 308;
        while (scale > 0)
        {
            if (!isDouble)
            {
                if (SafeCastToDouble(dnv))
                {
                    result   = (double) dnv;
                    isDouble = true;
                }
                else
                {
                    dnv /= 10;
                }
            }
            result /= 10;
            scale--;
        }
        if (!isDouble)
            return value.Sign < 0 ? double.NegativeInfinity : double.PositiveInfinity;
        return result;
    }
    public static explicit operator decimal(BigDecimal value)
    {
        var factor = BigInteger.Pow(10, value.Scale);
        if (SafeCastToDecimal(value._unscaledValue) && SafeCastToDecimal(factor))
            return (decimal) value._unscaledValue / (decimal) factor;
        var dnv = value._unscaledValue * DecimalPrecision / factor;
        if (dnv.IsZero)
            return decimal.Zero;
        for (var scale = 28; scale >= 0; scale--)
            if (!SafeCastToDecimal(dnv))
            {
                dnv /= 10;
            }
            else
            {
                var dec = new DecimalUInt32();
                dec.dec   = (decimal) dnv;
                dec.flags = (dec.flags & ~0x00FF0000) | (scale << 16);
                return dec.dec;
            }
        throw new Exception("Value was either too large or too small for a Decimal.");
    }
    public static implicit operator BigDecimal(sbyte value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(ushort value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(uint value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(ulong value)
    {
        return new BigDecimal((BigInteger) value);
    }
    public static implicit operator BigDecimal(byte value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(short value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(int value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(long value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(BigInteger value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(FixedBigInteger value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(float value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(double value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(decimal value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(BigRational value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(BigIntX value)
    {
        return new BigDecimal(value.ToString());
    }
    private static bool SafeCastToDouble(BigInteger value)
    {
        return DoubleMinValue <= value && value <= DoubleMaxValue;
    }
    private static bool SafeCastToDecimal(BigInteger value)
    {
        return DecimalMinValue <= value && value <= DecimalMaxValue;
    }
    private static BigInteger GetLastDigit(BigInteger value)
    {
        return value % new BigInteger(10);
    }
    private static int GetNumberOfDigits(BigInteger value)
    {
        return BigInteger.Abs(value).ToString().Length;
    }
    private static BigDecimal Factorial(BigDecimal x)
    {
        BigDecimal r = 1;
        BigDecimal c = 1;
        while (c <= x)
        {
            r *= c;
            c++;
        }
        return r;
    }
    public static BigDecimal Exp(BigDecimal x)
    {
        BigDecimal r  = 0;
        BigDecimal r1 = 0;
        var        k  = 0;
        while (true)
        {
            r += Pow(x, k) / Factorial(k);
            if (r == r1)
                break;
            r1 = r;
            k++;
        }
        return r;
    }
    public static BigDecimal Sine(BigDecimal ar, int n)
    {
        if (Factorials == null)
        {
            Factorials = new BigDecimal[MaxFactorials];
            for (var i = 0; i < MaxFactorials; i++)
                Factorials[i] = new BigDecimal();
            for (var i = 1; i < MaxFactorials + 1; i++)
                Factorials[i - 1] = Factorial(i);
        }
        var sin = ar;
        for (var i = 1; i <= n; i++)
        {
            var trm = Pow(ar, i * 2 + 1);
            trm /= Factorials[i * 2];
            if ((i & 1) == 1)
                sin -= trm;
            else
                sin += trm;
        }
        return sin;
    }
    public static BigDecimal Atan(BigDecimal ar, int n)
    {
        var atan = ar;
        for (var i = 1; i <= n; i++)
        {
            var trm = Pow(ar, i * 2 + 1);
            trm /= i * 2;
            if ((i & 1) == 1)
                atan -= trm;
            else
                atan += trm;
        }
        return atan;
    }
    public static BigDecimal Cosine(BigDecimal ar, int n)
    {
        if (Factorials == null)
        {
            Factorials = new BigDecimal[MaxFactorials];
            for (var i = 0; i < MaxFactorials; i++)
                Factorials[i] = new BigDecimal();
            for (var i = 1; i < MaxFactorials + 1; i++)
                Factorials[i - 1] = Factorial(i);
        }
        BigDecimal cos = 1.0;
        for (var i = 1; i <= n; i++)
        {
            var trm = Pow(ar, i * 2);
            trm /= Factorials[i * 2 - 1];
            if ((i & 1) == 1)
                cos -= trm;
            else
                cos += trm;
        }
        return cos;
    }
    private static BigDecimal GetE(int n)
    {
        BigDecimal e = 1.0;
        var        c = n;
        while (c > 0)
        {
            BigDecimal f = 0;
            if (c == 1)
            {
                f = 1;
            }
            else
            {
                var i = c - 1;
                f = c;
                while (i > 0)
                {
                    f *= i;
                    i--;
                }
            }
            c--;
            e += 1.0 / f;
        }
        return e;
    }
    public static BigDecimal Tangent(BigDecimal ar, int n)
    {
        return Sine(ar, n) / Cosine(ar, n);
    }
    public static BigDecimal CoTangent(BigDecimal ar, int n)
    {
        return Cosine(ar, n) / Sine(ar, n);
    }
    public static BigDecimal Secant(BigDecimal ar, int n)
    {
        return 1.0 / Cosine(ar, n);
    }
    public static BigDecimal NthRoot(BigDecimal value, int nth)
    {
        BigDecimal lx;
        var        a = value;
        var        n = nth;
        BigDecimal s = 1.0;
        do
        {
            var t = s;
            lx = a / Pow(s, n - 1);
            var r = (n        - 1) * s;
            s = (lx + r) / n;
        } while (lx != s);
        return s;
    }
    public static BigDecimal LogN(BigDecimal value)
    {
        var        E = GetE(MaxFactorials);
        BigDecimal a;
        var        p = value;
        BigDecimal n = 0.0;
        while (p >= E)
        {
            p /= E;
            n++;
        }
        n += p / E;
        p =  value;
        do
        {
            a = n;
            var lx = p         / Exp(n - 1.0);
            var r  = (n - 1.0) * E;
            n = (lx + r) / E;
        } while (n != a);
        return n;
    }
    public static BigDecimal Log(BigDecimal n, int b)
    {
        return LogN(n) / LogN(b);
    }
    public static BigDecimal CoSecant(BigDecimal ar, int n)
    {
        return 1.0 / Sine(ar, n);
    }
    public void Ceiling(int precision)
    {
        RemoveTrailingZeros();
        var diff = GetNumberOfDigits(_unscaledValue) - precision;
        if (diff > 0)
        {
            for (var i = 0; i < diff; i++)
            {
                _unscaledValue = BigInteger.Divide(_unscaledValue, 10);
                Scale--;
            }
            if (_unscaledValue.Sign < 0)
                _unscaledValue--;
            else
                _unscaledValue++;
        }
    }
    public void Floor(int precision)
    {
        RemoveTrailingZeros();
        var diff = GetNumberOfDigits(_unscaledValue) - precision;
        if (diff > 0)
        {
            for (var i = 0; i < diff; i++)
            {
                _unscaledValue = BigInteger.Divide(_unscaledValue, 10);
                Scale--;
            }
            if (_unscaledValue.Sign > 0)
                _unscaledValue--;
            else
                _unscaledValue++;
        }
    }
    private void RemoveTrailingZeros()
    {
        BigInteger remainder;
        do
        {
            var shortened = BigInteger.DivRem(_unscaledValue, 10, out remainder);
            if (remainder == BigInteger.Zero)
            {
                _unscaledValue = shortened;
                Scale--;
            }
        } while (remainder == BigInteger.Zero);
    }
    public BigDecimal Min(BigDecimal value)
    {
        return CompareTo(value) <= 0 ? this : value;
    }
    public BigDecimal Max(BigDecimal value)
    {
        return CompareTo(value) >= 0 ? this : value;
    }
    public static BigDecimal Sqrt(BigDecimal value)
    {
        return BigRational.Sqrt(value);
    }
    [StructLayout(LayoutKind.Explicit)]
    internal struct DecimalUInt32
    {
        [FieldOffset(0)] public decimal dec;
        [FieldOffset(0)] public int     flags;
    }
}

NativeWin32.cs

Contains some native Windows and SetupDi API calls

using System;
using System.Runtime.InteropServices;
using System.Text;

/// <summary>
///     Contains some native Windows and SetupDi API calls
/// </summary>
public class NativeWin32
{
    [Flags]
    public enum DeviceCapabilities
    {
        Unknown           = 0x00000000,
        LockSupported     = 0x00000001,
        EjectSupported    = 0x00000002,
        Removable         = 0x00000004,
        DockDevice        = 0x00000008,
        UniqueId          = 0x00000010,
        SilentInstall     = 0x00000020,
        RawDeviceOk       = 0x00000040,
        SurpriseRemovalOk = 0x00000080,
        HardwareDisabled  = 0x00000100,
        NonDynamic        = 0x00000200
    }

    [Flags]
    public enum DICFG
    {
        /// <summary>
        ///     Return only the device that is associated with the system default device interface, if one is set.
        /// </summary>
        DEFAULT = 0x00000001,

        /// <summary>
        ///     Return only devices that are currently present in a system.
        /// </summary>
        PRESENT = 0x00000002,

        /// <summary>
        ///     Return a list of installed devices for all device setup classes or all device interface classes.
        /// </summary>
        ALLCLASSES = 0x00000004,

        /// <summary>
        ///     Return only devices that are a part of the current hardware profile.
        /// </summary>
        PROFILE = 0x00000008,

        /// <summary>
        ///     Return devices that support device interfaces for the specified device interface classes.
        /// </summary>
        DEVICEINTERFACE = 0x00000010
    }

    public enum PNP_VETO_TYPE
    {
        Ok,
        TypeUnknown,
        LegacyDevice,
        PendingClose,
        WindowsApp,
        WindowsService,
        OutstandingOpen,
        Device,
        Driver,
        IllegalDeviceRequest,
        InsufficientPower,
        NonDisableable,
        LegacyDriver
    }

    /// <summary>
    ///     SEE: https://msdn.microsoft.com/en-us/library/windows/hardware/ff542548(v=vs.85).aspx
    /// </summary>
    [Flags]
    public enum SPDRP
    {
        /// <summary>
        ///     Requests a string describing the device, such as "Microsoft PS/2 Port Mouse", typically defined by the
        ///     manufacturer.
        ///     String
        /// </summary>
        DeviceDesc = 0x00000000,

        /// <summary>
        ///     Requests the hardware IDs provided by the device that identify the device.
        ///     String[]
        /// </summary>
        HardwareId = 0x00000001,

        /// <summary>
        ///     Requests the compatible IDs reported by the device.
        ///     string[]
        /// </summary>
        CompatibleIds = 0x00000002,
        Unused0 = 0x00000003,

        /// <summary>
        ///     Service device property represents the name of the service that is installed for a device instance.
        ///     string
        /// </summary>
        Service = 0x00000004,
        Unused1 = 0x00000005,
        Unused2 = 0x00000006,

        /// <summary>
        ///     Requests the name of the device's setup class, in text format.
        ///     string
        /// </summary>
        Class = 0x00000007,

        /// <summary>
        ///     Requests the GUID for the device's setup class.
        ///     GUID
        /// </summary>
        ClassGuid = 0x00000008,

        /// <summary>
        ///     Requests the name of the driver-specific registry key.
        ///     string
        /// </summary>
        Driver = 0x00000009,

        /// <summary>
        ///     ConfigFlags device property represents the configuration flags that are set for a device instance.
        ///     Int32
        /// </summary>
        ConfigFlags = 0x0000000A,

        /// <summary>
        ///     Requests a string identifying the manufacturer of the device.
        ///     string
        /// </summary>
        Mfg = 0x0000000B,

        /// <summary>
        ///     Requests a string that can be used to distinguish between two similar devices, typically defined by the class
        ///     installer.
        ///     string
        /// </summary>
        FriendlyName = 0x0000000C,

        /// <summary>
        ///     Requests information about the device's location on the bus; the interpretation of this information is
        ///     bus-specific.
        ///     string
        /// </summary>
        LocationInformation = 0x0000000D,

        /// <summary>
        ///     Requests the name of the PDO for this device.
        ///     Binary
        /// </summary>
        PhysicalDeviceObjectName = 0x0000000E,

        /// <summary>
        ///     Capabilities device property represents the capabilities of a device instance.
        ///     Int32
        /// </summary>
        Capabilities = 0x0000000F,

        /// <summary>
        ///     Requests a number associated with the device that can be displayed in the user interface.
        ///     Int32
        /// </summary>
        UiNumber = 0x00000010,

        /// <summary>
        ///     UpperFilters device property represents a list of the service names of the upper-level filter drivers that are
        ///     installed for a device instance.
        ///     string[]
        /// </summary>
        UpperFilters = 0x00000011,

        /// <summary>
        ///     LowerFilters device property represents a list of the service names of the lower-level filter drivers that are
        ///     installed for a device instance.
        ///     string[]
        /// </summary>
        LowerFilters = 0x00000012,

        /// <summary>
        ///     Requests the GUID for the bus that the device is connected to.
        ///     GUID
        /// </summary>
        BusTypeGuid = 0x00000013,

        /// <summary>
        ///     Requests the bus type, such as PCIBus or PCMCIABus.
        ///     Int32
        /// </summary>
        LegacyBusType = 0x00000014,

        /// <summary>
        ///     Requests the legacy bus number of the bus the device is connected to.
        ///     Int32
        /// </summary>
        BusNumber = 0x00000015,

        /// <summary>
        ///     Requests the name of the enumerator for the device, such as "USB".
        ///     string
        /// </summary>
        EnumeratorName = 0x00000016,

        /// <summary>
        ///     Security device property represents a security descriptor structure for a device instance.
        ///     SECURITY_DESCRIPTOR
        /// </summary>
        Security = 0x00000017,

        /// <summary>
        ///     SecuritySDS device property represents a security descriptor string for a device instance.
        /// </summary>
        Security_SDS = 0x00000018,

        /// <summary>
        ///     DevType device property represents the device type of a device instance.
        ///     Int32
        /// </summary>
        DevType = 0x00000019,

        /// <summary>
        ///     Exclusive device property represents a Boolean value that determines whether a device instance can be opened for
        ///     exclusive use.
        ///     bool
        /// </summary>
        Exclusive = 0x0000001A,

        /// <summary>
        ///     Characteristics device property represents the characteristics of a device instance.
        ///     INt32
        /// </summary>
        Characteristics = 0x0000001B,

        /// <summary>
        ///     Requests the address of the device on the bus.
        ///     Int32
        /// </summary>
        Address = 0x0000001C,

        /// <summary>
        ///     UINumberDescFormat device property represents a printf-compatible format string that you should use to display
        ///     the value of the DEVPKEY_DEVICE_UINumber device property for a device instance.
        ///     string
        /// </summary>
        UI_Number_Desc_Format = 0x0000001D,

        /// <summary>
        ///     PowerData device property represents power information about a device instance.
        ///     Binary
        /// </summary>
        Device_Power_Data = 0x0000001E,

        /// <summary>
        ///     (Windows XP and later.) Requests the device's current removal policy. The operating system uses this value as a
        ///     hint to determine how the device is normally removed.
        ///     Int32
        /// </summary>
        RemovalPolicy = 0x0000001F,

        /// <summary>
        ///     RemovalPolicyDefault device property represents the default removal policy for a device instance.
        ///     Int32
        /// </summary>
        Removal_Policy_Defualt = 0x00000020,

        /// <summary>
        ///     RemovalPolicyOverride device property represents the removal policy override for a device instance.
        ///     Int32
        /// </summary>
        Removal_Policy_Override = 0x00000021,

        /// <summary>
        ///     Windows XP and later.) Requests the device's installation state.
        ///     Int32
        /// </summary>
        InstallState = 0x00000022,

        /// <summary>
        ///     LocationPaths device property represents the location of a device instance in the device tree.
        ///     string[]
        /// </summary>
        LocationPaths = 0x00000023
    }

    public const int INVALID_HANDLE_VALUE                = -1;
    public const int MAX_DEV_LEN                         = 200;
    public const int DEVICE_NOTIFY_WINDOW_HANDLE         = 0x00000000;
    public const int DEVICE_NOTIFY_SERVICE_HANDLE        = 0x00000001;
    public const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004;
    public const int DBT_DEVTYP_DEVICEINTERFACE          = 0x00000005;
    public const int DBT_DEVNODES_CHANGED                = 0x0007;
    public const int WM_DEVICECHANGE                     = 0x0219;
    public const int DIF_PROPERTYCHANGE                  = 0x00000012;
    public const int DICS_FLAG_GLOBAL                    = 0x00000001;
    public const int DICS_FLAG_CONFIGSPECIFIC            = 0x00000002;
    public const int DICS_ENABLE                         = 0x00000001;
    public const int DICS_DISABLE                        = 0x00000002;

    public const int ERROR_INVALID_DATA                   = 13;
    public const int ERROR_NO_MORE_ITEMS                  = 259;
    public const int ERROR_INSUFFICIENT_BUFFER            = 122;
    public const int GENERIC_READ                         = unchecked((int) 0x80000000);
    public const int FILE_SHARE_READ                      = 0x00000001;
    public const int FILE_SHARE_WRITE                     = 0x00000002;
    public const int OPEN_EXISTING                        = 3;
    public const int IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = 0x00560000;

    [DllImport("setupapi.dll")]
    public static extern bool SetupDiOpenDeviceInfo(
        IntPtr              deviceInfoSet,
        string              deviceInstanceId,
        IntPtr              hwndParent,
        int                 openFlags,
        ref SP_DEVINFO_DATA deviceInfoData
    );

    [DllImport("Kernel32.dll", SetLastError = true)]
    internal static extern IntPtr CreateFile(string lpFileName,           int dwDesiredAccess,       int dwShareMode,
        IntPtr                                      lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("Kernel32.dll", SetLastError = true)]
    internal static extern bool DeviceIoControl(IntPtr hDevice,       int    dwIoControlCode, IntPtr lpInBuffer,
        int                                            nInBufferSize, IntPtr lpOutBuffer,     int    nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);

    [DllImport("Kernel32.dll", SetLastError = true)]
    internal static extern bool CloseHandle(IntPtr hObject);

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern bool GetVolumeNameForVolumeMountPoint(
        string        volumeName,
        StringBuilder uniqueVolumeName,
        int           uniqueNameBufferCapacity);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient,
        DEV_BROADCAST_DEVICEINTERFACE                             NotificationFilter, uint Flags);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern uint UnregisterDeviceNotification(IntPtr hHandle);

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern IntPtr SetupDiGetClassDevs(ref Guid   ClassGuid,
        [MarshalAs(UnmanagedType.LPStr)]                string Enumerator, IntPtr hwndParent, DICFG Flags);

    [DllImport("setupapi.dll")]
    public static extern IntPtr SetupDiGetClassDevsEx(ref Guid   ClassGuid,
        [MarshalAs(UnmanagedType.LPStr)]                  string Enumerator,
        IntPtr                                                   hwndParent, int Flags, IntPtr DeviceInfoSet,
        [MarshalAs(UnmanagedType.LPStr)] string                  MachineName,
        IntPtr                                                   Reserved);

    [DllImport(@"setupapi.dll", SetLastError = true)]
    public static extern bool SetupDiEnumDeviceInterfaces(
        IntPtr                       hDevInfo,
        IntPtr                       devInfo,
        Guid                         interfaceClassGuid,
        uint                         memberIndex,
        ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData
    );

    [DllImport(@"setupapi.dll", SetLastError = true)]
    public static extern bool SetupDiEnumDeviceInterfaces(
        IntPtr                       hDevInfo,
        ref SP_DEVINFO_DATA          devInfo,
        Guid                         interfaceClassGuid,
        uint                         memberIndex,
        ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData
    );

    [DllImport(@"setupapi.dll", SetLastError = true)]
    public static extern bool SetupDiGetDeviceInterfaceDetail(
        IntPtr                              hDevInfo,
        ref SP_DEVICE_INTERFACE_DATA        deviceInterfaceData,
        ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
        uint                                deviceInterfaceDetailDataSize,
        ref uint                            requiredSize,
        ref SP_DEVINFO_DATA                 deviceInfoData
    );

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern int SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet);

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern bool SetupDiEnumDeviceInfo(IntPtr lpInfoSet, int dwIndex, ref SP_DEVINFO_DATA devInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr lpInfoSet, ref SP_DEVINFO_DATA DeviceInfoData,
        uint                                                          Property,
        uint                                                          PropertyRegDataType, StringBuilder PropertyBuffer, uint PropertyBufferSize, IntPtr RequiredSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr lpInfoSet, ref SP_DEVINFO_DATA DeviceInfoData,
        uint                                                          Property,
        uint                                                          PropertyRegDataType, IntPtr propertyBuffer, uint PropertyBufferSize, IntPtr RequiredSize);

    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool SetupDiSetClassInstallParams(IntPtr DeviceInfoSet,      ref SP_DEVINFO_DATA DeviceInfoData,
        SP_PROPCHANGE_PARAMS                                      ClassInstallParams, int                 ClassInstallParamsSize);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    public static extern bool SetupDiCallClassInstaller(uint InstallFunction, IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA                                  DeviceInfoData);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    public static extern bool SetupDiClassNameFromGuid(ref Guid ClassGuid,     StringBuilder className,
        int                                                     ClassNameSize, ref int       RequiredSize);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    public static extern bool SetupDiGetClassDescription(ref Guid ClassGuid,            StringBuilder classDescription,
        int                                                       ClassDescriptionSize, ref int       RequiredSize);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    public static extern bool SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet,    ref SP_DEVINFO_DATA DeviceInfoData,
        StringBuilder                                           DeviceInstanceId, int                 DeviceInstanceIdSize, ref int RequiredSize);

    [DllImport("setupapi.dll")]
    public static extern int CM_Get_Parent(
        out uint pdnDevInst,
        uint     dnDevInst,
        int      ulFlags
    );

    [DllImport("setupapi.dll")]
    public static extern int CM_Get_Device_ID(
        uint          dnDevInst,
        StringBuilder buffer,
        uint          bufferLen,
        int           ulFlags);

    [DllImport("setupapi.dll")]
    public static extern int CM_Request_Device_Eject(
        uint              dnDevInst,
        out PNP_VETO_TYPE pVetoType,
        StringBuilder     pszVetoName,
        int               ulNameLength,
        uint              ulFlags
    );

    [DllImport("setupapi.dll", EntryPoint = "CM_Request_Device_Eject")]
    public static extern int CM_Request_Device_Eject_NoUi(
        uint          dnDevInst,
        IntPtr        pVetoType,
        StringBuilder pszVetoName,
        uint          ulNameLength,
        uint          ulFlags
    );

    public class GUID_DEVINTERFACE
    {
        public static Guid BUS1394_CLASS_GUID                   = new Guid("6BDD1FC1-810F-11d0-BEC7-08002BE2092F");
        public static Guid GUID_61883_CLASS                     = new Guid("7EBEFBC0-3200-11d2-B4C2-00A0C9697D07");
        public static Guid GUID_DEVICE_APPLICATIONLAUNCH_BUTTON = new Guid("629758EE-986E-4D9E-8E47-DE27F8AB054D");
        public static Guid GUID_DEVICE_BATTERY                  = new Guid("72631E54-78A4-11D0-BCF7-00AA00B7B32A");
        public static Guid GUID_DEVICE_LID                      = new Guid("4AFA3D52-74A7-11d0-be5e-00A0C9062857");
        public static Guid GUID_DEVICE_MEMORY                   = new Guid("3FD0F03D-92E0-45FB-B75C-5ED8FFB01021");
        public static Guid GUID_DEVICE_MESSAGE_INDICATOR        = new Guid("CD48A365-FA94-4CE2-A232-A1B764E5D8B4");
        public static Guid GUID_DEVICE_PROCESSOR                = new Guid("97FADB10-4E33-40AE-359C-8BEF029DBDD0");
        public static Guid GUID_DEVICE_SYS_BUTTON               = new Guid("4AFA3D53-74A7-11d0-be5e-00A0C9062857");
        public static Guid GUID_DEVICE_THERMAL_ZONE             = new Guid("4AFA3D51-74A7-11d0-be5e-00A0C9062857");
        public static Guid GUID_BTHPORT_DEVICE_INTERFACE        = new Guid("0850302A-B344-4fda-9BE9-90576B8D46F0");
        public static Guid GUID_DEVINTERFACE_BRIGHTNESS         = new Guid("FDE5BBA4-B3F9-46FB-BDAA-0728CE3100B4");
        public static Guid GUID_DEVINTERFACE_DISPLAY_ADAPTER    = new Guid("5B45201D-F2F2-4F3B-85BB-30FF1F953599");
        public static Guid GUID_DEVINTERFACE_I2C                = new Guid("2564AA4F-DDDB-4495-B497-6AD4A84163D7");
        public static Guid GUID_DEVINTERFACE_IMAGE              = new Guid("6BDD1FC6-810F-11D0-BEC7-08002BE2092F");
        public static Guid GUID_DEVINTERFACE_MONITOR            = new Guid("E6F07B5F-EE97-4a90-B076-33F57BF4EAA7");
        public static Guid GUID_DEVINTERFACE_OPM                = new Guid("BF4672DE-6B4E-4BE4-A325-68A91EA49C09");

        public static Guid GUID_DEVINTERFACE_VIDEO_OUTPUT_ARRIVAL =
            new Guid("1AD9E4F0-F88D-4360-BAB9-4C2D55E564CD");

        public static Guid GUID_DISPLAY_DEVICE_ARRIVAL = new Guid("1CA05180-A699-450A-9A0C-DE4FBE3DDD89");
        public static Guid GUID_DEVINTERFACE_HID       = new Guid("4D1E55B2-F16F-11CF-88CB-001111000030");
        public static Guid GUID_DEVINTERFACE_KEYBOARD  = new Guid("884b96c3-56ef-11d1-bc8c-00a0c91405dd");
        public static Guid GUID_DEVINTERFACE_MOUSE     = new Guid("378DE44C-56EF-11D1-BC8C-00A0C91405DD");
        public static Guid GUID_DEVINTERFACE_MODEM     = new Guid("2C7089AA-2E0E-11D1-B114-00C04FC2AAE4");
        public static Guid GUID_DEVINTERFACE_NET       = new Guid("CAC88484-7515-4C03-82E6-71A87ABAC361");

        public static Guid GUID_DEVINTERFACE_SENSOR = new Guid(0XBA1BB692, 0X9B7A, 0X4833, 0X9A, 0X1E, 0X52, 0X5E,
            0XD1, 0X34, 0XE7, 0XE2);

        public static Guid GUID_DEVINTERFACE_COMPORT  = new Guid("86E0D1E0-8089-11D0-9CE4-08003E301F73");
        public static Guid GUID_DEVINTERFACE_PARALLEL = new Guid("97F76EF0-F883-11D0-AF1F-0000F800845C");
        public static Guid GUID_DEVINTERFACE_PARCLASS = new Guid("811FC6A5-F728-11D0-A537-0000F8753ED1");

        public static Guid GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR =
            new Guid("4D36E978-E325-11CE-BFC1-08002BE10318");

        public static Guid GUID_DEVINTERFACE_CDCHANGER           = new Guid("53F56312-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_CDROM               = new Guid("53F56308-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_DISK                = new Guid("53F56307-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_FLOPPY              = new Guid("53F56311-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_MEDIUMCHANGER       = new Guid("53F56310-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_PARTITION           = new Guid("53F5630A-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_STORAGEPORT         = new Guid("2ACCFE60-C130-11D2-B082-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_TAPE                = new Guid("53F5630B-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_VOLUME              = new Guid("53F5630D-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_DEVINTERFACE_WRITEONCEDISK       = new Guid("53F5630C-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_IO_VOLUME_DEVICE_INTERFACE       = new Guid("53F5630D-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid MOUNTDEV_MOUNTED_DEVICE_GUID          = new Guid("53F5630D-B6BF-11D0-94F2-00A0C91EFB8B");
        public static Guid GUID_AVC_CLASS                        = new Guid("095780C3-48A1-4570-BD95-46707F78C2DC");
        public static Guid GUID_VIRTUAL_AVC_CLASS                = new Guid("616EF4D0-23CE-446D-A568-C31EB01913D0");
        public static Guid KSCATEGORY_ACOUSTIC_ECHO_CANCEL       = new Guid("BF963D80-C559-11D0-8A2B-00A0C9255AC1");
        public static Guid KSCATEGORY_AUDIO                      = new Guid("6994AD04-93EF-11D0-A3CC-00A0C9223196");
        public static Guid KSCATEGORY_AUDIO_DEVICE               = new Guid("FBF6F530-07B9-11D2-A71E-0000F8004788");
        public static Guid KSCATEGORY_AUDIO_GFX                  = new Guid("9BAF9572-340C-11D3-ABDC-00A0C90AB16F");
        public static Guid KSCATEGORY_AUDIO_SPLITTER             = new Guid("9EA331FA-B91B-45F8-9285-BD2BC77AFCDE");
        public static Guid KSCATEGORY_BDA_IP_SINK                = new Guid("71985F4A-1CA1-11d3-9CC8-00C04F7971E0");
        public static Guid KSCATEGORY_BDA_NETWORK_EPG            = new Guid("71985F49-1CA1-11d3-9CC8-00C04F7971E0");
        public static Guid KSCATEGORY_BDA_NETWORK_PROVIDER       = new Guid("71985F4B-1CA1-11d3-9CC8-00C04F7971E0");
        public static Guid KSCATEGORY_BDA_NETWORK_TUNER          = new Guid("71985F48-1CA1-11d3-9CC8-00C04F7971E0");
        public static Guid KSCATEGORY_BDA_RECEIVER_COMPONENT     = new Guid("FD0A5AF4-B41D-11d2-9C95-00C04F7971E0");
        public static Guid KSCATEGORY_BDA_TRANSPORT_INFORMATION  = new Guid("A2E3074F-6C3D-11d3-B653-00C04F79498E");
        public static Guid KSCATEGORY_BRIDGE                     = new Guid("085AFF00-62CE-11CF-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_CAPTURE                    = new Guid("65E8773D-8F56-11D0-A3B9-00A0C9223196");
        public static Guid KSCATEGORY_CLOCK                      = new Guid("53172480-4791-11D0-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_COMMUNICATIONSTRANSFORM    = new Guid("CF1DDA2C-9743-11D0-A3EE-00A0C9223196");
        public static Guid KSCATEGORY_CROSSBAR                   = new Guid("A799A801-A46D-11D0-A18C-00A02401DCD4");
        public static Guid KSCATEGORY_DATACOMPRESSOR             = new Guid("1E84C900-7E70-11D0-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_DATADECOMPRESSOR           = new Guid("2721AE20-7E70-11D0-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_DATATRANSFORM              = new Guid("2EB07EA0-7E70-11D0-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_DRM_DESCRAMBLE             = new Guid("FFBB6E3F-CCFE-4D84-90D9-421418B03A8E");
        public static Guid KSCATEGORY_ENCODER                    = new Guid("19689BF6-C384-48fd-AD51-90E58C79F70B");
        public static Guid KSCATEGORY_ESCALANTE_PLATFORM_DRIVER  = new Guid("74F3AEA8-9768-11D1-8E07-00A0C95EC22E");
        public static Guid KSCATEGORY_FILESYSTEM                 = new Guid("760FED5E-9357-11D0-A3CC-00A0C9223196");
        public static Guid KSCATEGORY_INTERFACETRANSFORM         = new Guid("CF1DDA2D-9743-11D0-A3EE-00A0C9223196");
        public static Guid KSCATEGORY_MEDIUMTRANSFORM            = new Guid("CF1DDA2E-9743-11D0-A3EE-00A0C9223196");
        public static Guid KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR = new Guid("830A44F2-A32D-476B-BE97-42845673B35A");
        public static Guid KSCATEGORY_MIXER                      = new Guid("AD809C00-7B88-11D0-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_MULTIPLEXER                = new Guid("7A5DE1D3-01A1-452c-B481-4FA2B96271E8");
        public static Guid KSCATEGORY_NETWORK                    = new Guid("67C9CC3C-69C4-11D2-8759-00A0C9223196");
        public static Guid KSCATEGORY_PREFERRED_MIDIOUT_DEVICE   = new Guid("D6C50674-72C1-11D2-9755-0000F8004788");
        public static Guid KSCATEGORY_PREFERRED_WAVEIN_DEVICE    = new Guid("D6C50671-72C1-11D2-9755-0000F8004788");
        public static Guid KSCATEGORY_PREFERRED_WAVEOUT_DEVICE   = new Guid("D6C5066E-72C1-11D2-9755-0000F8004788");
        public static Guid KSCATEGORY_PROXY                      = new Guid("97EBAACA-95BD-11D0-A3EA-00A0C9223196");
        public static Guid KSCATEGORY_QUALITY                    = new Guid("97EBAACB-95BD-11D0-A3EA-00A0C9223196");
        public static Guid KSCATEGORY_REALTIME                   = new Guid("EB115FFC-10C8-4964-831D-6DCB02E6F23F");
        public static Guid KSCATEGORY_RENDER                     = new Guid("65E8773E-8F56-11D0-A3B9-00A0C9223196");
        public static Guid KSCATEGORY_SPLITTER                   = new Guid("0A4252A0-7E70-11D0-A5D6-28DB04C10000");
        public static Guid KSCATEGORY_SYNTHESIZER                = new Guid("DFF220F3-F70F-11D0-B917-00A0C9223196");
        public static Guid KSCATEGORY_SYSAUDIO                   = new Guid("A7C7A5B1-5AF3-11D1-9CED-00A024BF0407");
        public static Guid KSCATEGORY_TEXT                       = new Guid("6994AD06-93EF-11D0-A3CC-00A0C9223196");
        public static Guid KSCATEGORY_TOPOLOGY                   = new Guid("DDA54A40-1E4C-11D1-A050-405705C10000");
        public static Guid KSCATEGORY_TVAUDIO                    = new Guid("A799A802-A46D-11D0-A18C-00A02401DCD4");
        public static Guid KSCATEGORY_TVTUNER                    = new Guid("A799A800-A46D-11D0-A18C-00A02401DCD4");
        public static Guid KSCATEGORY_VBICODEC                   = new Guid("07DAD660-22F1-11D1-A9F4-00C04FBBDE8F");
        public static Guid KSCATEGORY_VIDEO                      = new Guid("6994AD05-93EF-11D0-A3CC-00A0C9223196");
        public static Guid KSCATEGORY_VIRTUAL                    = new Guid("3503EAC4-1F26-11D1-8AB0-00A0C9223196");
        public static Guid KSCATEGORY_VPMUX                      = new Guid("A799A803-A46D-11D0-A18C-00A02401DCD4");
        public static Guid KSCATEGORY_WDMAUD                     = new Guid("3E227E76-690D-11D2-8161-0000F8775BF1");
        public static Guid KSMFT_CATEGORY_AUDIO_DECODER          = new Guid("9ea73fb4-ef7a-4559-8d5d-719d8f0426c7");
        public static Guid KSMFT_CATEGORY_AUDIO_EFFECT           = new Guid("11064c48-3648-4ed0-932e-05ce8ac811b7");
        public static Guid KSMFT_CATEGORY_AUDIO_ENCODER          = new Guid("91c64bd0-f91e-4d8c-9276-db248279d975");
        public static Guid KSMFT_CATEGORY_DEMULTIPLEXER          = new Guid("a8700a7a-939b-44c5-99d7-76226b23b3f1");
        public static Guid KSMFT_CATEGORY_MULTIPLEXER            = new Guid("059c561e-05ae-4b61-b69d-55b61ee54a7b");
        public static Guid KSMFT_CATEGORY_OTHER                  = new Guid("90175d57-b7ea-4901-aeb3-933a8747756f");
        public static Guid KSMFT_CATEGORY_VIDEO_DECODER          = new Guid("d6c02d4b-6833-45b4-971a-05a4b04bab91");
        public static Guid KSMFT_CATEGORY_VIDEO_EFFECT           = new Guid("12e17c21-532c-4a6e-8a1c-40825a736397");
        public static Guid KSMFT_CATEGORY_VIDEO_ENCODER          = new Guid("f79eac7d-e545-4387-bdee-d647d7bde42a");
        public static Guid KSMFT_CATEGORY_VIDEO_PROCESSOR        = new Guid("302ea3fc-aa5f-47f9-9f7a-c2188bb16302");
        public static Guid GUID_DEVINTERFACE_USB_DEVICE          = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED");
        public static Guid GUID_DEVINTERFACE_USB_HOST_CONTROLLER = new Guid("3ABF6F2D-71C4-462A-8A92-1E6861E6AF27");
        public static Guid GUID_DEVINTERFACE_USB_HUB             = new Guid("F18A0E88-C30C-11D0-8815-00A0C906BED8");
        public static Guid GUID_DEVINTERFACE_WPD                 = new Guid("6AC27878-A6FA-4155-BA85-F98F491D4F33");
        public static Guid GUID_DEVINTERFACE_WPD_PRIVATE         = new Guid("BA0C718F-4DED-49B7-BDD3-FABE28661211");
        public static Guid GUID_DEVINTERFACE_SIDESHOW            = new Guid("152E5811-FEB9-4B00-90F4-D32947AE1681");
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISK_EXTENT
    {
        internal uint  DiskNumber;
        internal ulong StartingOffset;
        internal ulong ExtentLength;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class VOLUME_DISK_EXTENTS
    {
        public uint NumberOfDiskExtents;

        public uint ZBUf;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class DEV_BROADCAST_DEVICEINTERFACE
    {
        public int dbcc_devicetype;
        public int dbcc_reserved;
        public int dbcc_size;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SP_DEVINFO_DATA
    {
        public uint    cbSize;
        public Guid    classGuid;
        public uint    devInst;
        public UIntPtr reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class SP_DEVINSTALL_PARAMS
    {
        public int    cbSize;
        public IntPtr ClassInstallReserved;

        [MarshalAs(UnmanagedType.LPTStr)] public string DriverPath;

        public IntPtr FileQueue;
        public int    Flags;
        public int    FlagsEx;
        public IntPtr hwndParent;
        public IntPtr InstallMsgHandler;
        public IntPtr InstallMsgHandlerContext;
        public int    Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class SP_PROPCHANGE_PARAMS
    {
        public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
        public int                    HwProfile;
        public int                    Scope;
        public int                    StateChange;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class SP_CLASSINSTALL_HEADER
    {
        public int cbSize;
        public int InstallFunction;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SP_DEVICE_INTERFACE_DETAIL_DATA
    {
        public uint cbSize;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string devicePath;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SP_DEVICE_INTERFACE_DATA
    {
        public uint    cbSize;
        public uint    flags;
        public Guid    interfaceClassGuid;
        public UIntPtr reserved;
    }
}

SetupDi.cs

Gather Information from the Device Setup or Information Class

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
public class SetupDi
{
    /// <summary>
    ///     Class Names (Incomplete??)
    /// </summary>
    public string[] ClassNames =
    {
        "AudioEndpoint",
        "CDROM",
        "Computer",
        "DiskDrive",
        "Display",
        "DriverInterface",
        "HDC",
        "HIDClass",
        "Keyboard",
        "MEDIA",
        "Monitor",
        "Mouse",
        "Net",
        "PrintQueue",
        "Processor",
        "SCSIAdapter",
        "Sensor",
        "SoftwareDevice",
        "System",
        "USB",
        "Volume",
        "VolumeSnapshot",
        "WPD"
    };
    /// <summary>
    ///     Are we running using 64 or 32 bits
    /// </summary>
    public bool Is64Bit => IntPtr.Size == 8;
    /// <summary>
    ///     32 and 64 bit operations require differing offsets within the pointer return values
    /// </summary>
    public uint OffsetSize => Is64Bit ? 8u : 6u;
    /// <summary>
    ///     Get a list of active drives on the PC.
    /// </summary>
    public IEnumerable<string> GetDriveReadyList => from driveInfo in DriveInfo.GetDrives() where driveInfo.IsReady select driveInfo.Name;
    /// <summary>
    ///     Get a list of drive: letters and associated MountPoints for active drives.
    /// </summary>
    public Dictionary<string, string> LogicalDrives
    {
        get
        {
            var _logicalDrives = new Dictionary<string, string>();
            foreach (var drive in GetDriveReadyList)
            {
                var sb = new StringBuilder(1024);
                if (NativeWin32.GetVolumeNameForVolumeMountPoint(drive, sb, sb.Capacity))
                    _logicalDrives.Add(drive.Replace("\\", ""), sb.ToString());
            }
            return _logicalDrives;
        }
    }
    /// <summary>
    ///     Get a list of Drive: -> Disk numbers and associated length and offset information
    /// </summary>
    public Dictionary<string, List<NativeWin32.DISK_EXTENT>> DiskNumbers
    {
        get
        {
            var _diskNumbers = new Dictionary<string, List<NativeWin32.DISK_EXTENT>>();
            foreach (var ld in LogicalDrives)
            {
                var dkexts = new List<NativeWin32.DISK_EXTENT>();
                var hFile  = NativeWin32.CreateFile(@"\\.\" + ld.Key, NativeWin32.GENERIC_READ, NativeWin32.FILE_SHARE_READ | NativeWin32.FILE_SHARE_WRITE, IntPtr.Zero, NativeWin32.OPEN_EXISTING, 0, IntPtr.Zero);
                if (hFile == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE)
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                var size          = 1024;
                var buffer        = Marshal.AllocHGlobal(size);
                var alloced       = buffer;
                var bytesReturned = 0;
                try
                {
                    if (!NativeWin32.DeviceIoControl(hFile, NativeWin32.IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, IntPtr.Zero, 0, buffer, size, out bytesReturned, IntPtr.Zero))
                    {
                    }
                }
                catch (Exception e)
                {
                    var m = e.Message;
                }
                finally
                {
                    NativeWin32.CloseHandle(hFile);
                }
                if (bytesReturned > 0)
                {
                    var vde     = new NativeWin32.VOLUME_DISK_EXTENTS();
                    var dextent = new NativeWin32.DISK_EXTENT();
                    Marshal.PtrToStructure(buffer, vde);
                    buffer = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(vde));
                    for (var i = 0; i < vde.NumberOfDiskExtents; i++)
                    {
                        dextent = (NativeWin32.DISK_EXTENT) Marshal.PtrToStructure(buffer, typeof(NativeWin32.DISK_EXTENT));
                        dkexts.Add(dextent);
                        buffer = new IntPtr(buffer.ToInt64() + Marshal.SizeOf(dextent));
                    }
                }
                Marshal.FreeHGlobal(alloced);
                _diskNumbers.Add(ld.Key, dkexts);
            }
            return _diskNumbers;
        }
    }
    /// <summary>
    ///     Associates a drive letter to its physical disk numbers using SetupDi API functions.
    /// </summary>
    /// <returns></returns>
    public Dictionary<string, VOLUME_INFO> GetVolumePaths()
    {
        var _volumepaths = new Dictionary<string, VOLUME_INFO>();
        var classGuid    = NativeWin32.GUID_DEVINTERFACE.GUID_DEVINTERFACE_VOLUME;
        var hDevInfo     = NativeWin32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, NativeWin32.DICFG.DEVICEINTERFACE | NativeWin32.DICFG.PRESENT);
        if (hDevInfo == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE)
            throw new Exception("read hardware information error");
        var devIndex = 0u;
        do
        {
            var dia = new NativeWin32.SP_DEVICE_INTERFACE_DATA();
            dia.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVICE_INTERFACE_DATA));
            if (NativeWin32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, classGuid, devIndex, ref dia))
            {
                var didd = new NativeWin32.SP_DEVICE_INTERFACE_DETAIL_DATA();
                didd.cbSize = OffsetSize;
                var devInfoData = new NativeWin32.SP_DEVINFO_DATA();
                devInfoData.cbSize = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVINFO_DATA));
                uint nRequiredSize = 0;
                uint nBytes        = 1024;
                if (NativeWin32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref dia, ref didd, nBytes, ref nRequiredSize, ref devInfoData))
                {
                    var sb = new StringBuilder(1024);
                    if (NativeWin32.GetVolumeNameForVolumeMountPoint(didd.devicePath + @"\", sb, sb.Capacity))
                    {
                        var cv = sb.ToString();
                        var di = new VOLUME_INFO();
                        foreach (var V in LogicalDrives)
                            if (V.Value.IndexOf(cv, StringComparison.OrdinalIgnoreCase) != -1)
                            {
                                di.Drive            = V.Key;
                                di.VolumeMountPoint = cv;
                                di.DevicePath       = didd.devicePath;
                                foreach (var de in DiskNumbers[V.Key])
                                {
                                    di.DiskNumbers.Add(de.DiskNumber);
                                    di.ExtentLengths.Add(de.ExtentLength);
                                    di.StartingOffsets.Add(de.StartingOffset);
                                }
                                _volumepaths.Add(di.Drive.Trim(), di);
                                break;
                            }
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            else
            {
                break;
            }
            devIndex++;
        } while (true);
        NativeWin32.SetupDiDestroyDeviceInfoList(hDevInfo);
        return _volumepaths;
    }
    /// <summary>
    ///     Retrieves a list of All devices installed starting at the base root
    /// </summary>
    public Dictionary<string, DEVICE_INFO> GetAllGUIDs()
    {
        var DevList   = new Dictionary<string, DEVICE_INFO>();
        var classGuid = Guid.Empty;
        var hDevInfo  = NativeWin32.SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, NativeWin32.DICFG.ALLCLASSES | NativeWin32.DICFG.PRESENT);
        if (hDevInfo == (IntPtr) NativeWin32.INVALID_HANDLE_VALUE)
            throw new Exception("read hardware information error");
        var devIndex = 0;
        do
        {
            var devInfoData = new NativeWin32.SP_DEVINFO_DATA();
            devInfoData.cbSize    = (uint) Marshal.SizeOf(typeof(NativeWin32.SP_DEVINFO_DATA));
            devInfoData.classGuid = Guid.Empty;
            devInfoData.devInst   = 0;
            devInfoData.reserved  = UIntPtr.Zero;
            if (!NativeWin32.SetupDiEnumDeviceInfo(hDevInfo, devIndex, ref devInfoData))
                break;
            var di = new DEVICE_INFO();
            di.Guid            = $"{devInfoData.classGuid}";
            di.ClassName       = $"{GetClassNameFromGuid(devInfoData.classGuid)}";
            di.Description     = $"{GetClassDescriptionFromGuid(devInfoData.classGuid)}";
            di.InstanceID      = $"{GetDeviceInstanceId(hDevInfo, devInfoData)}";
            di.DI_Capabilities = (NativeWin32.DeviceCapabilities) GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.Capabilities, 0);
            di.FriendlyName    = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.FriendlyName,   null);
            di.ClassGuid       = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.ClassGuid,      null);
            di.HardwareId      = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.HardwareId,     null);
            di.Mfg             = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.Mfg,            null);
            di.EnumeratorName  = GetProperty(hDevInfo, devInfoData, (uint) NativeWin32.SPDRP.EnumeratorName, null);
            if (!DevList.ContainsValue(di))
                DevList.Add($"{devIndex}", di);
            devIndex++;
        } while (true);
        NativeWin32.SetupDiDestroyDeviceInfoList(hDevInfo);
        return DevList;
    }
    /// <summary>
    ///     Get a list of all devices starting a a specified Guid base.
    /// </summary>
    public IEnumerable<DEVICE_INFO> GetGUIDGroup(string ClassName)
    {
        if (ClassNames.All(c => c.IndexOf(ClassName, StringComparison.OrdinalIgnoreCase) == -1))
            throw new Exception("ClassName is Invalid.");
        var dl = GetAllGUIDs();
        return dl.Values.Where(d => d.ClassName.IndexOf(ClassName, StringComparison.OrdinalIgnoreCase) != -1);
    }
    /// <summary>
    ///     property is SPDRP type
    /// </summary>
    private static uint GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devInfoData, uint property, uint defaultValue)
    {
        var propertyRegDataType = 0u;
        var requiredSize        = IntPtr.Zero;
        var propertyBufferSize  = (uint) Marshal.SizeOf(typeof(uint));
        var propertyBuffer      = Marshal.AllocHGlobal((int) propertyBufferSize);
        if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize))
        {
            var error = Marshal.GetLastWin32Error();
            if (error != NativeWin32.ERROR_INVALID_DATA)
                throw new Win32Exception(error);
            return defaultValue;
        }
        var value = (uint) Marshal.PtrToStructure(propertyBuffer, typeof(uint));
        Marshal.FreeHGlobal(propertyBuffer);
        return value;
    }
    /// <summary>
    ///     property is SPDRP type
    /// </summary>
    private Guid GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devData, uint property, Guid defaultValue)
    {
        var propertyRegDataType = 0u;
        var requiredSize        = IntPtr.Zero;
        var propertyBufferSize  = (uint) Marshal.SizeOf(typeof(Guid));
        var propertyBuffer      = Marshal.AllocHGlobal((int) propertyBufferSize);
        if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize))
        {
            Marshal.FreeHGlobal(propertyBuffer);
            var error = Marshal.GetLastWin32Error();
            if (error != NativeWin32.ERROR_INVALID_DATA)
                throw new Win32Exception(error);
            return defaultValue;
        }
        var value = (Guid) Marshal.PtrToStructure(propertyBuffer, typeof(Guid));
        Marshal.FreeHGlobal(propertyBuffer);
        return value;
    }
    /// <summary>
    ///     property is SPDRP type
    /// </summary>
    private string GetProperty(IntPtr deviceInfoSet, NativeWin32.SP_DEVINFO_DATA devInfoData, uint property, string defaultValue)
    {
        var propertyRegDataType = 0u;
        var requiredSize        = IntPtr.Zero;
        var propertyBufferSize  = 1024u;
        var propertyBuffer      = new StringBuilder((int) propertyBufferSize);
        if (!NativeWin32.SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref devInfoData, property, propertyRegDataType, propertyBuffer, propertyBufferSize, requiredSize))
        {
            var error = Marshal.GetLastWin32Error();
            if (error != NativeWin32.ERROR_INVALID_DATA)
                throw new Win32Exception(error);
            return defaultValue;
        }
        return propertyBuffer.ToString();
    }
    public string GetClassNameFromGuid(Guid guid)
    {
        var result        = string.Empty;
        var className     = new StringBuilder();
        var iRequiredSize = 0;
        var iSize         = 0;
        var b             = NativeWin32.SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize);
        className = new StringBuilder(iRequiredSize);
        iSize     = iRequiredSize;
        b         = NativeWin32.SetupDiClassNameFromGuid(ref guid, className, iSize, ref iRequiredSize);
        if (b)
            result = className.ToString();
        return result;
    }
    public string GetClassDescriptionFromGuid(Guid guid)
    {
        var result        = string.Empty;
        var classDesc     = new StringBuilder(0);
        var iRequiredSize = 0;
        var iSize         = 0;
        var b             = NativeWin32.SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize);
        classDesc = new StringBuilder(iRequiredSize);
        iSize     = iRequiredSize;
        b         = NativeWin32.SetupDiGetClassDescription(ref guid, classDesc, iSize, ref iRequiredSize);
        if (b)
            result = classDesc.ToString();
        return result;
    }
    public string GetDeviceInstanceId(IntPtr DeviceInfoSet, NativeWin32.SP_DEVINFO_DATA DeviceInfoData)
    {
        var result        = string.Empty;
        var id            = new StringBuilder(0);
        var iRequiredSize = 0;
        var iSize         = 0;
        var b             = NativeWin32.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, id, iSize, ref iRequiredSize);
        id    = new StringBuilder(iRequiredSize);
        iSize = iRequiredSize;
        b     = NativeWin32.SetupDiGetDeviceInstanceId(DeviceInfoSet, ref DeviceInfoData, id, iSize, ref iRequiredSize);
        if (b)
            result = id.ToString();
        return result;
    }
    public class VOLUME_INFO
    {
        public string      DevicePath;
        public List<uint>  DiskNumbers = new List<uint>();
        public string      Drive;
        public List<ulong> ExtentLengths   = new List<ulong>();
        public List<ulong> StartingOffsets = new List<ulong>();
        public string      VolumeMountPoint;
    }
    public struct DEVICE_INFO
    {
        public string                         Guid;
        public string                         ClassName;
        public string                         Description;
        public string                         InstanceID;
        public NativeWin32.DeviceCapabilities DI_Capabilities;
        public string                         FriendlyName;
        public string                         ClassGuid;
        public string                         HardwareId;
        public string                         Mfg;
        public string                         EnumeratorName;
        public string                         Drive;
        public string                         VolumePath;
    }
}

Ellipse.cs

Ellipse Control

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class Ellipse : Control
{
    private readonly Color[] _surroundcolors        = {Color.FromArgb(0, 135, 206, 250)};
    private          Color   _centerreflectioncolor = Color.FromArgb(180, 135, 206, 250);
    private          Color   _color                 = Color.DodgerBlue;
    private          Color   _lightColor, _darkColor, _darkDarkColor;
    private          bool    _on           = true;
    private          bool    _reflectionon = true;
    public Ellipse()
    {
        SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true);
        Name           = "Ellipse";
        Size           = new Size(10, 10);
        _lightColor    = ControlPaint.Light(Color.DodgerBlue, .4f);
        _darkColor     = ControlPaint.Dark(_lightColor, .2f);
        _darkDarkColor = ControlPaint.DarkDark(_lightColor);
    }
    [DefaultValue(typeof(Color), "30, 144, 255")]
    public Color Color
    {
        get => _color;
        set
        {
            _color         = value;
            _lightColor    = ControlPaint.Light(value, .4f);
            _darkColor     = ControlPaint.Dark(_lightColor, .2f);
            _darkDarkColor = ControlPaint.DarkDark(_lightColor);
            Invalidate();
        }
    }
    [DefaultValue(typeof(Color), "180, 135, 206, 250")]
    public Color ReflectionColor
    {
        get => _centerreflectioncolor;
        set
        {
            _centerreflectioncolor = value;
            Invalidate();
        }
    }
    [DefaultValue(typeof(bool), "true")]
    public bool On
    {
        get => _on;
        set
        {
            _on = value;
            Invalidate();
        }
    }
    [DefaultValue(typeof(bool), "true")]
    public bool ReflectionOn
    {
        get => _reflectionon;
        set
        {
            _reflectionon = value;
            Invalidate();
        }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        var offScreenBmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
        using (var g = Graphics.FromImage(offScreenBmp))
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            DrawControl(g, On);
            e.Graphics.DrawImageUnscaled(offScreenBmp, 0, 0);
        }
    }
    private void DrawControl(Graphics g, bool on)
    {
        var lightColor = on ? _color : Color.FromArgb(180, _darkColor);
        var darkColor  = on ? _darkColor : _darkDarkColor;
        var width      = Width  - (Padding.Left + Padding.Right);
        var height     = Height - (Padding.Top  + Padding.Bottom);
        var diameter   = Math.Min(width, height);
        diameter = Math.Max(diameter - 1, 1);
        var rectangle = new Rectangle(Padding.Left, Padding.Top, diameter, diameter);
        g.FillEllipse(new SolidBrush(darkColor), rectangle);
        var path = new GraphicsPath();
        path.AddEllipse(rectangle);
        var pathBrush = new PathGradientBrush(path)
        {
            CenterColor    = lightColor,
            SurroundColors = new[] {Color.FromArgb(0, lightColor)}
        };
        g.FillEllipse(pathBrush, rectangle);
        if (_reflectionon)
        {
            var offset    = Convert.ToInt32(diameter        * .15F);
            var diameter1 = Convert.ToInt32(rectangle.Width * .8F);
            var whiteRect = new Rectangle(rectangle.X - offset, rectangle.Y - offset, diameter1, diameter1);
            var path1     = new GraphicsPath();
            path1.AddEllipse(whiteRect);
            var pathBrush1 = new PathGradientBrush(path)
            {
                CenterColor    = _centerreflectioncolor,
                SurroundColors = _surroundcolors
            };
            g.FillEllipse(pathBrush1, whiteRect);
        }
        g.SetClip(ClientRectangle);
        if (On) g.DrawEllipse(new Pen(Color.FromArgb(85, Color.Black), 1F), rectangle);
    }
}

CustomToolTip.cs

Customer ToolTip Class

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
/// <summary>
///     A custom tooltip class which adds some things I would like to see. I originally wrote this to have access to the
///     tooltip text.
/// </summary>
public class CustomToolTip : ToolTip
{
    private readonly float[]    _GradientPositions;
    private readonly ColorBlend gradientBlender;
    private          Color      _gradientEndColor    = Color.DeepSkyBlue;
    private          Color      _gradientMiddleColor = Color.LightSkyBlue;
    private          Color      _gradientStartColor  = Color.LightSkyBlue;
    public CustomToolTip()
    {
        Font                      =  new Font("Arial Narrow", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0);
        _GradientPositions        =  new float[3];
        _GradientPositions[0]     =  0f;
        _GradientPositions[1]     =  .3f;
        _GradientPositions[2]     =  1f;
        gradientBlender           =  new ColorBlend(3) {Positions = _GradientPositions};
        gradientBlender.Colors[0] =  _gradientStartColor;
        gradientBlender.Colors[1] =  _gradientMiddleColor;
        gradientBlender.Colors[2] =  _gradientEndColor;
        OwnerDraw                 =  true;
        Popup                     += OnPopup;
        Draw                      += OnDraw;
    }
    /// <summary>
    ///     The font used in the drawing of the text.
    /// </summary>
    [Description("The font used in the drawing of the text.")]
    public Font Font
    {
        get;
        set;
    }
    /// <summary>
    ///     The background image used in the control.
    /// </summary>
    [Description("The background image used in the control.")]
    public Image BackgroundImage
    {
        get;
        set;
    }
    /// <summary>
    ///     Sets the color of the border
    /// </summary>
    [Description("Sets the color of the border")]
    public Color BorderColor
    {
        get;
        set;
    } = Color.DodgerBlue;
    /// <summary>
    ///     Enables or disables the drawing of the border
    /// </summary>
    [Description("Enables or disables the drawing of the border")]
    public bool EnableBorder
    {
        get;
        set;
    } = true;
    /// <summary>
    ///     Enables or disables the drawing of the Gradient Background
    /// </summary>
    [Description("Enables or disables the drawing of the Gradient Background")]
    public bool EnableGradientBackground
    {
        get;
        set;
    } = false;
    public string Text
    {
        get;
        set;
    } = "";
    /// <summary>
    ///     Sets the direction of the gradient
    /// </summary>
    [Description("Sets the direction of the gradient")]
    public LinearGradientMode GradientMode
    {
        get;
        set;
    } = LinearGradientMode.Vertical;
    /// <summary>
    ///     Sets the color of the start of the gradient
    /// </summary>
    [Description("Sets the color of the start of the gradient")]
    public Color GradientStartColor
    {
        get => _gradientStartColor;
        set
        {
            _gradientStartColor       = value;
            gradientBlender.Colors[0] = _gradientStartColor;
        }
    }
    /// <summary>
    ///     Sets the color of the middle of the gradient
    /// </summary>
    [Description("Sets the color of the middle of the gradient")]
    public Color GradientMiddleColor
    {
        get => _gradientMiddleColor;
        set
        {
            _gradientMiddleColor      = value;
            gradientBlender.Colors[1] = _gradientMiddleColor;
        }
    }
    /// <summary>
    ///     Sets the color of the end of the gradient
    /// </summary>
    [Description("Sets the color of the end of the gradient")]
    public Color GradientEndColor
    {
        get => _gradientEndColor;
        set
        {
            _gradientEndColor         = value;
            gradientBlender.Colors[2] = _gradientEndColor;
        }
    }
    /// <summary>
    ///     Set or Get the lower,center,upper bounds for the gradient brush
    /// </summary>
    [Category("Behavior")]
    [Description("Set or Get the lower,center,upper bounds for the gradient brush")]
    public float[] GradientPositions
    {
        get => _GradientPositions;
        set
        {
            _GradientPositions[0]     = value[0];
            _GradientPositions[1]     = value[1];
            _GradientPositions[2]     = value[2];
            gradientBlender.Positions = _GradientPositions;
        }
    }
    private void OnPopup(object sender, PopupEventArgs e)
    {
        var tt     = GetToolTip(e.AssociatedControl);
        var newstr = tt.Replace(@"\n", Environment.NewLine);
        e.ToolTipSize = newstr.MeasureText(Font, 1, 1);
    }
    private void OnDraw(object sender, DrawToolTipEventArgs e)
    {
        var fs = Font.GetFontSize();
        var g  = e.Graphics;
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.InterpolationMode  = InterpolationMode.High;
        Text                 = e.ToolTipText;
        var newstr = e.ToolTipText.Replace(@"\n", Environment.NewLine);
        if (BackgroundImage == null)
            if (EnableGradientBackground)
            {
                var b = new LinearGradientBrush(e.Bounds, Color.Black, Color.Black, GradientMode) {InterpolationColors = gradientBlender};
                g.FillRectangle(b, e.Bounds);
            }
            else
            {
                g.FillRectangle(new SolidBrush(BackColor), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
            }
        else
            g.DrawImage(new Bitmap(BackgroundImage, e.Bounds.Width, e.Bounds.Height), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
        g.DrawString(newstr, Font, new SolidBrush(ForeColor), new PointF(e.Bounds.X + fs.Width / 2, e.Bounds.Y + fs.Height / 2));
        if (EnableBorder)
            g.DrawRectangle(new Pen(new SolidBrush(BorderColor), 1), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1));
    }
}

Random64csp.cs

64 Bit Random Number Generator Using RNGCryptoServiceProvider

using System;
using System.Security.Cryptography;
[Serializable]
public class Random64csp : RandomNumberGenerator
{
    private byte[] _buffer;
    private RNGCryptoServiceProvider _crng;
    private double _dBi;
    private ulong UpperLimit = ulong.MaxValue;
    public Random64csp()
    {
        SetDataUse = 8;
        _crng = new RNGCryptoServiceProvider();
    }
    
    public Random64csp(int dataSize)
    {
        SetDataUse = dataSize;
        _crng      = new RNGCryptoServiceProvider();
    }
    
    public int SetDataUse
    {
        get => _buffer.Length;
        set
        {
            var v = value;
            if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7)
                throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8");
            switch (v)
            {
                case 1:
                    _dBi = 1.0D / byte.MaxValue;
                    UpperLimit = byte.MaxValue;
                    _buffer = new byte[1];
                    break;
                case 2:
                    _dBi = 1.0D / ushort.MaxValue;
                    UpperLimit = ushort.MaxValue;
                    _buffer = new byte[2];
                    break;
                case 4:
                    _dBi = 1.0D / uint.MaxValue;
                    UpperLimit = uint.MaxValue;
                    _buffer = new byte[4];
                    break;
                case 8:
                    _dBi = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer = new byte[8];
                    break;
                default:
                    _dBi = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer = new byte[8];
                    break;
            }
        }
    }
    /// <summary>
    ///     Will generate only odd values
    /// </summary>
    public bool OddsOnly
    {
        get;
        set;
    }
    private double Sample()
    {
        ulong Internal()
        {
            _crng.GetBytes(_buffer);
            return BufferToLong(_buffer);
        }
        return Internal() * _dBi;
    }
    public ulong Next(ulong minValue, ulong maxValue)
    {
        var sa = Sample();
        var fi = (double)(maxValue - minValue + minValue);
        var n = (ulong)(sa * fi);
        n = !OddsOnly ? n : n | 1;
        if (n < minValue)
            return Next(minValue, maxValue);
        return n;
    }
    public ulong Next(ulong maxValue)
    {
        return Next(0, maxValue);
    }
    public ulong Next()
    {
        return Next(0, UpperLimit);
    }
    public unsafe double NextDouble()
    {
        var buf = new byte[8];
        GetBytes(buf);
        fixed (byte* ptr = buf)
        {
            return *(ulong*)ptr * _dBi * ulong.MaxValue;
        }
    }
    public char[] GetNextCharArray(int size)
    {
        var xbc = new byte[1];
        var ca = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            var c = xbc[0];
            if (c >= 32 && c <= 127)
                ca[ptr++] = (char)c;
        } while (ptr < size);
        return ca;
    }
    public char[] GetNextCharArrayX(int size)
    {
        var xbc = new byte[2];
        var ca = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            ca[ptr++] = Convert.ToChar(xbc.ToShort());
        } while (ptr < size);
        return ca;
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _crng.GetBytes(ba);
        return ba;
    }
    /// <summary>
    ///     Next(0,2)==0?false:true; has a distribution error of 1% weighted toward zero.
    ///     The distribution error here is 0.000000046% which is statistically insignificant in this context.
    /// </summary>
    /// <param name="size"></param>
    /// <returns></returns>
    public bool[] GetNextBoolArrayLimit(int size)
    {
        var ba = new bool[size];
        const uint ll = uint.MaxValue >> 1;
        for (var i = 0; i < size; ++i)
            ba[i] = Next(0, uint.MaxValue) > ll;
        return ba;
    }
    public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new byte[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (byte)Next(minValue, maxValue);
        return ba;
    }
    public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ushort[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (ushort)Next(minValue, maxValue);
        return ba;
    }
    public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new uint[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (uint)Next(minValue, maxValue);
        return ba;
    }
    public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ulong[size];
        for (var i = 0; i < size; ++i)
            ba[i] = Next(minValue, maxValue);
        return ba;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int)Next((ulong)minLen, (ulong)maxLen)));
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public void NextBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        for (var index = 0; index < buffer.Length; ++index)
            buffer[index] = (byte)(Sample() * byte.MaxValue + 1);
    }
    public override void GetNonZeroBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        var index = 0;
        do
        {
            var v = (byte)(Sample() * byte.MaxValue + 1);
            if (v > 0)
            {
                buffer[index] = v;
                index++;
            }
        } while (index < buffer.Length);
    }
    private unsafe ulong BufferToLong(byte[] buffer)
    {
        var len = buffer.Length;
        if (len < 1 || len > 8)
            throw new ArgumentException($"The array length {len} must be between 1 and 8");
        fixed (byte* Ptr = &buffer[0])
        {
            switch (len)
            {
                case 1:
                    return *Ptr;
                case 2:
                    return (uint)(*Ptr | (Ptr[1] << 8));
                case 3:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16));
                case 4:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24));
                case 5:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)Ptr[4] << 32);
                case 6:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8)) << 32);
                case 7:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32);
                case 8:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32);
                default:
                    return 0;
            }
        }
    }
}

DynamicFSList.cs

Fast Search Concurrent Non-Concurrent List

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public class DynamicFSList<T> : MonitorActionFunc, IEnumerable<T>
{
    private static IEqualityComparer<T> Comparer;
    private         VerticalList[]       _verticalLists;
    public          int                  Count;

    /// <summary>
    /// The initial size should be at least 1/8 of the expected total number of objects.
    /// For faster searching make initial size equal to the expected total number of objects.
    /// </summary>
    /// <param name="size"></param>
    public DynamicFSList(int size) : this(size, EqualityComparer<T>.Default)
    {
    }
    public DynamicFSList(int size, IEqualityComparer<T> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<T>.Default;
        Comparer       = comparer;
        _verticalLists = new VerticalList[size];
        Count          = 0;
    }
    public (int mDepth, int index) MaximumListLength => GetMaximumListLength();
    public int                     TrueItemCount     => GetItemCount();
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public IEnumerator<T> GetEnumerator()
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            return GetEnum();
        });
    }
    public void Clear()
    {
        _verticalLists.Clear();
    }
    public void Add(T item)
    {
        var tmpThis = this;
        tmpThis.Lock(tmpThis, () =>
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var pos      = hashCode % _verticalLists.Length;
            if (_verticalLists[pos] == null)
                _verticalLists[pos] = new VerticalList();
            _verticalLists[pos].Add(item);
            Count++;
            if (Count > _verticalLists.Length << 3)
                EnsureSize();
        });
    }
    public int AddWithLocation(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            var pos      = hashCode % _verticalLists.Length;
            if (_verticalLists[pos] == null)
                _verticalLists[pos] = new VerticalList();
            _verticalLists[pos].Add(item);
            Count++;
            if (Count > _verticalLists.Length << 3)
                EnsureSize();
            return FindEntry(item, hashCode);
        });
    }
    public T[] ToArray()
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            var newArray = new T[Count];
            var ptr      = 0;
            for (var i = 0; i < _verticalLists.Length; i++)
                if (_verticalLists[i] != null)
                    for (var j = 0; j < _verticalLists[i].Count; ++j)
                    {
                        newArray[ptr] = _verticalLists[i].Values[j];
                        ptr++;
                    }
            return newArray;
        });
    }
    private (int mDepth, int index) GetMaximumListLength()
    {
        var max = 0;
        var j   = 0;
        for (var i = 0; i < _verticalLists.Length; i++)
            if (_verticalLists[i] != null)
            {
                var count = _verticalLists[i].Count;
                if (count > max)
                {
                    max = count;
                    j   = i;
                }
            }
        return (max, j);
    }
    private int GetItemCount()
    {
        var count = 0;
        for (var i = 0; i < _verticalLists.Length; i++)
            if (_verticalLists[i] != null)
            {
                var c = _verticalLists[i].Count;
                count += c;
            }
        return count;
    }
    public int FindEntry(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            return FindEntry(item, hashCode);
        });
    }
    private int FindEntry(T item, int hashCode)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            if (Count == 0)
                return -1;
            var pos = hashCode % _verticalLists.Length;
            if (_verticalLists[pos] == null)
                _verticalLists[pos] = new VerticalList();
            foreach (var i in _verticalLists[pos].Values)
                if (Comparer.Equals(i, item))
                    return pos;
            return -1;
        });
    }
    private void EnsureSize()
    {
        var cArray  = ToArray();
        var newSize = Count >> (1 + Count);
        _verticalLists = new VerticalList[newSize];
        foreach (var i in cArray)
        {
            var hashCode = Comparer.GetHashCode(i) & int.MaxValue;
            var pos      = hashCode % _verticalLists.Length;
            if (_verticalLists[pos] == null)
                _verticalLists[pos] = new VerticalList();
            _verticalLists[pos].Add(i);
        }
    }
    public bool Contains(T item)
    {
        var tmpThis = this;
        return tmpThis.Lock(tmpThis, () =>
        {
            var hashCode = Comparer.GetHashCode(item) & int.MaxValue;
            return FindEntry(item, hashCode) != -1;
        });
    }
    private IEnumerator<T> GetEnum()
    {
        for (var i = 0; i < _verticalLists.Length; i++)
            if (_verticalLists[i] != null)
                for (var j = 0; j < _verticalLists[i].Count; ++j)
                    yield return _verticalLists[i].Values[j];
    }
    private class VerticalList
    {
        public int Count;
        public T[] Values;
        public VerticalList()
        {
            Values = new T[3];
            Count  = 0;
        }
        public void Add(T item)
        {
            if (Contains(item))
                return;
            if (Count >= Values.Length)
                Array.Resize(ref Values, Values.Length + 3);
            Values[Count] = item;
            Count++;
        }
        private bool Contains(T item)
        {
            foreach (var i in Values)
                if (Comparer.Equals(i, item))
                    return true;
            return false;
        }
    }
}