[WIP] Refactor for taskbar code

Partially through a different refactor to completely change how the taskbar settigns are stored, and the logic behind the application. Should make the taskbar more robust to apply.
This commit is contained in:
Terry MacDonald 2022-02-01 22:04:08 +13:00
parent cd25f9a0fa
commit f6e5dbc0b7
7 changed files with 416 additions and 295 deletions

View File

@ -26,8 +26,8 @@ using System.Resources;
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
// Version information
[assembly: AssemblyVersion("2.2.0.152")]
[assembly: AssemblyFileVersion("2.2.0.152")]
[assembly: AssemblyVersion("2.2.0.154")]
[assembly: AssemblyFileVersion("2.2.0.154")]
[assembly: NeutralResourcesLanguageAttribute( "en" )]
[assembly: CLSCompliant(true)]

View File

@ -20,7 +20,7 @@ namespace DisplayMagician.UIForms
private Dictionary<Wallpaper.Style, string> wallpaperStyleText = new Dictionary<Wallpaper.Style, string>();
Bitmap wallpaperImage = null;
private Dictionary<TaskBarStuckRectangle.TaskBarForcedEdge, string> forcedTaskBarEdgeText = new Dictionary<TaskBarStuckRectangle.TaskBarForcedEdge, string>();
private Dictionary<TaskBarForcedEdge, string> forcedTaskBarEdgeText = new Dictionary<TaskBarForcedEdge, string>();
private bool _profileSettingChanged = false;
public ProfileSettingsForm()
@ -45,18 +45,18 @@ namespace DisplayMagician.UIForms
if (Utils.IsWindows11())
{
// Is Windows 11
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Left, "Left");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Top, "Top");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Right, "Right");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Bottom, "Bottom");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Left, "Left");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Top, "Top");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Right, "Right");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Bottom, "Bottom");
}
else
{
// Is Windows 10
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Left, "Left");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Top, "Top");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Right, "Right");
forcedTaskBarEdgeText.Add(TaskBarStuckRectangle.TaskBarForcedEdge.Bottom, "Bottom");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Left, "Left");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Top, "Top");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Right, "Right");
forcedTaskBarEdgeText.Add(TaskBarForcedEdge.Bottom, "Bottom");
}
cmb_forced_taskbar_location.DisplayMember = "Value";
@ -112,9 +112,9 @@ namespace DisplayMagician.UIForms
rb_leave_wallpaper.Checked = true;
cmb_wallpaper_display_mode.SelectedIndex = 0;
}
if (Profile.ForcedTaskBarEdge.Equals(TaskBarStuckRectangle.TaskBarForcedEdge.None))
WINDOWS_DISPLAY_CONFIG winConfig = Profile.WindowsDisplayConfig;
if (winConfig.TaskBarForcedEdge.Equals(TaskBarForcedEdge.None))
{
rb_default_taskbar.Checked = true;
cmb_forced_taskbar_location.SelectedIndex = 3;
@ -122,7 +122,7 @@ namespace DisplayMagician.UIForms
else
{
rb_forced_taskbar.Checked = true;
cmb_forced_taskbar_location.SelectedIndex = cmb_forced_taskbar_location.FindStringExact(forcedTaskBarEdgeText[Profile.ForcedTaskBarEdge]);
cmb_forced_taskbar_location.SelectedIndex = cmb_forced_taskbar_location.FindStringExact(forcedTaskBarEdgeText[winConfig.TaskBarForcedEdge]);
}
}
@ -144,17 +144,18 @@ namespace DisplayMagician.UIForms
Profile.WallpaperStyle = ((KeyValuePair<Wallpaper.Style, string>)cmb_wallpaper_display_mode.SelectedItem).Key;
WINDOWS_DISPLAY_CONFIG winConfig = Profile.WindowsDisplayConfig;
// Reset the taskbar layout binary to the original one we stored when the profile was made
winConfig.TaskBarLayout = new List<TaskBarStuckRectangle>(winConfig.OriginalTaskBarLayout);
if (rb_default_taskbar.Checked)
{
Profile.ForcedTaskBarEdge = TaskBarStuckRectangle.TaskBarForcedEdge.None;
winConfig.TaskBarForcedEdge = TaskBarForcedEdge.None;
}
else
{
Profile.ForcedTaskBarEdge = ((KeyValuePair<TaskBarStuckRectangle.TaskBarForcedEdge, string>)cmb_forced_taskbar_location.SelectedItem).Key;
winConfig.TaskBarForcedEdge = ((KeyValuePair<TaskBarForcedEdge, string>)cmb_forced_taskbar_location.SelectedItem).Key;
}
// Apply the changed taskbar settings to the windows config if needed
WINDOWS_DISPLAY_CONFIG winDispConfig = Profile.WindowsDisplayConfig;
TaskBarStuckRectangle.ForceTaskBarIfNeeded(ref winDispConfig.TaskBarLayout, Profile.ForcedTaskBarEdge);
}
private void btn_back_Click(object sender, EventArgs e)

