diff --git a/CommonHelpers/CommonHelpers.csproj b/CommonHelpers/CommonHelpers.csproj index fa385ec..842cef6 100644 --- a/CommonHelpers/CommonHelpers.csproj +++ b/CommonHelpers/CommonHelpers.csproj @@ -14,17 +14,8 @@ - RTSSSharedMemoryNET.dll + ..\ExternalHelpers\RTSSSharedMemoryNET.dll - - - PreserveNewest - - - PreserveNewest - - - diff --git a/ExternalHelpers/ExternalHelpers.csproj b/ExternalHelpers/ExternalHelpers.csproj new file mode 100644 index 0000000..247d3ee --- /dev/null +++ b/ExternalHelpers/ExternalHelpers.csproj @@ -0,0 +1,31 @@ + + + + net6.0-windows + enable + true + enable + True + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/PowerControl/External/GlobalHotKey.cs b/ExternalHelpers/GlobalHotKey.cs similarity index 96% rename from PowerControl/External/GlobalHotKey.cs rename to ExternalHelpers/GlobalHotKey.cs index 0015a77..331fa7e 100644 --- a/PowerControl/External/GlobalHotKey.cs +++ b/ExternalHelpers/GlobalHotKey.cs @@ -4,8 +4,11 @@ using System.Runtime.InteropServices; using System.Windows.Forms; using System.Windows.Input; -namespace PowerControl.External +namespace ExternalHelpers { + /// + /// Taken and adapted from: https://stackoverflow.com/a/65412682 + /// public class GlobalHotKey : IDisposable { /// @@ -30,7 +33,7 @@ namespace PowerControl.External return success; } - public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction, bool repeat = false) + public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction, bool repeat) { if (aModifier == ModifierKeys.None && false) { @@ -44,7 +47,7 @@ namespace PowerControl.External System.Windows.Forms.Keys aVirtualKeyCode = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(aKey); currentID = currentID + 1; bool aRegistered = RegisterHotKey(window.Handle, currentID, - (uint)aModifier | (repeat ? 0 : MOD_NOREPEAT), + (uint)aModifier | (repeat ? MOD_NOREPEAT : 0), (uint)aVirtualKeyCode); if (aRegistered) diff --git a/ExternalHelpers/PhysicalMonitorBrightnessController.cs b/ExternalHelpers/PhysicalMonitorBrightnessController.cs new file mode 100644 index 0000000..03faaf0 --- /dev/null +++ b/ExternalHelpers/PhysicalMonitorBrightnessController.cs @@ -0,0 +1,177 @@ +using Microsoft.VisualBasic.Logging; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.InteropServices; + +namespace PowerControl.Helpers +{ + // Taken from: https://stackoverflow.com/questions/4013622/adjust-screen-brightness-using-c-sharp + public class PhysicalMonitorBrightnessController : IDisposable + { + #region DllImport + [DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors); + + [DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray); + + [DllImport("dxva2.dll", EntryPoint = "GetMonitorBrightness")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetMonitorBrightness(IntPtr handle, ref uint minimumBrightness, ref uint currentBrightness, ref uint maxBrightness); + + [DllImport("dxva2.dll", EntryPoint = "SetMonitorBrightness")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetMonitorBrightness(IntPtr handle, uint newBrightness); + + [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitor")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DestroyPhysicalMonitor(IntPtr hMonitor); + + [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize, [In] PHYSICAL_MONITOR[] pPhysicalMonitorArray); + + [DllImport("user32.dll")] + static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, EnumMonitorsDelegate lpfnEnum, IntPtr dwData); + delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData); + #endregion + + private IReadOnlyCollection Monitors { get; set; } + + public PhysicalMonitorBrightnessController() + { + UpdateMonitors(); + } + + #region Get & Set + public void Set(uint brightness) + { + Set(brightness, true); + } + + private void Set(uint brightness, bool refreshMonitorsIfNeeded) + { + bool isSomeFail = false; + foreach (var monitor in Monitors) + { + uint realNewValue = (monitor.MaxValue - monitor.MinValue) * brightness / 100 + monitor.MinValue; + if (SetMonitorBrightness(monitor.Handle, realNewValue)) + { + monitor.CurrentValue = realNewValue; + } + else if (refreshMonitorsIfNeeded) + { + isSomeFail = true; + break; + } + } + + if (refreshMonitorsIfNeeded && (isSomeFail || !Monitors.Any())) + { + UpdateMonitors(); + Set(brightness, false); + return; + } + } + + public int Get() + { + if (!Monitors.Any()) + { + return -1; + } + return (int)Monitors.Average(d => d.CurrentValue); + } + #endregion + + private void UpdateMonitors() + { + DisposeMonitors(this.Monitors); + + var monitors = new List(); + EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) => + { + uint physicalMonitorsCount = 0; + if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, ref physicalMonitorsCount)) + { + // Cannot get monitor count + return true; + } + + var physicalMonitors = new PHYSICAL_MONITOR[physicalMonitorsCount]; + if (!GetPhysicalMonitorsFromHMONITOR(hMonitor, physicalMonitorsCount, physicalMonitors)) + { + // Cannot get physical monitor handle + return true; + } + + foreach (PHYSICAL_MONITOR physicalMonitor in physicalMonitors) + { + uint minValue = 0, currentValue = 0, maxValue = 0; + var info = new MonitorInfo + { + Handle = physicalMonitor.hPhysicalMonitor, + MinValue = minValue, + CurrentValue = currentValue, + MaxValue = maxValue, + }; + monitors.Add(info); + } + + return true; + }, IntPtr.Zero); + + this.Monitors = monitors; + } + + public void Dispose() + { + DisposeMonitors(Monitors); + GC.SuppressFinalize(this); + } + + private static void DisposeMonitors(IEnumerable monitors) + { + if (monitors?.Any() == true) + { + PHYSICAL_MONITOR[] monitorArray = monitors.Select(m => new PHYSICAL_MONITOR { hPhysicalMonitor = m.Handle }).ToArray(); + DestroyPhysicalMonitors((uint)monitorArray.Length, monitorArray); + } + } + + #region Classes + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct PHYSICAL_MONITOR + { + public IntPtr hPhysicalMonitor; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string szPhysicalMonitorDescription; + } + + [StructLayout(LayoutKind.Sequential)] + public struct Rect + { + public int left; + public int top; + public int right; + public int bottom; + } + + public class MonitorInfo + { + public uint MinValue { get; set; } + public uint MaxValue { get; set; } + public IntPtr Handle { get; set; } + public uint CurrentValue { get; set; } + } + #endregion + } + +} diff --git a/CommonHelpers/RTSSSharedMemoryNET.dll b/ExternalHelpers/RTSSSharedMemoryNET.dll similarity index 100% rename from CommonHelpers/RTSSSharedMemoryNET.dll rename to ExternalHelpers/RTSSSharedMemoryNET.dll diff --git a/PowerControl/External/SDStructs.cs b/ExternalHelpers/SDStructs.cs similarity index 89% rename from PowerControl/External/SDStructs.cs rename to ExternalHelpers/SDStructs.cs index 43c81fd..12707ff 100644 --- a/PowerControl/External/SDStructs.cs +++ b/ExternalHelpers/SDStructs.cs @@ -7,7 +7,10 @@ using System.Runtime.InteropServices; namespace PowerControl.External { - internal enum SDCPacketType + /// + /// Taken from: https://github.com/mKenfenheuer/neptune-hidapi.net/blob/main/Hid/HidEnums.cs + /// + public enum SDCPacketType { PT_INPUT = 0x01, PT_HOTPLUG = 0x03, @@ -26,7 +29,7 @@ namespace PowerControl.External PT_RESET = 0x95, PT_GET_SERIAL = 0xAE, } - internal enum SDCPacketLength + public enum SDCPacketLength { PL_LED = 0x03, PL_OFF = 0x04, @@ -35,14 +38,14 @@ namespace PowerControl.External PL_CONFIGURE_BT = 0x0f, PL_GET_SERIAL = 0x15, } - internal enum SDCConfigType + public enum SDCConfigType { CT_LED = 0x2d, CT_CONFIGURE = 0x32, CONFIGURE_BT = 0x18, } - internal enum SDCButton0 + public enum SDCButton0 { BTN_L5 = 0b1000000000000000, BTN_OPTIONS = 0b0100000000000000, @@ -62,7 +65,7 @@ namespace PowerControl.External BTN_R2 = 0b0000000000000001, } - internal enum SDCButton1 + public enum SDCButton1 { BTN_LSTICK_PRESS = 0b01000000, BTN_LPAD_TOUCH = 0b00001000, @@ -72,12 +75,12 @@ namespace PowerControl.External BTN_R5 = 0b00000001, } - internal enum SDCButton2 + public enum SDCButton2 { BTN_RSTICK_PRESS = 0b00000100, } - internal enum SDCButton4 + public enum SDCButton4 { BTN_LSTICK_TOUCH = 0b01000000, BTN_RSTICK_TOUCH = 0b10000000, @@ -85,14 +88,14 @@ namespace PowerControl.External BTN_L4 = 0b00000010, } - internal enum SDCButton5 + public enum SDCButton5 { BTN_QUICK_ACCESS = 0b00000100, } [StructLayout(LayoutKind.Sequential)] - internal struct SDCInput + public struct SDCInput { public byte ptype; //0x00 public byte _a1; //0x01 @@ -128,7 +131,7 @@ namespace PowerControl.External public short lpad_pressure; //0x38 public short rpad_pressure; //0x3A - internal static SDCInput FromBuffer(byte[] bytes) + public static SDCInput FromBuffer(byte[] bytes) { var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try @@ -147,7 +150,7 @@ namespace PowerControl.External } [StructLayout(LayoutKind.Sequential)] - internal struct SDCHapticPacket + public struct SDCHapticPacket { public byte packet_type; // = 0x8f; public byte len; // = 0x07; diff --git a/CommonHelpers/FromLibreHardwareMonitor/StartupManager.cs b/ExternalHelpers/StartupManager.cs similarity index 93% rename from CommonHelpers/FromLibreHardwareMonitor/StartupManager.cs rename to ExternalHelpers/StartupManager.cs index 3061f02..efb33dc 100644 --- a/CommonHelpers/FromLibreHardwareMonitor/StartupManager.cs +++ b/ExternalHelpers/StartupManager.cs @@ -15,23 +15,26 @@ using Microsoft.Win32.TaskScheduler; using Action = Microsoft.Win32.TaskScheduler.Action; using Task = Microsoft.Win32.TaskScheduler.Task; -namespace CommonHelpers.FromLibreHardwareMonitor +namespace ExternalHelpers { + /// + /// Taken and adapter from: https://github.com/LibreHardwareMonitor/LibreHardwareMonitor/blob/master/LibreHardwareMonitor/UI/StartupManager.cs + /// public class StartupManager { private const string RegistryPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; private bool _startup; - public String NameOf { get; set; } - public String Description { get; set; } + public string NameOf { get; set; } + public string Description { get; set; } - public StartupManager(String name, String description = null) + public StartupManager(string name, string description = null) { NameOf = name; if (description != null) Description = description; else - Description = String.Format("Starts {0} on Windows startup", name); + Description = string.Format("Starts {0} on Windows startup", name); if (Environment.OSVersion.Platform >= PlatformID.Unix) { diff --git a/PowerControl/Helpers/WindowsMasterVolume.cs b/ExternalHelpers/WindowsMasterVolume.cs similarity index 100% rename from PowerControl/Helpers/WindowsMasterVolume.cs rename to ExternalHelpers/WindowsMasterVolume.cs index a48848c..70b5c58 100644 --- a/PowerControl/Helpers/WindowsMasterVolume.cs +++ b/ExternalHelpers/WindowsMasterVolume.cs @@ -14,6 +14,11 @@ namespace PowerControl.Helpers /// public static class AudioManager { + public static int GetMasterVolume(double roundValue) + { + return (int)(Math.Round(GetMasterVolume() / roundValue) * roundValue); + } + #region Master Volume Manipulation /// @@ -42,11 +47,6 @@ namespace PowerControl.Helpers } } - public static int GetMasterVolume(double roundValue) - { - return (int)(Math.Round(GetMasterVolume() / roundValue) * roundValue); - } - /// /// Gets the mute state of the master volume. /// While the volume can be muted the will still return the pre-muted volume value. diff --git a/PowerControl/Helpers/WindowsSettingsBrightnessController.cs b/ExternalHelpers/WindowsSettingsBrightnessController.cs similarity index 88% rename from PowerControl/Helpers/WindowsSettingsBrightnessController.cs rename to ExternalHelpers/WindowsSettingsBrightnessController.cs index 1cb498c..ef078d7 100644 --- a/PowerControl/Helpers/WindowsSettingsBrightnessController.cs +++ b/ExternalHelpers/WindowsSettingsBrightnessController.cs @@ -7,8 +7,16 @@ using System.Threading.Tasks; namespace PowerControl.Helpers { + /// + /// Taken from: https://gist.github.com/maxkoshevoi/b8a1ad91f4d2a9fd3931168c14080694 + /// public static class WindowsSettingsBrightnessController { + public static int Get(double roundValue = 10.0) + { + return (int)(Math.Round(Get() / roundValue) * roundValue); + } + public static int Get() { try @@ -30,11 +38,6 @@ namespace PowerControl.Helpers } } - public static int Get(double roundValue = 10.0) - { - return (int)(Math.Round(Get() / roundValue) * roundValue); - } - public static void Set(int brightness) { using var mclass = new ManagementClass("WmiMonitorBrightnessMethods") diff --git a/PowerControl/hidapi.dll b/ExternalHelpers/hidapi.dll similarity index 100% rename from PowerControl/hidapi.dll rename to ExternalHelpers/hidapi.dll diff --git a/PowerControl/hidapi.net.dll b/ExternalHelpers/hidapi.net.dll similarity index 100% rename from PowerControl/hidapi.net.dll rename to ExternalHelpers/hidapi.net.dll diff --git a/CommonHelpers/inpoutx64.dll b/ExternalHelpers/inpoutx64.dll similarity index 100% rename from CommonHelpers/inpoutx64.dll rename to ExternalHelpers/inpoutx64.dll diff --git a/FanControl/FanControl.csproj b/FanControl/FanControl.csproj index 0784371..ea1fbf8 100644 --- a/FanControl/FanControl.csproj +++ b/FanControl/FanControl.csproj @@ -18,6 +18,7 @@ + diff --git a/FanControl/FanControlForm.cs b/FanControl/FanControlForm.cs index c6fcad7..377a8af 100644 --- a/FanControl/FanControlForm.cs +++ b/FanControl/FanControlForm.cs @@ -1,5 +1,5 @@ using CommonHelpers; -using CommonHelpers.FromLibreHardwareMonitor; +using ExternalHelpers; using FanControl.Properties; using System; using System.Collections.Generic; diff --git a/PerformanceOverlay/Controller.cs b/PerformanceOverlay/Controller.cs index 6c7121a..bc04592 100644 --- a/PerformanceOverlay/Controller.cs +++ b/PerformanceOverlay/Controller.cs @@ -1,7 +1,6 @@ using CommonHelpers; -using CommonHelpers.FromLibreHardwareMonitor; +using ExternalHelpers; using Microsoft.VisualBasic.Logging; -using PerformanceOverlay.External; using RTSSSharedMemoryNET; using System; using System.Collections.Generic; diff --git a/PerformanceOverlay/External/GlobalHotKey.cs b/PerformanceOverlay/External/GlobalHotKey.cs deleted file mode 100644 index f172d1d..0000000 --- a/PerformanceOverlay/External/GlobalHotKey.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Windows.Forms; -using System.Windows.Input; - -namespace PerformanceOverlay.External -{ - public class GlobalHotKey : IDisposable - { - /// - /// Registers a global hotkey - /// - /// e.g. Alt + Shift + Control + Win + S - /// Action to be called when hotkey is pressed - /// true, if registration succeeded, otherwise false - public static bool RegisterHotKey(string aKeyGestureString, Action aAction) - { - var c = new KeyGestureConverter(); - KeyGesture aKeyGesture = (KeyGesture)c.ConvertFrom(aKeyGestureString); - return RegisterHotKey(aKeyGesture.Modifiers, aKeyGesture.Key, aAction); - } - - public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction) - { - if (aModifier == ModifierKeys.None && false) - { - throw new ArgumentException("Modifier must not be ModifierKeys.None"); - } - if (aAction is null) - { - throw new ArgumentNullException(nameof(aAction)); - } - - System.Windows.Forms.Keys aVirtualKeyCode = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(aKey); - currentID = currentID + 1; - bool aRegistered = RegisterHotKey(window.Handle, currentID, - (uint)aModifier | MOD_NOREPEAT, - (uint)aVirtualKeyCode); - - if (aRegistered) - { - registeredHotKeys.Add(new HotKeyWithAction(aModifier, aKey, aAction)); - } - return aRegistered; - } - - public void Dispose() - { - // unregister all the registered hot keys. - for (int i = currentID; i > 0; i--) - { - UnregisterHotKey(window.Handle, i); - } - - // dispose the inner native window. - window.Dispose(); - } - - static GlobalHotKey() - { - window.KeyPressed += (s, e) => - { - registeredHotKeys.ForEach(x => - { - if (e.Modifier == x.Modifier && e.Key == x.Key) - { - x.Action(); - } - }); - }; - } - - private static readonly InvisibleWindowForMessages window = new InvisibleWindowForMessages(); - private static int currentID; - private static uint MOD_NOREPEAT = 0x4000; - private static List registeredHotKeys = new List(); - - private class HotKeyWithAction - { - - public HotKeyWithAction(ModifierKeys modifier, Key key, Action action) - { - Modifier = modifier; - Key = key; - Action = action; - } - - public ModifierKeys Modifier { get; } - public Key Key { get; } - public Action Action { get; } - } - - // Registers a hot key with Windows. - [DllImport("user32.dll")] - private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); - // Unregisters the hot key with Windows. - [DllImport("user32.dll")] - private static extern bool UnregisterHotKey(IntPtr hWnd, int id); - - private class InvisibleWindowForMessages : System.Windows.Forms.NativeWindow, IDisposable - { - public InvisibleWindowForMessages() - { - CreateHandle(new System.Windows.Forms.CreateParams()); - } - - private static int WM_HOTKEY = 0x0312; - protected override void WndProc(ref System.Windows.Forms.Message m) - { - base.WndProc(ref m); - - if (m.Msg == WM_HOTKEY) - { - var aWPFKey = KeyInterop.KeyFromVirtualKey(((int)m.LParam >> 16) & 0xFFFF); - ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF); - if (KeyPressed != null) - { - KeyPressed(this, new HotKeyPressedEventArgs(modifier, aWPFKey)); - } - } - } - - public class HotKeyPressedEventArgs : EventArgs - { - private ModifierKeys _modifier; - private Key _key; - - internal HotKeyPressedEventArgs(ModifierKeys modifier, Key key) - { - _modifier = modifier; - _key = key; - } - - public ModifierKeys Modifier - { - get { return _modifier; } - } - - public Key Key - { - get { return _key; } - } - } - - - public event EventHandler KeyPressed; - - #region IDisposable Members - - public void Dispose() - { - this.DestroyHandle(); - } - - #endregion - } - } - -} diff --git a/PerformanceOverlay/PerformanceOverlay.csproj b/PerformanceOverlay/PerformanceOverlay.csproj index 937695f..84b2082 100644 --- a/PerformanceOverlay/PerformanceOverlay.csproj +++ b/PerformanceOverlay/PerformanceOverlay.csproj @@ -29,11 +29,12 @@ + - ..\CommonHelpers\RTSSSharedMemoryNET.dll + ..\ExternalHelpers\RTSSSharedMemoryNET.dll diff --git a/PowerControl/Controller.cs b/PowerControl/Controller.cs index 073f8e5..18faf2a 100644 --- a/PowerControl/Controller.cs +++ b/PowerControl/Controller.cs @@ -1,5 +1,5 @@ using CommonHelpers; -using CommonHelpers.FromLibreHardwareMonitor; +using ExternalHelpers; using Microsoft.VisualBasic.Logging; using PowerControl.External; using PowerControl.Helpers; diff --git a/PowerControl/Helpers/PhysicalMonitorBrightnessController.cs b/PowerControl/Helpers/DisplayResolutionController.cs similarity index 64% rename from PowerControl/Helpers/PhysicalMonitorBrightnessController.cs rename to PowerControl/Helpers/DisplayResolutionController.cs index 2a92a8f..3e31f08 100644 --- a/PowerControl/Helpers/PhysicalMonitorBrightnessController.cs +++ b/PowerControl/Helpers/DisplayResolutionController.cs @@ -1,45 +1,165 @@ -using Microsoft.VisualBasic.Logging; -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using static PowerControl.Helpers.PhysicalMonitorBrightnessController; namespace PowerControl.Helpers { - // Taken from: https://stackoverflow.com/questions/4013622/adjust-screen-brightness-using-c-sharp - public class PhysicalMonitorBrightnessController : IDisposable + internal class DisplayResolutionController { - #region DllImport - [DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors); + public struct DisplayResolution : IComparable + { + public int Width { get; set; } + public int Height { get; set; } - [DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray); + public DisplayResolution() { Width = 0; Height = 0; } - [DllImport("dxva2.dll", EntryPoint = "GetMonitorBrightness")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetMonitorBrightness(IntPtr handle, ref uint minimumBrightness, ref uint currentBrightness, ref uint maxBrightness); + public DisplayResolution(int width, int height) { Width = width; Height = height; } - [DllImport("dxva2.dll", EntryPoint = "SetMonitorBrightness")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool SetMonitorBrightness(IntPtr handle, uint newBrightness); + public static bool operator ==(DisplayResolution sz1, DisplayResolution sz2) => sz1.Width == sz2.Width && sz1.Height == sz2.Height; - [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitor")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DestroyPhysicalMonitor(IntPtr hMonitor); + public static bool operator !=(DisplayResolution sz1, DisplayResolution sz2) => !(sz1 == sz2); - [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize, [In] PHYSICAL_MONITOR[] pPhysicalMonitorArray); + public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is DisplayResolution && Equals((DisplayResolution)obj); + public readonly bool Equals(DisplayResolution other) => this == other; + + public override readonly int GetHashCode() => HashCode.Combine(Width, Height); + + public int CompareTo(DisplayResolution other) + { + var index = Width.CompareTo(other.Width); + if (index == 0) index = Height.CompareTo(other.Height); + return index; + } + + public override string ToString() + { + return String.Format("{0}x{1}", Width, Height); + } + } + + private static IEnumerable FindAllDisplaySettings() + { + DEVMODE dm = new DEVMODE(); + for (int i = 0; EnumDisplaySettings(null, i, ref dm); i++) + { + if (dm.dmFields.HasFlag(DM.PelsWidth) && dm.dmFields.HasFlag(DM.PelsHeight) && dm.dmFields.HasFlag(DM.PelsHeight)) + yield return dm; + + dm = new DEVMODE(); + } + } + + private static DEVMODE? CurrentDisplaySettings() + { + DEVMODE dm = new DEVMODE(); + if (EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) + return dm; + return null; + } + + public static DisplayResolution[] GetAllResolutions() + { + return FindAllDisplaySettings() + .Select((dm) => new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight)) + .ToImmutableSortedSet() + .ToArray(); + } + + public static DisplayResolution? GetResolution() + { + var dm = CurrentDisplaySettings(); + if (dm is not null) + return new DisplayResolution(dm.Value.dmPelsWidth, dm.Value.dmPelsHeight); + + return null; + } + + public static bool SetResolution(DisplayResolution size) + { + DEVMODE? best = FindAllDisplaySettings() + .Where((dm) => dm.dmPelsWidth == size.Width && dm.dmPelsHeight == size.Height) + .MaxBy((dm) => dm.dmDisplayFrequency); + + if (best == null) + return false; + + DEVMODE dm = best.Value; + + var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero); + + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) + return false; + + Trace.WriteLine("DispChange: " + dispChange.ToString() + " Size:" + size.ToString() + + " SetSize:" + new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight).ToString()); + + if (dispChange == DISP_CHANGE.Successful) + return true; + + return true; + } + + public static int[] GetRefreshRates(DisplayResolution? size = null) + { + if (size is null) + size = GetResolution(); + if (size is null) + return new int[0]; + + return FindAllDisplaySettings() + .Where((dm) => dm.dmPelsWidth == size?.Width && dm.dmPelsHeight == size?.Height) + .Select((dm) => dm.dmDisplayFrequency) + .ToHashSet() + .ToArray(); + } + + public static int GetRefreshRate() + { + var dm = CurrentDisplaySettings(); + + if (dm is not null) + return dm.Value.dmDisplayFrequency; + + return -1; + } + + public static bool SetRefreshRate(int hz) + { + var current = CurrentDisplaySettings(); + + if (current is null) + return false; + + DEVMODE? best = FindAllDisplaySettings() + .Where((dm) => dm.dmPelsWidth == current.Value.dmPelsWidth && dm.dmPelsHeight == current.Value.dmPelsHeight) + .Where((dm) => dm.dmDisplayFrequency == hz) + .First(); + + if (best is null) + return false; + + DEVMODE dm = best.Value; + + var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero); + + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) + return false; + + Trace.WriteLine("DispChange: " + dispChange.ToString() + " HZ:" + hz.ToString() + " SetHZ:" + dm.dmDisplayFrequency.ToString()); + + if (dispChange == DISP_CHANGE.Successful) + return true; + + return true; + } - [DllImport("user32.dll")] - static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, EnumMonitorsDelegate lpfnEnum, IntPtr dwData); - delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData); enum DISP_CHANGE : int { @@ -192,285 +312,5 @@ namespace PowerControl.Helpers [DllImport("user32.dll")] static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); - #endregion - - private IReadOnlyCollection Monitors { get; set; } - - public PhysicalMonitorBrightnessController() - { - UpdateMonitors(); - } - - public struct DisplayResolution : IComparable - { - public int Width { get; set; } - public int Height { get; set; } - - public DisplayResolution() { Width = 0; Height = 0; } - - public DisplayResolution(int width, int height) { Width = width; Height = height; } - - public static bool operator ==(DisplayResolution sz1, DisplayResolution sz2) => sz1.Width == sz2.Width && sz1.Height == sz2.Height; - - public static bool operator !=(DisplayResolution sz1, DisplayResolution sz2) => !(sz1 == sz2); - - public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is DisplayResolution && Equals((DisplayResolution)obj); - public readonly bool Equals(DisplayResolution other) => this == other; - - public override readonly int GetHashCode() => HashCode.Combine(Width, Height); - - public int CompareTo(DisplayResolution other) - { - var index = Width.CompareTo(other.Width); - if (index == 0) index = Height.CompareTo(other.Height); - return index; - } - - public override string ToString() - { - return String.Format("{0}x{1}", Width, Height); - } - } - - #region Get & Set - public void Set(uint brightness) - { - Set(brightness, true); - } - - private static IEnumerable FindAllDisplaySettings() - { - DEVMODE dm = new DEVMODE(); - for (int i = 0; EnumDisplaySettings(null, i, ref dm); i++) - { - if (dm.dmFields.HasFlag(DM.PelsWidth) && dm.dmFields.HasFlag(DM.PelsHeight) && dm.dmFields.HasFlag(DM.PelsHeight)) - yield return dm; - - dm = new DEVMODE(); - } - } - - private static DEVMODE? CurrentDisplaySettings() - { - DEVMODE dm = new DEVMODE(); - if (EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) - return dm; - return null; - } - - public static DisplayResolution[] GetAllResolutions() - { - return FindAllDisplaySettings() - .Select((dm) => new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight)) - .ToImmutableSortedSet() - .ToArray(); - } - - public static DisplayResolution? GetResolution() - { - var dm = CurrentDisplaySettings(); - if (dm is not null) - return new DisplayResolution(dm.Value.dmPelsWidth, dm.Value.dmPelsHeight); - - return null; - } - - public static bool SetResolution(DisplayResolution size) - { - DEVMODE? best = FindAllDisplaySettings() - .Where((dm) => dm.dmPelsWidth == size.Width && dm.dmPelsHeight == size.Height) - .MaxBy((dm) => dm.dmDisplayFrequency); - - if (best == null) - return false; - - DEVMODE dm = best.Value; - - var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero); - - if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) - return false; - - Trace.WriteLine("DispChange: " + dispChange.ToString() + " Size:" + size.ToString() + - " SetSize:" + new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight).ToString()); - - if (dispChange == DISP_CHANGE.Successful) - return true; - - return true; - } - - public static int[] GetRefreshRates(DisplayResolution? size = null) - { - if (size is null) - size = GetResolution(); - if (size is null) - return new int[0]; - - return FindAllDisplaySettings() - .Where((dm) => dm.dmPelsWidth == size?.Width && dm.dmPelsHeight == size?.Height) - .Select((dm) => dm.dmDisplayFrequency) - .ToHashSet() - .ToArray(); - } - - public static int GetRefreshRate() - { - var dm = CurrentDisplaySettings(); - - if (dm is not null) - return dm.Value.dmDisplayFrequency; - - return -1; - } - - public static bool SetRefreshRate(int hz) - { - var current = CurrentDisplaySettings(); - - if (current is null) - return false; - - DEVMODE? best = FindAllDisplaySettings() - .Where((dm) => dm.dmPelsWidth == current.Value.dmPelsWidth && dm.dmPelsHeight == current.Value.dmPelsHeight) - .Where((dm) => dm.dmDisplayFrequency == hz) - .First(); - - if (best is null) - return false; - - DEVMODE dm = best.Value; - - var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero); - - if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) - return false; - - Trace.WriteLine("DispChange: " + dispChange.ToString() + " HZ:" + hz.ToString() + " SetHZ:" + dm.dmDisplayFrequency.ToString()); - - if (dispChange == DISP_CHANGE.Successful) - return true; - - return true; - } - - private void Set(uint brightness, bool refreshMonitorsIfNeeded) - { - bool isSomeFail = false; - foreach (var monitor in Monitors) - { - uint realNewValue = (monitor.MaxValue - monitor.MinValue) * brightness / 100 + monitor.MinValue; - if (SetMonitorBrightness(monitor.Handle, realNewValue)) - { - monitor.CurrentValue = realNewValue; - } - else if (refreshMonitorsIfNeeded) - { - isSomeFail = true; - break; - } - } - - if (refreshMonitorsIfNeeded && (isSomeFail || !Monitors.Any())) - { - UpdateMonitors(); - Set(brightness, false); - return; - } - } - - public int Get() - { - if (!Monitors.Any()) - { - return -1; - } - return (int)Monitors.Average(d => d.CurrentValue); - } - #endregion - - private void UpdateMonitors() - { - DisposeMonitors(this.Monitors); - - var monitors = new List(); - EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) => - { - uint physicalMonitorsCount = 0; - if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, ref physicalMonitorsCount)) - { - // Cannot get monitor count - return true; - } - - var physicalMonitors = new PHYSICAL_MONITOR[physicalMonitorsCount]; - if (!GetPhysicalMonitorsFromHMONITOR(hMonitor, physicalMonitorsCount, physicalMonitors)) - { - // Cannot get physical monitor handle - return true; - } - - foreach (PHYSICAL_MONITOR physicalMonitor in physicalMonitors) - { - uint minValue = 0, currentValue = 0, maxValue = 0; - var info = new MonitorInfo - { - Handle = physicalMonitor.hPhysicalMonitor, - MinValue = minValue, - CurrentValue = currentValue, - MaxValue = maxValue, - }; - monitors.Add(info); - } - - return true; - }, IntPtr.Zero); - - this.Monitors = monitors; - } - - public void Dispose() - { - DisposeMonitors(Monitors); - GC.SuppressFinalize(this); - } - - private static void DisposeMonitors(IEnumerable monitors) - { - if (monitors?.Any() == true) - { - PHYSICAL_MONITOR[] monitorArray = monitors.Select(m => new PHYSICAL_MONITOR { hPhysicalMonitor = m.Handle }).ToArray(); - DestroyPhysicalMonitors((uint)monitorArray.Length, monitorArray); - } - } - - #region Classes - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct PHYSICAL_MONITOR - { - public IntPtr hPhysicalMonitor; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] - public string szPhysicalMonitorDescription; - } - - [StructLayout(LayoutKind.Sequential)] - public struct Rect - { - public int left; - public int top; - public int right; - public int bottom; - } - - public class MonitorInfo - { - public uint MinValue { get; set; } - public uint MaxValue { get; set; } - public IntPtr Handle { get; set; } - public uint CurrentValue { get; set; } - } - #endregion } - } diff --git a/PowerControl/Helpers/RTSS.cs b/PowerControl/Helpers/RTSS.cs index dd9219a..a0f5e3d 100644 --- a/PowerControl/Helpers/RTSS.cs +++ b/PowerControl/Helpers/RTSS.cs @@ -20,7 +20,7 @@ namespace PowerControl.Helpers { try { - processId = (int?)Helpers.TopLevelWindow.GetTopLevelProcessId(); + processId = (int?)GetTopLevelProcessId(); if (processId is null) return false; @@ -81,11 +81,17 @@ namespace PowerControl.Helpers } } - [DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", SetLastError = true)] - public static extern IntPtr GetModuleHandle(string moduleName); + public static uint EnableFlag(uint flag, bool status) + { + var current = SetFlags(~flag, status ? flag : 0); + UpdateSettings(); + return current; + } - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] - static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); + public static void UpdateSettings() + { + PostMessage(WM_RTSS_UPDATESETTINGS, IntPtr.Zero, IntPtr.Zero); + } [return: MarshalAs(UnmanagedType.Bool)] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] @@ -118,6 +124,21 @@ namespace PowerControl.Helpers [DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)] public static extern void UpdateProfiles(); + [DllImport("user32.dll", SetLastError = true)] + static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + private static uint? GetTopLevelProcessId() + { + var hWnd = GetForegroundWindow(); + var result = GetWindowThreadProcessId(hWnd, out uint processId); + if (result != 0) + return processId; + return null; + } + private static void PostMessage(uint Msg, IntPtr wParam, IntPtr lParam) { var hWnd = FindWindow(null, "RTSS"); @@ -128,18 +149,6 @@ namespace PowerControl.Helpers PostMessage(hWnd, Msg, wParam, lParam); } - public static uint EnableFlag(uint flag, bool status) - { - var current = SetFlags(~flag, status ? flag : 0); - UpdateSettings(); - return current; - } - - public static void UpdateSettings() - { - PostMessage(WM_RTSS_UPDATESETTINGS, IntPtr.Zero, IntPtr.Zero); - } - public const uint WM_APP = 0x8000; public const uint WM_RTSS_UPDATESETTINGS = WM_APP + 100; public const uint WM_RTSS_SHOW_PROPERTIES = WM_APP + 102; diff --git a/PowerControl/Helpers/TopLevelWindow.cs b/PowerControl/Helpers/TopLevelWindow.cs deleted file mode 100644 index d89d87d..0000000 --- a/PowerControl/Helpers/TopLevelWindow.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace PowerControl.Helpers -{ - public class TopLevelWindow - { - [DllImport("user32.dll", SetLastError= true)] - static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); - - [DllImport("user32.dll")] - public static extern IntPtr GetForegroundWindow(); - - public static uint? GetTopLevelProcessId() - { - var hWnd = GetForegroundWindow(); - var result = GetWindowThreadProcessId(hWnd, out uint processId); - if (result != 0) - return processId; - return null; - } - } -} diff --git a/PowerControl/MenuStack.cs b/PowerControl/MenuStack.cs index d662a3a..53dd124 100644 --- a/PowerControl/MenuStack.cs +++ b/PowerControl/MenuStack.cs @@ -59,11 +59,11 @@ namespace PowerControl ResetValue = () => { if (!AMDAdrenaline.IsGPUScalingEnabled() && !Settings.Default.EnableExperimentalFeatures) return null; - return Helpers.PhysicalMonitorBrightnessController.GetAllResolutions().Last(); + return DisplayResolutionController.GetAllResolutions().Last(); }, OptionsValues = delegate() { - var resolutions = Helpers.PhysicalMonitorBrightnessController.GetAllResolutions(); + var resolutions = DisplayResolutionController.GetAllResolutions(); if (resolutions.Count() > 1) return resolutions.Select(item => (object)item).ToArray(); return null; @@ -72,37 +72,37 @@ namespace PowerControl { if (!AMDAdrenaline.IsGPUScalingEnabled() && !Settings.Default.EnableExperimentalFeatures) return null; - return Helpers.PhysicalMonitorBrightnessController.GetResolution(); + return DisplayResolutionController.GetResolution(); }, ApplyValue = delegate(object selected) { - Helpers.PhysicalMonitorBrightnessController.SetResolution((DisplayResolution)selected); + DisplayResolutionController.SetResolution((DisplayResolutionController.DisplayResolution)selected); Root["Refresh Rate"].Update(); // force refresh Refresh Rate Root["FPS Limit"].Update(); // force refresh FPS limit - return Helpers.PhysicalMonitorBrightnessController.GetResolution(); + return DisplayResolutionController.GetResolution(); } }, new Menu.MenuItemWithOptions() { Name = "Refresh Rate", ApplyDelay = 1000, - ResetValue = () => { return Helpers.PhysicalMonitorBrightnessController.GetRefreshRates().Max(); }, + ResetValue = () => { return DisplayResolutionController.GetRefreshRates().Max(); }, OptionsValues = delegate() { - var refreshRates = Helpers.PhysicalMonitorBrightnessController.GetRefreshRates(); + var refreshRates = DisplayResolutionController.GetRefreshRates(); if (refreshRates.Count() > 1) return refreshRates.Select(item => (object)item).ToArray(); return null; }, CurrentValue = delegate() { - return Helpers.PhysicalMonitorBrightnessController.GetRefreshRate(); + return DisplayResolutionController.GetRefreshRate(); }, ApplyValue = delegate(object selected) { - Helpers.PhysicalMonitorBrightnessController.SetRefreshRate((int)selected); + DisplayResolutionController.SetRefreshRate((int)selected); Root["FPS Limit"].Update(); // force refresh FPS limit - return Helpers.PhysicalMonitorBrightnessController.GetRefreshRate(); + return DisplayResolutionController.GetRefreshRate(); } }, new Menu.MenuItemWithOptions() @@ -112,7 +112,7 @@ namespace PowerControl ResetValue = () => { return "Off"; }, OptionsValues = delegate() { - var refreshRate = Helpers.PhysicalMonitorBrightnessController.GetRefreshRate(); + var refreshRate = DisplayResolutionController.GetRefreshRate(); return new object[] { refreshRate / 4, refreshRate / 2, refreshRate, "Off" diff --git a/PowerControl/PowerControl.csproj b/PowerControl/PowerControl.csproj index 5fa715d..dc6d30e 100644 --- a/PowerControl/PowerControl.csproj +++ b/PowerControl/PowerControl.csproj @@ -29,14 +29,15 @@ + - hidapi.net.dll + ..\ExternalHelpers\hidapi.net.dll - ..\CommonHelpers\RTSSSharedMemoryNET.dll + ..\ExternalHelpers\RTSSSharedMemoryNET.dll @@ -61,12 +62,6 @@ - - PreserveNewest - - - PreserveNewest - PreserveNewest diff --git a/SteamDeckTools.sln b/SteamDeckTools.sln index 5101fda..41e7921 100644 --- a/SteamDeckTools.sln +++ b/SteamDeckTools.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceOverlay", "Perfo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommonHelpers", "CommonHelpers\CommonHelpers.csproj", "{17728E90-015B-4221-8AA8-68FB359FA12F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerControl", "PowerControl\PowerControl.csproj", "{85A44F35-60C9-493E-B1A7-FB2284E5ACCF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerControl", "PowerControl\PowerControl.csproj", "{85A44F35-60C9-493E-B1A7-FB2284E5ACCF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExternalHelpers", "ExternalHelpers\ExternalHelpers.csproj", "{A3FD29A4-844F-42B1-80C5-0301BD053AC0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -69,6 +71,18 @@ Global {85A44F35-60C9-493E-B1A7-FB2284E5ACCF}.Release|x64.Build.0 = Release|Any CPU {85A44F35-60C9-493E-B1A7-FB2284E5ACCF}.Release|x86.ActiveCfg = Release|Any CPU {85A44F35-60C9-493E-B1A7-FB2284E5ACCF}.Release|x86.Build.0 = Release|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Debug|x64.ActiveCfg = Debug|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Debug|x64.Build.0 = Debug|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Debug|x86.ActiveCfg = Debug|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Debug|x86.Build.0 = Debug|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|Any CPU.Build.0 = Release|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x64.ActiveCfg = Release|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x64.Build.0 = Release|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x86.ActiveCfg = Release|Any CPU + {A3FD29A4-844F-42B1-80C5-0301BD053AC0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE