| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 | using Microsoft.Win32;using System;using System.Collections;using System.Collections.Generic;using System.Drawing;using System.Linq;using System.Reflection;namespace Optimizer{    public sealed class ColorOverrider    {        public static event Action SystemColorsChanging;        public static event Action SystemColorsChanged;        private int[] OriginalColors { get; }        private IReadOnlyDictionary<int, int> KnownOriginalColors;        private int[] _colorTable;        private readonly FieldInfo _colorTableField;        private readonly PropertyInfo _threadDataProperty;        public ColorOverrider()        {            // force init color table            byte unused = SystemColors.Window.R;            var systemDrawingAssembly = typeof(Color).Assembly;            string colorTableField = "colorTable";            _colorTableField = systemDrawingAssembly.GetType("System.Drawing.KnownColorTable")                .GetField(colorTableField, BindingFlags.Static | BindingFlags.NonPublic);            _colorTable = readColorTable();            SystemEvents.UserPreferenceChanging += userPreferenceChanging;            OriginalColors = _colorTable.ToArray();            KnownOriginalColors = KnownColors.Cast<int>()                .ToDictionary(i => i, i => OriginalColors[i]);            _threadDataProperty = systemDrawingAssembly.GetType("System.Drawing.SafeNativeMethods")                .GetNestedType("Gdip", BindingFlags.NonPublic)                .GetProperty("ThreadData", BindingFlags.Static | BindingFlags.NonPublic);            string systemBrushesKeyField = "SystemBrushesKey";            SystemBrushesKey = typeof(SystemBrushes)                .GetField(systemBrushesKeyField, BindingFlags.Static | BindingFlags.NonPublic)                ?.GetValue(null);            SystemPensKey = typeof(SystemPens)                .GetField("SystemPensKey", BindingFlags.Static | BindingFlags.NonPublic)                ?.GetValue(null);        }        private void userPreferenceChanging(object sender, UserPreferenceChangingEventArgs e)        {            if (e.Category != UserPreferenceCategory.Color)                return;            _colorTable = readColorTable();            fireColorsChangedEvents();        }        private static void fireColorsChangedEvents()        {            SystemColorsChanging?.Invoke();            SystemColorsChanged?.Invoke();        }        private int[] readColorTable() =>            (int[])_colorTableField.GetValue(null);        public void SetColor(KnownColor knownColor, int argb)        {            setColor(knownColor, argb);            if (SystemBrushesKey != null)                ThreadData[SystemBrushesKey] = null;            if (SystemPensKey != null)                ThreadData[SystemPensKey] = null;            fireColorsChangedEvents();        }        private void setColor(KnownColor knownColor, int argb) =>            _colorTable[(int)knownColor] = argb;        public int GetOriginalColor(KnownColor knownColor) =>            OriginalColors[(int)knownColor];        public int GetColor(KnownColor knownColor)        {            if (!KnownColors.Contains(knownColor))                throw new ArgumentException();            return _colorTable[(int)knownColor];        }        public IReadOnlyDictionary<int, int> Save() =>            KnownColors.Cast<int>()                .ToDictionary(i => i, i => _colorTable[i]);        public void Load(IReadOnlyDictionary<int, int> saved)        {            foreach (var color in KnownColors)            {                int v;                var value = saved.TryGetValue((int)color, out v);                setColor(color, v);            }            if (SystemBrushesKey != null)                ThreadData[SystemBrushesKey] = null;            if (SystemPensKey != null)                ThreadData[SystemPensKey] = null;            fireColorsChangedEvents();        }        public void Reset(KnownColor color) =>            SetColor(color, OriginalColors[(int)color]);        public void ResetAll() =>            Load(KnownOriginalColors);        private IDictionary ThreadData =>            (IDictionary)_threadDataProperty.GetValue(null, null);        private object SystemBrushesKey { get; }        private object SystemPensKey { get; }        public readonly HashSet<KnownColor> KnownColors = new HashSet<KnownColor>(            new[]            {                SystemColors.Control,                SystemColors.ControlText,                SystemColors.ButtonFace, // menu gradient				SystemColors.ButtonShadow, // menu border				SystemColors.Window,                SystemColors.WindowText,                SystemColors.GrayText,                SystemColors.HotTrack,                SystemColors.Highlight,                SystemColors.HighlightText,                SystemColors.ActiveCaption,                SystemColors.GradientActiveCaption,                SystemColors.InactiveCaption,                SystemColors.GradientInactiveCaption,                SystemColors.ActiveBorder            }.Select(_ => _.ToKnownColor())        );    }}
 |