View File

@ -73,8 +73,7 @@ namespace DisplayMagicianShared
private bool _isPossible = false;
private Keys _hotkey = Keys.None;
private string _wallpaperBitmapFilename = "";
private TaskBarStuckRectangle.TaskBarForcedEdge _forcedTaskBarEdge = TaskBarStuckRectangle.TaskBarForcedEdge.None;
#region JsonConverterBitmap
internal class CustomBitmapConverter : JsonConverter
@ -291,16 +290,6 @@ namespace DisplayMagicianShared
public string SavedProfileIconCacheFilename { get; set; }
public TaskBarStuckRectangle.TaskBarForcedEdge ForcedTaskBarEdge {
get
{
return _forcedTaskBarEdge;
}
set
{
_forcedTaskBarEdge = value;
}
}
public Wallpaper.Mode WallpaperMode { get; set; }
@ -461,7 +450,6 @@ namespace DisplayMagicianShared
profile.WallpaperMode = WallpaperMode;
profile.WallpaperBitmapFilename = WallpaperBitmapFilename;
profile.WallpaperStyle = WallpaperStyle;
profile.ForcedTaskBarEdge = ForcedTaskBarEdge;
return true;
}

View File

@ -842,14 +842,14 @@ namespace DisplayMagicianShared
// Now we try to patch in a Windows Taskbar Stuck Rects list into the json if there isnt one
SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Looking for a missing ForcedTaskBarEdge setting in Profile.");
// Create a default object (a default of NONE)
TaskBarStuckRectangle.TaskBarForcedEdge taskBarForcedEdge = TaskBarStuckRectangle.TaskBarForcedEdge.None;
TaskBarForcedEdge taskBarForcedEdge = TaskBarForcedEdge.None;
for (int i = 0; i < root.Count; i++)
{
JObject profile = (JObject)root[i];
JValue forcedTaskBarEdge = (JValue)profile.SelectToken("ForcedTaskBarEdge");
if (forcedTaskBarEdge == null)
{
JProperty newForcedTaskBarEdge = new JProperty("ForcedTaskBarEdge", TaskBarStuckRectangle.TaskBarForcedEdge.None);
JProperty newForcedTaskBarEdge = new JProperty("ForcedTaskBarEdge", TaskBarForcedEdge.None);
profile.Add("ForcedTaskBarEdge", newForcedTaskBarEdge);
changedJson = true;
SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Patched missing ForcedTaskBarEdge in profile {profile.SelectToken("Name")} (index {i}).");
@ -870,6 +870,9 @@ namespace DisplayMagicianShared
JObject WindowsDisplayConfig = (JObject)profile.SelectToken("WindowsDisplayConfig");
JArray newTaskBarLayout = JArray.FromObject(taskBarStuckRectangles);
WindowsDisplayConfig.Add("TaskBarLayout",newTaskBarLayout);
WindowsDisplayConfig.Add("OriginalTaskBarLayout", newTaskBarLayout);
JProperty newTaskBarForcedEdge = new JProperty("TaskBarForcedEdge", TaskBarForcedEdge.None);
WindowsDisplayConfig.Add("TaskBarForcedEdge", newTaskBarForcedEdge);
changedJson = true;
SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Patched missing Windows TaskBarLayout in profile {profile.SelectToken("Name")} (index {i}).");
}

View File

@ -16,15 +16,7 @@ namespace DisplayMagicianShared.Windows
{
public class TaskBarStuckRectangle
{
public enum TaskBarForcedEdge : UInt32
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3,
None = 9999
}
public enum TaskBarEdge : UInt32
{
Left = 0,
@ -59,51 +51,153 @@ namespace DisplayMagicianShared.Windows
private const string MultiDisplayAddress =
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MMStuckRects{0:D}";
private static readonly Dictionary<int, byte[]> Headers = new Dictionary<int, byte[]>
/*private static readonly Dictionary<int, byte[]> Headers = new Dictionary<int, byte[]>
{
{2, new byte[] {0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}},
{3, new byte[] {0x30, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF}}
};
public TaskBarStuckRectangle(int version, string devicePath) : this(version)
*/
public TaskBarStuckRectangle(string devicePath)
{
DevicePath = devicePath;
}
public TaskBarStuckRectangle(int version)
{
if (!Headers.ContainsKey(version))
bool MMStuckRectVerFound = false;
// Check if key exists
int version = 2;
string address = string.Format(MultiDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) != null)
{
throw new ArgumentException(@"Invalid version number specified.", nameof(version));
MMStuckRectVerFound = true;
}
else
{
// If it's not version 2, then try version 3
version = 3;
address = string.Format(MultiDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) != null)
{
MMStuckRectVerFound = true;
}
else
{
// It's not v2 or v3, so it must be a single display
MMStuckRectVerFound = false;
}
}
Version = version;
DevicePath = null;
bool foundDevicePath = false;
if (MMStuckRectVerFound)
{
// Check if value exists
if (version >= 2 && version <= 3)
{
using (var key = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadSubTree))
{
var binary = key?.GetValue(devicePath) as byte[];
if (binary?.Length > 0)
{
foundDevicePath = true;
MainScreen = false;
DevicePath = devicePath;
Binary = binary;
Version = version;
Binary = new byte[Headers[Version][0]];
Array.Copy(Headers[Version], 0, Binary, 0, Headers[Version].Length);
// Extract the values from the binary byte field
PopulateFieldsFromBinary();
DPI = 96;
Rows = 1;
Location = Rectangle.Empty;
MinSize = Size.Empty;
Edge = TaskBarEdge.Bottom;
Options = TaskBarOptions.KeepOnTop;
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: The taskbar for {DevicePath} is against the {Edge} edge, is positioned at ({Location.X},{Location.Y}) and is {Location.Width}x{Location.Height} in size.");
}
else
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
}
}
}
}
if (!foundDevicePath)
{
bool StuckRectVerFound = false;
// Check if string exists
version = 2;
address = string.Format(MainDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) != null)
{
StuckRectVerFound = true;
}
else
{
// If it's not version 2, then try version 3
version = 3;
address = string.Format(MainDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) != null)
{
StuckRectVerFound = true;
}
else
{
return;
}
}
if (StuckRectVerFound)
{
// Check if value exists
if (version >= 2 && version <= 3)
{
using (var key = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadSubTree))
{
var binary = key?.GetValue(devicePath) as byte[];
if (binary?.Length > 0)
{
foundDevicePath = true;
MainScreen = true;
DevicePath = devicePath;
Binary = binary;
Version = version;
// Extract the values from the binary byte field
PopulateFieldsFromBinary();
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: The taskbar for {DevicePath} is against the {Edge} edge, is positioned at ({Location.X},{Location.Y}) and is {Location.Width}x{Location.Height} in size.");
}
else
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
}
}
}
}
}
}
public TaskBarStuckRectangle()
{
}
public byte[] Binary { get; set; }
public byte[] BinaryBackup { get; set; }
public byte[] OriginalBinary { get; set; }
public string DevicePath { get; set; }
public bool MainScreen { get; set; }
[JsonIgnore]
public UInt32 DPI { get; set; }
public TaskBarEdge Edge { get; set; }
public Rectangle Location { get; set; }
public Size MinSize { get; set; }
public TaskBarOptions Options { get; set; }
public uint Rows { get; set; }
/*[JsonIgnore]
public UInt32 DPI
{
get
@ -125,9 +219,9 @@ namespace DisplayMagicianShared.Windows
var bytes = BitConverter.GetBytes(value);
Array.Copy(bytes, 0, Binary, 40, 4);
}
}
}*/
[JsonIgnore]
/*[JsonIgnore]
public TaskBarEdge Edge
{
get
@ -149,9 +243,9 @@ namespace DisplayMagicianShared.Windows
var bytes = BitConverter.GetBytes((uint)value);
Array.Copy(bytes, 0, Binary, 12, 4);
}
}
}*/
[JsonIgnore]
/*[JsonIgnore]
public Rectangle Location
{
get
@ -187,9 +281,9 @@ namespace DisplayMagicianShared.Windows
bytes = BitConverter.GetBytes(value.Bottom);
Array.Copy(bytes, 0, Binary, 36, 4);
}
}
}*/
[JsonIgnore]
/*[JsonIgnore]
public Size MinSize
{
get
@ -217,9 +311,9 @@ namespace DisplayMagicianShared.Windows
bytes = BitConverter.GetBytes(value.Height);
Array.Copy(bytes, 0, Binary, 20, 4);
}
}
}*/
[JsonIgnore]
/*[JsonIgnore]
public TaskBarOptions Options
{
get
@ -241,9 +335,9 @@ namespace DisplayMagicianShared.Windows
var bytes = BitConverter.GetBytes((uint)value);
Array.Copy(bytes, 0, Binary, 8, 4);
}
}
}*/
[JsonIgnore]
/*[JsonIgnore]
public uint Rows
{
get
@ -265,29 +359,28 @@ namespace DisplayMagicianShared.Windows
var bytes = BitConverter.GetBytes(value);
Array.Copy(bytes, 0, Binary, 44, 4);
}
}
}*/
public int Version { get; set; }
public override bool Equals(object obj) => obj is TaskBarStuckRectangle other && this.Equals(other);
public bool Equals(TaskBarStuckRectangle other)
{
// We return all the fields
return Version == other.Version &&
MainScreen == other.MainScreen &&
DevicePath == other.DevicePath &&
MainScreen == other.MainScreen &&
DPI == other.DPI &&
Edge == other.Edge &&
Location == other.Location;
// &&
//Xor(Binary, other.Binary);
Location == other.Location &&
MinSize == other.MinSize &&
Options == other.Options &&
Rows == other.Rows;
}
public override int GetHashCode()
{
//return (Version, MainScreen, DevicePath, Binary).GetHashCode();
return (Version, MainScreen, DevicePath, Edge, Location).GetHashCode();
return (Version, MainScreen, DevicePath, DPI, Edge, Location, MinSize, Options, Rows).GetHashCode();
}
public static bool operator ==(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => lhs.Equals(rhs);
@ -311,231 +404,217 @@ namespace DisplayMagicianShared.Windows
}
public static List<TaskBarStuckRectangle> GetCurrent(List<string> displayIdentifiers)
private bool PopulateFieldsFromBinary()
{
List<TaskBarStuckRectangle> taskBarStuckRectangles = new List<TaskBarStuckRectangle>();
int version = 2;
string address = "";
address = string.Format(MultiDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) == null)
// Now we decipher the binary properties features to populate the stuckrectangle
// DPI
if (Binary.Length < 44)
{
// If it's not version 2, then try version 3
version = 3;
address = string.Format(MultiDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) == null)
{
// It's not v2 or v3, so error
version = -1;
}
DPI = 0;
}
if (version >= 2)
else
{
foreach (string displayId in displayIdentifiers)
DPI = BitConverter.ToUInt32(Binary, 40);
}
// Edge
if (Binary.Length < 16)
{
Edge = TaskBarEdge.Bottom;
}
else
{
Edge = (TaskBarEdge)BitConverter.ToUInt32(Binary, 12);
}
// Location
if (Binary.Length < 40)
{
Location = Rectangle.Empty;
}
else
{
var left = BitConverter.ToInt32(Binary, 24);
var top = BitConverter.ToInt32(Binary, 28);
var right = BitConverter.ToInt32(Binary, 32);
var bottom = BitConverter.ToInt32(Binary, 36);
Location = Rectangle.FromLTRB(left, top, right, bottom);
}
// MinSize
if (Binary.Length < 24)
{
MinSize = Size.Empty;
}
else
{
var width = BitConverter.ToInt32(Binary, 16);
var height = BitConverter.ToInt32(Binary, 20);
MinSize = new Size(width, height);
}
// Options
if (Binary.Length < 12)
{
Options = 0;
}
else
{
Options = (TaskBarOptions)BitConverter.ToUInt32(Binary, 8);
}
// Rows
if (Binary.Length < 48)
{
Rows = 1;
}
else
{
Rows = BitConverter.ToUInt32(Binary, 44);
}
return true;
}
public bool PopulateBinaryFromFields()
{
// Set the DPI
if (Binary.Length < 44)
{
DPI = 0;
}
else
{
var bytes = BitConverter.GetBytes(DPI);
Array.Copy(bytes, 0, Binary, 40, 4);
}
// Edge
if (Binary.Length < 16)
{
Edge = TaskBarEdge.Bottom;
}
else
{
var bytes = BitConverter.GetBytes((uint)Edge);
Array.Copy(bytes, 0, Binary, 12, 4);
}
// Location
if (Binary.Length < 40)
{
var bytes = BitConverter.GetBytes(0);
Array.Copy(bytes, 0, Binary, 24, 4);
bytes = BitConverter.GetBytes(0);
Array.Copy(bytes, 0, Binary, 28, 4);
bytes = BitConverter.GetBytes(0);
Array.Copy(bytes, 0, Binary, 32, 4);
bytes = BitConverter.GetBytes(0);
Array.Copy(bytes, 0, Binary, 36, 4);
}
else
{
var bytes = BitConverter.GetBytes(Location.Left);
Array.Copy(bytes, 0, Binary, 24, 4);
bytes = BitConverter.GetBytes(Location.Top);
Array.Copy(bytes, 0, Binary, 28, 4);
bytes = BitConverter.GetBytes(Location.Right);
Array.Copy(bytes, 0, Binary, 32, 4);
bytes = BitConverter.GetBytes(Location.Bottom);
Array.Copy(bytes, 0, Binary, 36, 4);
}
// MinSize
if (Binary.Length < 24)
{
var bytes = BitConverter.GetBytes(0);
Array.Copy(bytes, 0, Binary, 16, 4);
bytes = BitConverter.GetBytes(0);
Array.Copy(bytes, 0, Binary, 20, 4);
}
else
{
var bytes = BitConverter.GetBytes(MinSize.Width);
Array.Copy(bytes, 0, Binary, 16, 4);
bytes = BitConverter.GetBytes(MinSize.Height);
Array.Copy(bytes, 0, Binary, 20, 4);
}
// Options
if (Binary.Length < 12)
{
var bytes = BitConverter.GetBytes((uint)0);
Array.Copy(bytes, 0, Binary, 8, 4);
}
else
{
var bytes = BitConverter.GetBytes((uint)Options);
Array.Copy(bytes, 0, Binary, 8, 4);
}
// Rows
if (Binary.Length < 48)
{
var bytes = BitConverter.GetBytes(1);
Array.Copy(bytes, 0, Binary, 44, 4);
}
else
{
var bytes = BitConverter.GetBytes(Rows);
Array.Copy(bytes, 0, Binary, 44, 4);
}
return true;
}
public bool WriteToRegistry()
{
// Update the binary with the current settings from the object
PopulateBinaryFromFields();
// Write the binary field to registry
string address;
if (MainScreen)
{
address = string.Format(MainDisplayAddress, Version);
// Set the Main Screen
try
{
// e.g. "WINAPI|\\\\?\\PCI#VEN_10DE&DEV_2482&SUBSYS_408E1458&REV_A1#4&2283f625&0&0019#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}|DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI|54074|4318|\\\\?\\DISPLAY#NVS10DE#5&2b46c695&0&UID185344#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}|NV Surround"
string[] winapiLine = displayId.Split('|');
string pattern = @"DISPLAY\#(.*)\#\{";
Match match = Regex.Match(winapiLine[5], pattern);
if (match.Success)
using (var key = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
TaskBarStuckRectangle taskBarStuckRectangle = new TaskBarStuckRectangle();
string tbStuckRectKey = match.Groups[1].Value;
using (var key = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadSubTree))
{
var settings = key?.GetValue(tbStuckRectKey) as byte[];
if (settings?.Length > 0)
{
taskBarStuckRectangle = new TaskBarStuckRectangle
{
MainScreen = false,
DevicePath = tbStuckRectKey,
Binary = settings,
BinaryBackup = settings,
Version = version
};
taskBarStuckRectangles.Add(taskBarStuckRectangle);
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: The taskbar for {taskBarStuckRectangle.DevicePath} is against the {taskBarStuckRectangle.Edge} edge, is positioned at ({taskBarStuckRectangle.Location.X},{taskBarStuckRectangle.Location.Y}) and is {taskBarStuckRectangle.Location.Width}x{taskBarStuckRectangle.Location.Height} in size.");
}
else
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Unable to get the TaskBarStuckRectangle for {displayId}.");
}
}
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: We were unable to figure out the DevicePath for the '{displayId}' display identifier.");
key.SetValue(DevicePath, Binary);
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
}
}
}
version = 2;
address = string.Format(MainDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) == null)
{
// If it's not version 2, then try version 3
version = 3;
address = string.Format(MainDisplayAddress, version);
if (Registry.CurrentUser.OpenSubKey(address) == null)
catch (Exception ex)
{
// It's not v2 or v3, so error
version = -1;
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
}
}
if (version >= 2)
else
{
address = string.Format(MultiDisplayAddress, Version);
// Grab the main screen taskbar placement
try
{
using (var key = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadSubTree))
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
var settings = key?.GetValue("Settings") as byte[];
if (settings?.Length > 0)
{
TaskBarStuckRectangle taskBarStuckRectangle = new TaskBarStuckRectangle
{
MainScreen = true,
DevicePath = "Settings",
Binary = settings,
BinaryBackup = settings,
Version = version
};
taskBarStuckRectangles.Add(taskBarStuckRectangle);
}
key.SetValue(DevicePath, Binary);
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
}
}
catch (Exception ex)
{
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to read the Main Screen TaskBarStuckRectangle registry settings due to an exception!");
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
}
}
return taskBarStuckRectangles;
}
public static bool ForceTaskBarIfNeeded(ref List<TaskBarStuckRectangle> taskBarStuckRectangles, TaskBarForcedEdge forcedEdge = TaskBarForcedEdge.None)
{
try
{
if (forcedEdge != TaskBarForcedEdge.None)
{
for (int i = 0; i < taskBarStuckRectangles.Count; i++)
{
// Force the taskbar change
taskBarStuckRectangles[i].Edge = (TaskBarEdge)forcedEdge;
taskBarStuckRectangles[i].Location = Rectangle.Empty;
}
}
else if (forcedEdge == TaskBarForcedEdge.None)
{
// Revert the forced taskbar change from the backup
for (int i = 0; i < taskBarStuckRectangles.Count; i++)
{
taskBarStuckRectangles[i].Binary = taskBarStuckRectangles[i].BinaryBackup;
}
}
return true;
}
catch (Exception ex)
{
return false;
}
}
public static bool Apply(List<TaskBarStuckRectangle> taskBarStuckRectangles, TaskBarForcedEdge forcedEdge = TaskBarForcedEdge.None)
{
string address;
if (taskBarStuckRectangles.Count < 1)
{
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: There are no TaskBarStuckRectangle registry settings to apply! This taskbar configuration is invalid.");
return false;
}
foreach (TaskBarStuckRectangle tbsr in taskBarStuckRectangles)
{
if (tbsr.Version >= 2 && tbsr.Version <= 3)
{
if (!tbsr.MainScreen)
{
address = string.Format(MultiDisplayAddress, tbsr.Version);
// Grab the main screen taskbar placement
try
{
using (var key = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
key.SetValue(tbsr.DevicePath, tbsr.Binary);
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {tbsr.DevicePath} Screen!");
}
}
catch (Exception ex)
{
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {tbsr.DevicePath} TaskBarStuckRectangle registry settings due to an exception!");
}
}
}
else
{
SharedLogger.logger.Error($"TaskBarStuckRectangle/GetCurrent: Unable to set the {tbsr.DevicePath} TaskBarStuckRectangle registry settings as the version isn't v2 or v3!");
}
}
// Tell Windows to refresh the Windows Taskbar (which will only refresh the non-main screen)
Utils.SendNotifyMessage((IntPtr)Utils.HWND_BROADCAST, Utils.WM_SETTINGCHANGE, (UIntPtr)Utils.NULL, "TraySettings");
foreach (TaskBarStuckRectangle tbsr in taskBarStuckRectangles)
{
if (tbsr.Version >= 2 && tbsr.Version <= 3)
{
if (tbsr.MainScreen)
{
address = string.Format(MainDisplayAddress, tbsr.Version);
// Grab the main screen taskbar placement
try
{
using (var key2 = Registry.CurrentUser.OpenSubKey(
address,
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
key2.SetValue("Settings", tbsr.Binary);
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the Main Screen!");
}
}
catch (Exception ex)
{
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the Main Screen TaskBarStuckRectangle registry settings due to an exception!");
}
}
}
else
{
SharedLogger.logger.Error($"TaskBarStuckRectangle/GetCurrent: Unable to set the Main Screen TaskBarStuckRectangle registry settings as the version isn't v2 or v3!");
}
}
// Tell Windows to refresh the Windows Taskbar (which will only refresh the non-main screen)
Utils.SendNotifyMessage((IntPtr)Utils.HWND_BROADCAST, Utils.WM_SETTINGCHANGE, (UIntPtr)Utils.NULL, "TraySettings");
Task.Delay(2000);
// This will refresh the main screen as well. No idea why the above notification doesn't update the main screen too :/)
//RestartManagerSession.RestartExplorer();
return true;
}
}
}

View File

@ -7,9 +7,22 @@ using System.Text.RegularExpressions;
using DisplayMagicianShared;
using System.IO;
using System.ComponentModel;
using Microsoft.Win32;
using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows
{
public enum TaskBarForcedEdge : UInt32
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3,
None = 9999
}
[StructLayout(LayoutKind.Sequential)]
public struct ADVANCED_HDR_INFO_PER_PATH : IEquatable<ADVANCED_HDR_INFO_PER_PATH>
{
@ -43,6 +56,9 @@ namespace DisplayMagicianShared.Windows
public List<ADVANCED_HDR_INFO_PER_PATH> DisplayHDRStates;
public Dictionary<string, GDI_DISPLAY_SETTING> GdiDisplaySettings;
public List<TaskBarStuckRectangle> TaskBarLayout;
public List<TaskBarStuckRectangle> OriginalTaskBarLayout;
public TaskBarForcedEdge TaskBarForcedEdge;
public TaskBarSettings TaskBarSettings;
public bool IsCloned;
// Note: We purposely have left out the DisplaySources from the Equals as it's order keeps changing after each reboot and after each profile swap
@ -63,11 +79,12 @@ namespace DisplayMagicianShared.Windows
GdiDisplaySettings.Values.SequenceEqual(other.GdiDisplaySettings.Values) &&
DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers) &&
TaskBarLayout.SequenceEqual(other.TaskBarLayout) &&
TaskBarForcedEdge == other.TaskBarForcedEdge &&
TaskBarSettings.Equals(other.TaskBarSettings);
public override int GetHashCode()
{
return (DisplayConfigPaths, DisplayConfigModes, DisplayHDRStates, IsCloned, DisplayIdentifiers, TaskBarLayout, TaskBarSettings).GetHashCode();
return (DisplayConfigPaths, DisplayConfigModes, DisplayHDRStates, IsCloned, DisplayIdentifiers, TaskBarLayout, TaskBarForcedEdge, TaskBarSettings).GetHashCode();
}
public static bool operator ==(WINDOWS_DISPLAY_CONFIG lhs, WINDOWS_DISPLAY_CONFIG rhs) => lhs.Equals(rhs);
@ -170,7 +187,9 @@ namespace DisplayMagicianShared.Windows
myDefaultConfig.DisplaySources = new Dictionary<string, List<uint>>();
myDefaultConfig.GdiDisplaySettings = new Dictionary<string, GDI_DISPLAY_SETTING>();
myDefaultConfig.TaskBarLayout = new List<TaskBarStuckRectangle>();
myDefaultConfig.OriginalTaskBarLayout = new List<TaskBarStuckRectangle>();
myDefaultConfig.TaskBarSettings = new TaskBarSettings();
myDefaultConfig.TaskBarForcedEdge = TaskBarForcedEdge.None;
myDefaultConfig.IsCloned = false;
return myDefaultConfig;
@ -602,7 +621,28 @@ namespace DisplayMagicianShared.Windows
// Now attempt to get the windows taskbar location for each display
// We use the information we already got from the display identifiers
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get the Windows Taskbar layout.");
List<TaskBarStuckRectangle> taskBarStuckRectangles = TaskBarStuckRectangle.GetCurrent(windowsDisplayConfig.DisplayIdentifiers);
List<TaskBarStuckRectangle> taskBarStuckRectangles = new List<TaskBarStuckRectangle>();
foreach (var displayId in windowsDisplayConfig.DisplayIdentifiers)
{
// e.g. "WINAPI|\\\\?\\PCI#VEN_10DE&DEV_2482&SUBSYS_408E1458&REV_A1#4&2283f625&0&0019#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}|DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI|54074|4318|\\\\?\\DISPLAY#NVS10DE#5&2b46c695&0&UID185344#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}|NV Surround"
string[] winapiLine = displayId.Split('|');
string pattern = @"DISPLAY\#(.*)\#\{";
Match match = Regex.Match(winapiLine[5], pattern);
if (match.Success)
{
string devicePath = match.Groups[1].Value;
TaskBarStuckRectangle taskBarStuckRectangle = new TaskBarStuckRectangle(devicePath);
taskBarStuckRectangles.Add(taskBarStuckRectangle);
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: We were unable to figure out the DevicePath for the '{displayId}' display identifier.");
}
}
// And we get the Main Screen taskbar too
TaskBarStuckRectangle mainTaskBarStuckRectangle = new TaskBarStuckRectangle("Settings");
taskBarStuckRectangles.Add(mainTaskBarStuckRectangle);
// Now we try to get the taskbar settings too
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get the Windows Taskbar settings.");
@ -1341,17 +1381,26 @@ namespace DisplayMagicianShared.Windows
if (displayConfig.TaskBarLayout.Count > 0)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Setting the taskbar layout.");
if (TaskBarStuckRectangle.Apply(displayConfig.TaskBarLayout))
foreach (TaskBarStuckRectangle tbsr in displayConfig.TaskBarLayout)
{
// TODO - We need to detect if it is Windows 11, as we need to restart explorer.exe for the settings to take
// No need to do it in Windows 10, as explorere auto-detects the registry key change, and moves the taskbar
// (In fact, if you try to restart explorer.exe on Win10 it actually stops the taskbar move from working!)
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Set the taskbar layout successfully.");
}
else
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Unable to set the taskbar layout.");
if (tbsr.Version >= 2 && tbsr.Version <= 3)
{
tbsr.WriteToRegistry();
}
else
{
SharedLogger.logger.Error($"WinLibrary/GetCurrent: Unable to set the {tbsr.DevicePath} TaskBarStuckRectangle registry settings as the version isn't v2 or v3!");
}
}
// Tell Windows to refresh the Windows Taskbar (which will only refresh the non-main screen)
Utils.SendNotifyMessage((IntPtr)Utils.HWND_BROADCAST, Utils.WM_SETTINGCHANGE, (UIntPtr)Utils.NULL, "TraySettings");
Task.Delay(2000);
// This will refresh the main screen as well. No idea why the above notification doesn't update the main screen too :/)
//RestartManagerSession.RestartExplorer();
}
else
{

View File

@ -629,6 +629,7 @@ namespace DisplayMagician.UIForms
// otherwise we'll save it only when the user wants to save this profile.
if (_saveOrRenameMode == "rename" && profileSettingsForm.ProfileSettingChanged)
{
//_selectedProfile = profileSettingsForm.Profile;
ProfileRepository.SaveProfiles();
}
}