mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
Updated the NVIDIALibrary and WinLibrary to v1.7.0
This is the version used within NVIDIAInfo v1.7.0
This commit is contained in:
parent
1f6af1f0c7
commit
67c1015730
@ -601,6 +601,12 @@ namespace DisplayMagician.Processes
|
||||
{
|
||||
if (ex.ErrorCode == -2147467259)
|
||||
{
|
||||
if (runAsAdministrator)
|
||||
{
|
||||
logger.Error(ex, $"ProcessUtils/TryExecute: Exception while trying to start {executable} for a second time with administrative rights. Giving up.");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.Error(ex, $"ProcessUtils/TryExecute: Exception while trying to start {executable}. The process requires elevation. Attempting again with admin rights.");
|
||||
if (TryExecute(executable, arguments, out processCreated, true, priorityClass, maxWaitMs))
|
||||
{
|
||||
|
@ -26,8 +26,8 @@ using System.Resources;
|
||||
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
|
||||
|
||||
// Version information
|
||||
[assembly: AssemblyVersion("2.2.0.250")]
|
||||
[assembly: AssemblyFileVersion("2.2.0.250")]
|
||||
[assembly: AssemblyVersion("2.2.0.251")]
|
||||
[assembly: AssemblyFileVersion("2.2.0.251")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en" )]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<Compile Include="Utils.cs" />
|
||||
<Compile Include="Windows\TaskBarSettings.cs" />
|
||||
<Compile Include="Windows\TaskBarLayout.cs" />
|
||||
<Compile Include="Windows\TaskBarStuckRectangle.cs" />
|
||||
<Compile Include="UserControls\DisplayView.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -839,43 +839,7 @@ namespace DisplayMagicianShared
|
||||
// We do the actual change we were trying to do
|
||||
try
|
||||
{
|
||||
|
||||
// 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 missing Windows Taskbar layout.");
|
||||
// Create a default object (an empty list)
|
||||
List<TaskBarStuckRectangle> taskBarStuckRectangles = new List<TaskBarStuckRectangle>();
|
||||
for (int i = 0; i < root.Count; i++)
|
||||
{
|
||||
JObject profile = (JObject)root[i];
|
||||
JArray WindowsTaskBarLayout = (JArray)profile.SelectToken("WindowsDisplayConfig.TaskBarLayout");
|
||||
if (WindowsTaskBarLayout == null)
|
||||
{
|
||||
JObject WindowsDisplayConfig = (JObject)profile.SelectToken("WindowsDisplayConfig");
|
||||
JArray newTaskBarLayout = JArray.FromObject(taskBarStuckRectangles);
|
||||
WindowsDisplayConfig.Add("TaskBarLayout",newTaskBarLayout);
|
||||
changedJson = true;
|
||||
SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Patched missing Windows TaskBarLayout in profile {profile.SelectToken("Name")} (index {i}).");
|
||||
}
|
||||
}
|
||||
|
||||
// Now we try to patch in a Windows Taskbar Settings list into the json if there isnt one
|
||||
SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Looking for missing Windows Taskbar settings.");
|
||||
// Create a default object using whatever the taskbar settings are right now
|
||||
// (We're assuming the user keeps these settings standard)
|
||||
TaskBarSettings taskBarSettings = TaskBarSettings.GetCurrent();
|
||||
for (int i = 0; i < root.Count; i++)
|
||||
{
|
||||
JObject profile = (JObject)root[i];
|
||||
JObject WindowsTaskBarSettings = (JObject)profile.SelectToken("WindowsDisplayConfig.TaskBarSettings");
|
||||
if (WindowsTaskBarSettings == null)
|
||||
{
|
||||
JObject WindowsDisplayConfig = (JObject)profile.SelectToken("WindowsDisplayConfig");
|
||||
JObject newTaskBarSettings = JObject.FromObject(taskBarSettings);
|
||||
WindowsDisplayConfig.Add("TaskBarSettings", newTaskBarSettings);
|
||||
changedJson = true;
|
||||
SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Patched missing Windows TaskBarSettings in profile {profile.SelectToken("Name")} (index {i}).");
|
||||
}
|
||||
}
|
||||
// Nothing to patch at the moment!
|
||||
}
|
||||
catch (JsonReaderException ex)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
@ -8,17 +9,188 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace DisplayMagicianShared
|
||||
{
|
||||
class Utils
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
|
||||
public struct WINDOWPOS
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public IntPtr hWnd;
|
||||
public IntPtr hwndInsertAfter;
|
||||
public int x;
|
||||
public int y;
|
||||
public int cx;
|
||||
public int cy;
|
||||
public SET_WINDOW_POSITION_FLAGS flags;
|
||||
|
||||
// Returns the WINDOWPOS structure pointed to by the lParam parameter
|
||||
// of a WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED message.
|
||||
public static WINDOWPOS FromMessage(IntPtr lParam)
|
||||
{
|
||||
// Marshal the lParam parameter to an WINDOWPOS structure,
|
||||
// and return the new structure
|
||||
return (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
|
||||
}
|
||||
|
||||
// Replaces the original WINDOWPOS structure pointed to by the lParam
|
||||
// parameter of a WM_WINDOWPOSCHANGING or WM_WINDOWPSCHANGING message
|
||||
// with this one, so that the native window will be able to see any
|
||||
// changes that we have made to its values.
|
||||
public void UpdateMessage(IntPtr lParam)
|
||||
{
|
||||
// Marshal this updated structure back to lParam so the native
|
||||
// window can respond to our changes.
|
||||
// The old structure that it points to should be deleted, too.
|
||||
Marshal.StructureToPtr(this, lParam, true);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
|
||||
public struct RECT
|
||||
{
|
||||
public int left;
|
||||
public int top;
|
||||
public int right;
|
||||
public int bottom;
|
||||
public Int32 left;
|
||||
public Int32 top;
|
||||
public Int32 right;
|
||||
public Int32 bottom;
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 8)]
|
||||
public struct APPBARDATA
|
||||
{
|
||||
public int cbSize;
|
||||
public IntPtr hWnd;
|
||||
public uint uCallbackMessage;
|
||||
public ABEDGE uEdge;
|
||||
public RECT rc;
|
||||
public int lParam;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The MONITORINFOEX structure contains information about a display monitor.
|
||||
/// The GetMonitorInfo function stores information into a MONITORINFOEX structure or a MONITORINFO structure.
|
||||
/// The MONITORINFOEX structure is a superset of the MONITORINFO structure. The MONITORINFOEX structure adds a string member to contain a name
|
||||
/// for the display monitor.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
|
||||
public struct MONITORINFOEX
|
||||
{
|
||||
/// <summary>
|
||||
/// The size, in bytes, of the structure. Set this member to sizeof(MONITORINFOEX) (72) before calling the GetMonitorInfo function.
|
||||
/// Doing so lets the function determine the type of structure you are passing to it.
|
||||
/// </summary>
|
||||
public UInt32 cbSize;
|
||||
|
||||
/// <summary>
|
||||
/// A RECT structure that specifies the display monitor rectangle, expressed in virtual-screen coordinates.
|
||||
/// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
|
||||
/// </summary>
|
||||
public RECT rcMonitor;
|
||||
|
||||
/// <summary>
|
||||
/// A RECT structure that specifies the work area rectangle of the display monitor that can be used by applications,
|
||||
/// expressed in virtual-screen coordinates. Windows uses this rectangle to maximize an application on the monitor.
|
||||
/// The rest of the area in rcMonitor contains system windows such as the task bar and side bars.
|
||||
/// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
|
||||
/// </summary>
|
||||
public RECT rcWork;
|
||||
|
||||
/// <summary>
|
||||
/// The attributes of the display monitor.
|
||||
///
|
||||
/// This member can be the following value:
|
||||
/// 1 : MONITORINFOF_PRIMARY
|
||||
/// </summary>
|
||||
public UInt32 dwFlags;
|
||||
|
||||
/// <summary>
|
||||
/// A string that specifies the device name of the monitor being used. Most applications have no use for a display monitor name,
|
||||
/// and so can save some bytes by using a MONITORINFO structure.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Utils.CCHDEVICENAME)]
|
||||
public string szDevice;
|
||||
|
||||
/*public void Init()
|
||||
{
|
||||
this.cbSize = 40 + 2 * Utils.CCHDEVICENAME;
|
||||
this.DeviceName = string.Empty;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The MONITORINFO structure contains information about a display monitor.
|
||||
/// The GetMonitorInfo function stores information into a MONITORINFOEX structure or a MONITORINFO structure.
|
||||
/// The MONITORINFOEX structure is a superset of the MONITORINFO structure. The MONITORINFOEX structure adds a string member to contain a name
|
||||
/// for the display monitor.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
|
||||
public struct MONITORINFO
|
||||
{
|
||||
/// <summary>
|
||||
/// The size, in bytes, of the structure. Set this member to sizeof(MONITORINFOEX) (72) before calling the GetMonitorInfo function.
|
||||
/// Doing so lets the function determine the type of structure you are passing to it.
|
||||
/// </summary>
|
||||
public UInt32 cbSize;
|
||||
|
||||
/// <summary>
|
||||
/// A RECT structure that specifies the display monitor rectangle, expressed in virtual-screen coordinates.
|
||||
/// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
|
||||
/// </summary>
|
||||
public RECT rcMonitor;
|
||||
|
||||
/// <summary>
|
||||
/// A RECT structure that specifies the work area rectangle of the display monitor that can be used by applications,
|
||||
/// expressed in virtual-screen coordinates. Windows uses this rectangle to maximize an application on the monitor.
|
||||
/// The rest of the area in rcMonitor contains system windows such as the task bar and side bars.
|
||||
/// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
|
||||
/// </summary>
|
||||
public RECT rcWork;
|
||||
|
||||
/// <summary>
|
||||
/// The attributes of the display monitor.
|
||||
///
|
||||
/// This member can be the following value:
|
||||
/// 1 : MONITORINFOF_PRIMARY
|
||||
/// </summary>
|
||||
public UInt32 dwFlags;
|
||||
|
||||
/*public void Init()
|
||||
{
|
||||
this.cbSize = 40 + 2 * Utils.CCHDEVICENAME;
|
||||
this.DeviceName = string.Empty;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
[Flags]
|
||||
public enum SET_WINDOW_POSITION_FLAGS : UInt32
|
||||
{
|
||||
SWP_ASYNCWINDOWPOS = 0x4000,
|
||||
SWP_DEFERERASE = 0x2000,
|
||||
SWP_DRAWFRAME = 0x0020,
|
||||
SWP_FRAMECHANGED = 0x0020,
|
||||
SWP_HIDEWINDOW = 0x0080,
|
||||
SWP_NOACTIVATE = 0x0010,
|
||||
SWP_NOCOPYBITS = 0x0100,
|
||||
SWP_NOMOVE = 0x0002,
|
||||
SWP_NOOWNERZORDER = 0x0200,
|
||||
SWP_NOREDRAW = 0x0008,
|
||||
SWP_NOREPOSITION = 0x0200,
|
||||
SWP_NOSENDCHANGING = 0x0400,
|
||||
SWP_NOSIZE = 0x0001,
|
||||
SWP_NOZORDER = 0x0004,
|
||||
SWP_SHOWWINDOW = 0x0040,
|
||||
}
|
||||
|
||||
public enum SET_WINDOW_POSITION_ZORDER : Int32
|
||||
{
|
||||
HWND_TOP = 0,
|
||||
HWND_BOTTOM = 1,
|
||||
HWND_TOPMOST = -1,
|
||||
HWND_NOTOPMOST = -2,
|
||||
}
|
||||
|
||||
|
||||
[Flags]
|
||||
public enum SendMessageTimeoutFlag : uint
|
||||
{
|
||||
@ -29,6 +201,68 @@ namespace DisplayMagicianShared
|
||||
SMTO_ERRORONEXIT = 0x20
|
||||
}
|
||||
|
||||
public enum ABEDGE : UInt32
|
||||
{
|
||||
ABE_LEFT = 0x0,
|
||||
ABE_TOP = 0x1,
|
||||
ABE_RIGHT = 0x2,
|
||||
ABE_BOTTOM = 0x3,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum MOUSEKEYS : UInt32
|
||||
{
|
||||
MK_LBUTTON = 0x1,
|
||||
MK_RBUTTON = 0x2,
|
||||
MK_SHIFT = 0x4,
|
||||
MK_CONTROL = 0x8,
|
||||
MK_MBUTTON = 0x10,
|
||||
MK_XBUTTON1 = 0x20,
|
||||
MK_XBUTTON2 = 0x40,
|
||||
}
|
||||
|
||||
|
||||
enum SYSCOMMAND : int
|
||||
{
|
||||
SC_SIZE = 0xF000,
|
||||
SC_MOVE = 0xF010,
|
||||
SC_MINIMIZE = 0xF020,
|
||||
SC_MAXIMIZE = 0xF030,
|
||||
SC_NEXTWINDOW = 0xF040,
|
||||
SC_PREVWINDOW = 0xF050,
|
||||
SC_CLOSE = 0xF060,
|
||||
SC_VSCROLL = 0xF070,
|
||||
SC_HSCROLL = 0xF080,
|
||||
SC_MOUSEMENU = 0xF090,
|
||||
SC_KEYMENU = 0xF100,
|
||||
SC_ARRANGE = 0xF110,
|
||||
SC_RESTORE = 0xF120,
|
||||
SC_TASKLIST = 0xF130,
|
||||
SC_SCREENSAVE = 0xF140,
|
||||
SC_HOTKEY = 0xF150,
|
||||
//#if(WINVER >= 0x0400) //Win95
|
||||
SC_DEFAULT = 0xF160,
|
||||
SC_MONITORPOWER = 0xF170,
|
||||
SC_CONTEXTHELP = 0xF180,
|
||||
SC_SEPARATOR = 0xF00F,
|
||||
//#endif /* WINVER >= 0x0400 */
|
||||
|
||||
//#if(WINVER >= 0x0600) //Vista
|
||||
SCF_ISSECURE = 0x00000001,
|
||||
//#endif /* WINVER >= 0x0600 */
|
||||
|
||||
/*
|
||||
* Obsolete names
|
||||
*/
|
||||
SC_ICON = SC_MINIMIZE,
|
||||
SC_ZOOM = SC_MAXIMIZE,
|
||||
}
|
||||
|
||||
|
||||
class Utils
|
||||
{
|
||||
|
||||
|
||||
#region enum HChangeNotifyEventID
|
||||
/// <summary>
|
||||
/// Describes the event that has occurred.
|
||||
@ -302,15 +536,39 @@ namespace DisplayMagicianShared
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, Int16 wParam, Int16 lParam);
|
||||
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
|
||||
|
||||
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
|
||||
HChangeNotifyFlags uFlags,
|
||||
IntPtr dwItem1,
|
||||
IntPtr dwItem2);
|
||||
|
||||
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern int SHAppBarMessage(uint dwMessage, ref APPBARDATA pData);
|
||||
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
|
||||
@ -318,6 +576,44 @@ namespace DisplayMagicianShared
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, SET_WINDOW_POSITION_ZORDER hWndInsertAfter, int x, int y, int cx, int cy, SET_WINDOW_POSITION_FLAGS uFlags);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
private static extern int ShowWindow(IntPtr hwnd, int command);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The MoveWindow function changes the position and dimensions of the specified window. For a top-level window, the
|
||||
/// position and dimensions are relative to the upper-left corner of the screen. For a child window, they are relative
|
||||
/// to the upper-left corner of the parent window's client area.
|
||||
/// <para>
|
||||
/// Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633534%28v=vs.85%29.aspx for more
|
||||
/// information
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="hWnd">C++ ( hWnd [in]. Type: HWND )<br /> Handle to the window.</param>
|
||||
/// <param name="X">C++ ( X [in]. Type: int )<br />Specifies the new position of the left side of the window.</param>
|
||||
/// <param name="Y">C++ ( Y [in]. Type: int )<br /> Specifies the new position of the top of the window.</param>
|
||||
/// <param name="nWidth">C++ ( nWidth [in]. Type: int )<br />Specifies the new width of the window.</param>
|
||||
/// <param name="nHeight">C++ ( nHeight [in]. Type: int )<br />Specifies the new height of the window.</param>
|
||||
/// <param name="bRepaint">
|
||||
/// C++ ( bRepaint [in]. Type: bool )<br />Specifies whether the window is to be repainted. If this
|
||||
/// parameter is TRUE, the window receives a message. If the parameter is FALSE, no repainting of any kind occurs. This
|
||||
/// applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the
|
||||
/// parent window uncovered as a result of moving a child window.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero.<br /> If the function fails, the return value is zero.
|
||||
/// <br />To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
|
||||
|
||||
public static bool IsWindows11()
|
||||
{
|
||||
var reg = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
|
||||
@ -333,6 +629,36 @@ namespace DisplayMagicianShared
|
||||
return ((p_2 << 16) | (p & 0xFFFF));
|
||||
}
|
||||
|
||||
internal delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
|
||||
|
||||
public static List<MONITORINFOEX> EnumMonitors()
|
||||
{
|
||||
List<MONITORINFOEX> monitors = new List<MONITORINFOEX>();
|
||||
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
|
||||
delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
|
||||
{
|
||||
MONITORINFOEX mi = new MONITORINFOEX();
|
||||
mi.cbSize = (uint)Marshal.SizeOf(mi);
|
||||
bool success = GetMonitorInfo(hMonitor, ref mi);
|
||||
if (success)
|
||||
{
|
||||
monitors.Add(mi);
|
||||
}
|
||||
return true;
|
||||
}, IntPtr.Zero);
|
||||
return monitors;
|
||||
}
|
||||
|
||||
private static bool MonitorEnumCallBack(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
|
||||
{
|
||||
MONITORINFOEX mon_info = new MONITORINFOEX();
|
||||
mon_info.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
|
||||
//mon_info.szDevice = new char[Utils.CCHDEVICENAME];
|
||||
GetMonitorInfo(hMonitor, ref mon_info);
|
||||
///Monitor info is stored in 'mon_info'
|
||||
return true;
|
||||
}
|
||||
|
||||
/*public static bool RefreshNotificationTray()
|
||||
{
|
||||
Utils.SHChangeNotify(Utils.HChangeNotifyEventID.SHCNE_ASSOCCHANGED, Utils.HChangeNotifyFlags.SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
|
||||
@ -344,13 +670,84 @@ namespace DisplayMagicianShared
|
||||
return true;
|
||||
}*/
|
||||
|
||||
public static Point PointFromLParam(IntPtr lParam)
|
||||
{
|
||||
return new Point((int)(lParam) & 0xFFFF, ((int)(lParam) >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
public static IntPtr LParamFromPoint(Point point)
|
||||
{
|
||||
return (IntPtr)((point.Y << 16) | (point.X & 0xFFFF));
|
||||
}
|
||||
|
||||
public static IntPtr LParamFromPoint(int x, int y)
|
||||
{
|
||||
return (IntPtr)((y << 16) | (x & 0xFFFF));
|
||||
}
|
||||
|
||||
|
||||
public const int NULL = 0;
|
||||
public const int HWND_BROADCAST = 0xffff;
|
||||
public const int WM_ENTERSIZEMOVE = 0x0231;
|
||||
public const int WM_EXITSIZEMOVE = 0x0232;
|
||||
public const int WM_WINDOWPOSCHANGING = 0x0046;
|
||||
public const int WM_WINDOWPOSCHANGED = 0x0047;
|
||||
public const int WM_SYSCOMMAND = 0x112;
|
||||
public const int WM_NOTIFY = 0xA005;
|
||||
public const int WM_SETTINGCHANGE = 0x001a;
|
||||
public const int WM_THEMECHANGED = 0x031a;
|
||||
public const int WM_MOUSEMOVE = 0x0200;
|
||||
public const int SPI_SETWORKAREA = 0x002F;
|
||||
public const int SHELLHOOK = 0xC028;
|
||||
public const int WM_USER_REFRESHTASKBAR = 0x05CA;
|
||||
public const int WM_USER_451 = 0x05C3;
|
||||
public const int WM_USER_440 = 0x05B8;
|
||||
public const int WM_USER_336 = 0x0550;
|
||||
public const int WM_USER_92 = 0x045C;
|
||||
public const int WM_USER_7 = 0x0407;
|
||||
public const int WM_USER_1 = 0x0401;
|
||||
public const int WM_USER_100 = 0x0464;
|
||||
public const int WM_USER_13 = 0x040D;
|
||||
public const int wParam_SHELLTRAY = 0x00000006;
|
||||
|
||||
public const int ABM_NEW = 0x00000000;
|
||||
public const int ABM_REMOVE = 0x00000001;
|
||||
public const int ABM_QUERYPOS = 0x00000002;
|
||||
public const int ABM_SETPOS = 0x00000003;
|
||||
public const int ABM_GETSTATE = 0x00000004;
|
||||
public const int ABM_GETTASKBARPOS = 0x00000005;
|
||||
public const int ABM_ACTIVATE = 0x00000006; // lParam == TRUE/FALSE means activate/deactivate
|
||||
public const int ABM_GETAUTOHIDEBAR = 0x00000007;
|
||||
public const int ABM_SETAUTOHIDEBAR = 0x00000008; // this can fail at any time. MUST check the result
|
||||
// lParam = TRUE/FALSE Set/Unset
|
||||
// uEdge = what edge
|
||||
public const int ABM_WINDOWPOSCHANGED = 0x0000009;
|
||||
public const int ABM_SETSTATE = 0x0000000a;
|
||||
|
||||
// these are put in the wparam of callback messages
|
||||
public const int ABN_STATECHANGE = 0x0000000;
|
||||
public const int ABN_POSCHANGED = 0x0000001;
|
||||
public const int ABN_FULLSCREENAPP = 0x0000002;
|
||||
public const int ABN_WINDOWARRANGE = 0x0000003; // lParam == TRUE means hide
|
||||
|
||||
// flags for get state
|
||||
public const int ABS_AUTOHIDE = 0x0000001;
|
||||
public const int ABS_ALWAYSONTOP = 0x0000002;
|
||||
|
||||
public const int ABE_LEFT = 0;
|
||||
public const int ABE_TOP = 1;
|
||||
public const int ABE_RIGHT = 2;
|
||||
public const int ABE_BOTTOM = 3;
|
||||
|
||||
public const int MONITOR_DEFAULTTONULL = 0;
|
||||
public const int MONITOR_DEFAULTTOPRIMARY = 1;
|
||||
public const int MONITOR_DEFAULTTONEAREST = 2;
|
||||
|
||||
// size of a device name string
|
||||
public const int CCHDEVICENAME = 32;
|
||||
public const uint MONITORINFOF_PRIMARY = 1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
namespace DisplayMagicianShared.Windows
|
||||
{
|
||||
|
||||
public enum WIN32STATUS : uint
|
||||
public enum WIN32STATUS : UInt32
|
||||
{
|
||||
ERROR_SUCCESS = 0,
|
||||
ERROR_ACCESS_DENIED = 5,
|
||||
@ -19,24 +19,29 @@ namespace DisplayMagicianShared.Windows
|
||||
ERROR_BAD_CONFIGURATION = 1610,
|
||||
}
|
||||
|
||||
public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
|
||||
public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : UInt32
|
||||
{
|
||||
Zero = 0,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, // Specifies the source name of the display device. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns the source name in the DISPLAYCONFIG_SOURCE_DEVICE_NAME structure.
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, // Specifies information about the monitor. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns info about the monitor in the DISPLAYCONFIG_TARGET_DEVICE_NAME structure.
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, // Specifies information about the preferred mode of a monitor. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns info about the preferred mode of a monitor in the DISPLAYCONFIG_TARGET_PREFERRED_MODE structure.
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, // Specifies the graphics adapter name. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns the adapter name in the DISPLAYCONFIG_ADAPTER_NAME structure.
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, // Specifies how to set the monitor. If the DisplayConfigSetDeviceInfo function is successful, DisplayConfigSetDeviceInfo uses info in the DISPLAYCONFIG_SET_TARGET_PERSISTENCE structure to force the output in a boot-persistent manner.
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, // Specifies how to set the base output technology for a given target ID. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns base output technology info in the DISPLAYCONFIG_TARGET_BASE_TYPE structure.
|
||||
// Supported by WDDM 1.3 and later user-mode display drivers running on Windows 8.1 and later.
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7, // Specifies the state of virtual mode support. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns virtual mode support information in the DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION structure. Supported starting in Windows 10.
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8, // Specifies how to set the state of virtual mode support. If the DisplayConfigSetDeviceInfo function is successful, DisplayConfigSetDeviceInfo uses info in the DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION structure to change the state of virtual mode support. Supported starting in Windows 10.
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9, // Specifies information about the state of the HDR Color for a display
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10, // Enables or disables the HDR Color for a display
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11, // Specifies the current SDR white level for an HDR monitor. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo return SDR white level info in the DISPLAYCONFIG_SDR_WHITE_LEVEL structure.
|
||||
// Supported starting in Windows<77>10 Fall Creators Update (Version 1709).
|
||||
DISPLAYCONFIG_DEVICE_INFO_GET_MONITOR_SPECIALIZATION = 12,
|
||||
DISPLAYCONFIG_DEVICE_INFO_SET_MONITOR_SPECIALIZATION = 13,
|
||||
DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF // Only here to
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_COLOR_ENCODING : uint
|
||||
public enum DISPLAYCONFIG_COLOR_ENCODING : UInt32
|
||||
{
|
||||
DISPLAYCONFIG_COLOR_ENCODING_RGB = 0,
|
||||
DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1,
|
||||
@ -46,7 +51,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_SCALING : uint
|
||||
public enum DISPLAYCONFIG_SCALING : UInt32
|
||||
{
|
||||
Zero = 0,
|
||||
DISPLAYCONFIG_SCALING_IDENTITY = 1,
|
||||
@ -59,7 +64,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_ROTATION : uint
|
||||
public enum DISPLAYCONFIG_ROTATION : UInt32
|
||||
{
|
||||
Zero = 0,
|
||||
DISPLAYCONFIG_ROTATION_IDENTITY = 1,
|
||||
@ -70,7 +75,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
|
||||
public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : UInt32
|
||||
{
|
||||
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 4294967295, // - 1
|
||||
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
|
||||
@ -95,7 +100,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_TOPOLOGY_ID : uint
|
||||
public enum DISPLAYCONFIG_TOPOLOGY_ID : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
|
||||
@ -106,7 +111,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_PATH_FLAGS : uint
|
||||
public enum DISPLAYCONFIG_PATH_FLAGS : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
DISPLAYCONFIG_PATH_ACTIVE = 0x00000001,
|
||||
@ -115,14 +120,14 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_SOURCE_FLAGS : uint
|
||||
public enum DISPLAYCONFIG_SOURCE_FLAGS : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_TARGET_FLAGS : uint
|
||||
public enum DISPLAYCONFIG_TARGET_FLAGS : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
|
||||
@ -134,7 +139,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum QDC : uint
|
||||
public enum QDC : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
// Get all paths
|
||||
@ -154,7 +159,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SDC : uint
|
||||
public enum SDC : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
SDC_TOPOLOGY_public = 0x00000001,
|
||||
@ -194,7 +199,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
|
||||
public enum DISPLAYCONFIG_SCANLINE_ORDERING : UInt32
|
||||
{
|
||||
DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
|
||||
DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
|
||||
@ -205,7 +210,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_PIXELFORMAT : uint
|
||||
public enum DISPLAYCONFIG_PIXELFORMAT : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
|
||||
@ -217,7 +222,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
|
||||
public enum DISPLAYCONFIG_MODE_INFO_TYPE : UInt32
|
||||
{
|
||||
Zero = 0x0,
|
||||
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
|
||||
@ -227,7 +232,7 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum D3D_VIDEO_SIGNAL_STANDARD : uint
|
||||
public enum D3D_VIDEO_SIGNAL_STANDARD : UInt32
|
||||
{
|
||||
Uninitialized = 0,
|
||||
VesaDmt = 1,
|
||||
|
861
DisplayMagicianShared/Windows/TaskBarLayout.cs
Normal file
861
DisplayMagicianShared/Windows/TaskBarLayout.cs
Normal file
@ -0,0 +1,861 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using DisplayMagicianShared;
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// This file is based on Soroush Falahati's amazing HeliosDisplayManagement software
|
||||
// available at https://github.com/falahati/HeliosDisplayManagement
|
||||
|
||||
// Substantial modifications made by Terry MacDonald 2022 onwards
|
||||
|
||||
namespace DisplayMagicianShared.Windows
|
||||
{
|
||||
public class TaskBarLayout
|
||||
{
|
||||
|
||||
public enum TaskBarEdge : UInt32
|
||||
{
|
||||
Left = 0,
|
||||
Top = 1,
|
||||
Right = 2,
|
||||
Bottom = 3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum TaskBarOptions : UInt32
|
||||
{
|
||||
None = 0,
|
||||
AutoHide = 1 << 0,
|
||||
KeepOnTop = 1 << 1,
|
||||
UseSmallIcons = 1 << 2,
|
||||
HideClock = 1 << 3,
|
||||
HideVolume = 1 << 4,
|
||||
HideNetwork = 1 << 5,
|
||||
HidePower = 1 << 6,
|
||||
WindowPreview = 1 << 7,
|
||||
Unknown1 = 1 << 8,
|
||||
Unknown2 = 1 << 9,
|
||||
HideActionCenter = 1 << 10,
|
||||
Unknown3 = 1 << 11,
|
||||
HideLocation = 1 << 12,
|
||||
HideLanguageBar = 1 << 13
|
||||
}
|
||||
|
||||
private const string MainDisplayAddress =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects{0:D}";
|
||||
|
||||
private const string MultiDisplayAddress =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MMStuckRects{0:D}";
|
||||
|
||||
/*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 bool ReadFromRegistry(string regKeyValue)
|
||||
{
|
||||
bool MMStuckRectVerFound = false;
|
||||
// Check if key exists
|
||||
int version = 3;
|
||||
string address = string.Format(MultiDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
MMStuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect3 registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's not version 3, then try version 2
|
||||
version = 2;
|
||||
address = string.Format(MultiDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
MMStuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect2 registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's not v2 or v3, so it must be a single display
|
||||
MMStuckRectVerFound = false;
|
||||
SharedLogger.logger.Warn($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an MMStuckRect2 or MMStuckRect3 registry key! Going to test if it is a single display only.");
|
||||
}
|
||||
}
|
||||
|
||||
if (MMStuckRectVerFound)
|
||||
{
|
||||
// Check if value exists
|
||||
if (version >= 2 && version <= 3)
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
address,
|
||||
RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
var binary = key?.GetValue(regKeyValue) as byte[];
|
||||
if (binary?.Length > 0)
|
||||
{
|
||||
MainScreen = false;
|
||||
RegKeyValue = regKeyValue;
|
||||
Binary = binary;
|
||||
Version = version;
|
||||
|
||||
// Extract the values from the binary byte field
|
||||
PopulateFieldsFromBinary();
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {RegKeyValue} is against the {Edge} edge, is positioned at ({TaskBarLocation.X},{TaskBarLocation.Y}) and is {TaskBarLocation.Width}x{TaskBarLocation.Height} in size.");
|
||||
|
||||
// If we get here then we're done and don't need to continue with the rest of the code.
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {regKeyValue} screen.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A MMStuckRect entry was found, but the version of the field is wrong.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: A MMStuckRect entry was NOT found. We will try to find the object in the StuckRect registry key instead");
|
||||
}
|
||||
|
||||
bool StuckRectVerFound = false;
|
||||
// Check if string exists
|
||||
version = 3;
|
||||
address = string.Format(MainDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
StuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect3 single display registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's not version 3, then try version 2
|
||||
version = 2;
|
||||
address = string.Format(MainDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
StuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect2 single display registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an single display StuckRect2 or StuckRect3 registry key! So we have to just return after doing nothing as there is nothing we can do.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (StuckRectVerFound)
|
||||
{
|
||||
// Check if value exists
|
||||
if (version >= 2 && version <= 3)
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
address,
|
||||
RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
var binary = key?.GetValue(regKeyValue) as byte[];
|
||||
if (binary?.Length > 0)
|
||||
{
|
||||
MainScreen = true;
|
||||
RegKeyValue = regKeyValue;
|
||||
Binary = binary;
|
||||
Version = version;
|
||||
|
||||
// Extract the values from the binary byte field
|
||||
PopulateFieldsFromBinary();
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {RegKeyValue} is against the {Edge} edge, is positioned at ({TaskBarLocation.X},{TaskBarLocation.Y}) and is {TaskBarLocation.Width}x{TaskBarLocation.Height} in size.");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {regKeyValue} screen.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A StuckRect entry was found, but the version of the field is wrong.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A StuckRect entry was NOT found. This means we're unable to get the taskbar location, an unable to return a sensible TaskBarStuckRectangle object.");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public TaskBarLayout()
|
||||
{
|
||||
}
|
||||
|
||||
public byte[] Binary { get; set; }
|
||||
|
||||
public string RegKeyValue { get; set; }
|
||||
|
||||
public bool MainScreen { get; set; }
|
||||
|
||||
public UInt32 DPI { get; set; }
|
||||
|
||||
public TaskBarEdge Edge { get; set; }
|
||||
|
||||
public Rectangle TaskBarLocation { get; set; }
|
||||
|
||||
public Rectangle StartMenuLocation { get; set; }
|
||||
|
||||
public Rectangle MonitorLocation { get; set; }
|
||||
|
||||
public Size MinSize { get; set; }
|
||||
|
||||
public TaskBarOptions Options { get; set; }
|
||||
|
||||
public uint Rows { get; set; }
|
||||
|
||||
public int Version { get; set; }
|
||||
|
||||
public override bool Equals(object obj) => obj is TaskBarLayout other && this.Equals(other);
|
||||
public bool Equals(TaskBarLayout other)
|
||||
{
|
||||
return Version == other.Version &&
|
||||
RegKeyValue == other.RegKeyValue &&
|
||||
MainScreen == other.MainScreen &&
|
||||
DPI == other.DPI &&
|
||||
Edge == other.Edge &&
|
||||
TaskBarLocation == other.TaskBarLocation &&
|
||||
MinSize == other.MinSize &&
|
||||
Options == other.Options &&
|
||||
Rows == other.Rows;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Version, MainScreen, RegKeyValue, DPI, Edge, TaskBarLocation, MinSize, Options, Rows).GetHashCode();
|
||||
}
|
||||
public static bool operator ==(TaskBarLayout lhs, TaskBarLayout rhs) => lhs.Equals(rhs);
|
||||
|
||||
public static bool operator !=(TaskBarLayout lhs, TaskBarLayout rhs) => !(lhs == rhs);
|
||||
|
||||
static bool Xor(byte[] a, byte[] b)
|
||||
|
||||
{
|
||||
|
||||
int x = a.Length ^ b.Length;
|
||||
|
||||
for (int i = 0; i < a.Length && i < b.Length; ++i)
|
||||
|
||||
{
|
||||
|
||||
x |= a[i] ^ b[i];
|
||||
|
||||
}
|
||||
|
||||
return x == 0;
|
||||
|
||||
}
|
||||
|
||||
private bool PopulateFieldsFromBinary()
|
||||
{
|
||||
// Now we decipher the binary properties features to populate the stuckrectangle
|
||||
// DPI
|
||||
if (Binary.Length < 44)
|
||||
{
|
||||
DPI = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
TaskBarLocation = 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);
|
||||
|
||||
TaskBarLocation = 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);
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateFieldsFromBinary: Grabbed the following settings for {RegKeyValue} from the registry: DPI = {DPI}, Edge = {Edge}, Location = ({TaskBarLocation.X},{TaskBarLocation.Y}), MinSize = {TaskBarLocation.Width}x{TaskBarLocation.Height}, Options = {Options}, Rows = {Rows}.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool PopulateBinaryFromFields()
|
||||
{
|
||||
// Set the DPI
|
||||
if (Binary.Length < 44)
|
||||
{
|
||||
DPI = 0;
|
||||
var bytes = BitConverter.GetBytes(DPI);
|
||||
Array.Copy(bytes, 0, Binary, 40, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(DPI);
|
||||
Array.Copy(bytes, 0, Binary, 40, 4);
|
||||
}
|
||||
// Edge
|
||||
if (Binary.Length < 16)
|
||||
{
|
||||
Edge = TaskBarEdge.Bottom;
|
||||
var bytes = BitConverter.GetBytes((uint)Edge);
|
||||
Array.Copy(bytes, 0, Binary, 12, 4);
|
||||
}
|
||||
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(TaskBarLocation.Left);
|
||||
Array.Copy(bytes, 0, Binary, 24, 4);
|
||||
|
||||
bytes = BitConverter.GetBytes(TaskBarLocation.Top);
|
||||
Array.Copy(bytes, 0, Binary, 28, 4);
|
||||
|
||||
bytes = BitConverter.GetBytes(TaskBarLocation.Right);
|
||||
Array.Copy(bytes, 0, Binary, 32, 4);
|
||||
|
||||
bytes = BitConverter.GetBytes(TaskBarLocation.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);
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateBinaryFromFields: Set the following settings for {RegKeyValue} into registry: DPI = {DPI}, Edge = {Edge}, Location = ({TaskBarLocation.X},{TaskBarLocation.Y}), MinSize = {TaskBarLocation.Width}x{TaskBarLocation.Height}, Options = {Options}, Rows = {Rows}.");
|
||||
|
||||
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 && RegKeyValue.Equals("Settings"))
|
||||
{
|
||||
address = string.Format(MainDisplayAddress, Version);
|
||||
// Set the Main Screen
|
||||
try
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
address,
|
||||
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
key.SetValue(RegKeyValue, Binary);
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {RegKeyValue} Screen in {address}!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {RegKeyValue} TaskBarStuckRectangle registry settings in {address} due to an exception!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
address = string.Format(MultiDisplayAddress, Version);
|
||||
// Grab the main screen taskbar placement
|
||||
try
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
address,
|
||||
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
key.SetValue(RegKeyValue, Binary);
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/WriteToRegistry: Successfully applied TaskBarStuckRectangle registry settings for the {RegKeyValue} Screen in {address}!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/WriteToRegistry: Unable to set the {RegKeyValue} TaskBarStuckRectangle registry settings in {address} due to an exception!");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Dictionary<string, TaskBarLayout> GetAllCurrentTaskBarLayouts(Dictionary<string, List<DISPLAY_SOURCE>> displaySources)
|
||||
{
|
||||
Dictionary<string, TaskBarLayout> taskBarStuckRectangles = new Dictionary<string, TaskBarLayout>();
|
||||
int state;
|
||||
|
||||
APPBARDATA abd = new APPBARDATA();
|
||||
|
||||
// Sleep delay just for testing so I can get the position of the Start Menu
|
||||
// Note for future me, the Start menu window is moved around the desktop to be next to the start button that is pressed by the user.
|
||||
// e.g. if you have two screens, and you click the right most start button, the Start menu window is moved to be the same as the WorkRect of the
|
||||
// monitor that the start button is on.
|
||||
//System.Threading.Thread.Sleep(5000);
|
||||
|
||||
// Firstly try to get the position of the main screen and main start menu
|
||||
try
|
||||
{
|
||||
// Figure out which monitor this taskbar is on
|
||||
IntPtr mainTaskbarHwnd = Utils.FindWindow("Shell_TrayWnd", "");
|
||||
IntPtr mainMonitorHwnd = Utils.MonitorFromWindow(mainTaskbarHwnd, Utils.MONITOR_DEFAULTTOPRIMARY);
|
||||
//IntPtr startMenuHwnd = Utils.FindWindow("Windows.UI.Core.CoreWindow", "Start");
|
||||
|
||||
//Utils.GetWindowRect(startMenuHwnd, out RECT lpRect);
|
||||
|
||||
// Figure out the monitor coordinates
|
||||
MONITORINFOEX monitorInfo = new MONITORINFOEX();
|
||||
monitorInfo.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
|
||||
//monitorInfo.szDevice = new char[Utils.CCHDEVICENAME];
|
||||
Utils.GetMonitorInfo(mainMonitorHwnd, ref monitorInfo);
|
||||
|
||||
abd.hWnd = mainTaskbarHwnd;
|
||||
abd.uEdge = ABEDGE.ABE_BOTTOM;
|
||||
abd.lParam = 0x1;
|
||||
abd.cbSize = Marshal.SizeOf(typeof(APPBARDATA));
|
||||
|
||||
state = Utils.SHAppBarMessage(Utils.ABM_GETTASKBARPOS, ref abd);
|
||||
|
||||
if (state == 1)
|
||||
{
|
||||
int tbWidth = Math.Abs(abd.rc.left - abd.rc.right);
|
||||
int tbHeight = Math.Abs(abd.rc.top - abd.rc.bottom);
|
||||
int monWidth = Math.Abs(monitorInfo.rcMonitor.left - monitorInfo.rcMonitor.right);
|
||||
int monHeight = Math.Abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom);
|
||||
|
||||
TaskBarLayout tbsr = new TaskBarLayout();
|
||||
// Now we're at the point that we should be able to update the binary that we grabbed earlier when the object was created
|
||||
tbsr.ReadFromRegistry(GetRegKeyValueFromDevicePath(displaySources[monitorInfo.szDevice][0].DevicePath));
|
||||
tbsr.Edge = (TaskBarEdge)abd.uEdge;
|
||||
tbsr.MonitorLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monWidth, monHeight);
|
||||
switch (tbsr.Edge)
|
||||
{
|
||||
case TaskBarEdge.Left:
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
|
||||
break;
|
||||
case TaskBarEdge.Top:
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
|
||||
break;
|
||||
case TaskBarEdge.Right:
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.right, monitorInfo.rcWork.top, tbWidth, tbHeight);
|
||||
break;
|
||||
case TaskBarEdge.Bottom:
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.left, monitorInfo.rcWork.bottom, tbWidth, tbHeight);
|
||||
break;
|
||||
default:
|
||||
// Default is bottom taskbar
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.left, monitorInfo.rcWork.bottom, tbWidth, tbHeight);
|
||||
break;
|
||||
}
|
||||
tbsr.MainScreen = true;
|
||||
|
||||
// Now as a LAST step we update the Binary field just before we apply it to make sure that the correct binary settings are stored
|
||||
tbsr.PopulateBinaryFromFields();
|
||||
|
||||
taskBarStuckRectangles.Add(monitorInfo.szDevice, tbsr);
|
||||
|
||||
// If it's a main screen, also add a duplicate so we track the main StuckRects settings separately too
|
||||
TaskBarLayout tbsrMain = new TaskBarLayout();
|
||||
tbsrMain.ReadFromRegistry("Settings");
|
||||
tbsrMain.Edge = tbsr.Edge;
|
||||
tbsrMain.MonitorLocation = tbsr.MonitorLocation;
|
||||
tbsrMain.TaskBarLocation = tbsr.TaskBarLocation;
|
||||
tbsrMain.MainScreen = tbsr.MainScreen;
|
||||
|
||||
// Now as a LAST step we update the Binary field just before we apply it to make sure that the correct binary settings are stored
|
||||
tbsrMain.PopulateBinaryFromFields();
|
||||
taskBarStuckRectangles.Add("Settings", tbsrMain);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SharedLogger.logger.Error(ex, $"WinLibrary/GetAllCurrentTaskBarPositions: Exception while trying to get the maintaskbar position");
|
||||
}
|
||||
|
||||
// Then go through the secondary windows and get the position of them
|
||||
// Tell Windows to refresh the Other Windows Taskbars if needed
|
||||
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Find the next "Shell_SecondaryTrayWnd" window
|
||||
IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
|
||||
if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
|
||||
{
|
||||
// No more windows taskbars to notify
|
||||
break;
|
||||
}
|
||||
|
||||
IntPtr secMonitorHwnd = Utils.MonitorFromWindow(nextTaskBarWindowHwnd, Utils.MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
// Figure out the monitor coordinates
|
||||
MONITORINFOEX monitorInfo = new MONITORINFOEX();
|
||||
monitorInfo.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
|
||||
//monitorInfo.szDevice = new char[Utils.CCHDEVICENAME];
|
||||
Utils.GetMonitorInfo(secMonitorHwnd, ref monitorInfo);
|
||||
|
||||
// Figure out the position of the taskbar ourselves
|
||||
int monWidth = Math.Abs(monitorInfo.rcMonitor.left - monitorInfo.rcMonitor.right);
|
||||
int monHeight = Math.Abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom);
|
||||
int wrkWidth = Math.Abs(monitorInfo.rcWork.left - monitorInfo.rcWork.right);
|
||||
int wrkHeight = Math.Abs(monitorInfo.rcWork.top - monitorInfo.rcWork.bottom);
|
||||
int tbWidth;
|
||||
int tbHeight;
|
||||
|
||||
TaskBarLayout tbsr = new TaskBarLayout();
|
||||
// Now we're at the point that we should be able to update the binary that we grabbed earlier when the object was created
|
||||
tbsr.ReadFromRegistry(GetRegKeyValueFromDevicePath(displaySources[monitorInfo.szDevice][0].DevicePath));
|
||||
if (monWidth == wrkWidth)
|
||||
{
|
||||
// Taskbar on top or bottom
|
||||
if (monitorInfo.rcMonitor.left == monitorInfo.rcWork.left && monitorInfo.rcMonitor.top == monitorInfo.rcWork.top)
|
||||
{
|
||||
// Taskbar on bottom
|
||||
tbWidth = monWidth;
|
||||
tbHeight = monHeight - wrkHeight;
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcWork.bottom, tbWidth, tbHeight);
|
||||
tbsr.Edge = TaskBarEdge.Bottom;
|
||||
}
|
||||
else if (monitorInfo.rcMonitor.right == monitorInfo.rcWork.right && monitorInfo.rcMonitor.bottom == monitorInfo.rcWork.bottom)
|
||||
{
|
||||
// Taskbar on top
|
||||
tbWidth = monWidth;
|
||||
tbHeight = monHeight - wrkHeight;
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
|
||||
tbsr.Edge = TaskBarEdge.Top;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid state
|
||||
SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Taskbar position was not on a horizontal edge of a monitor!");
|
||||
}
|
||||
|
||||
}
|
||||
else if (monHeight == wrkHeight)
|
||||
{
|
||||
// Taskbar on the sides
|
||||
if (monitorInfo.rcMonitor.right == monitorInfo.rcWork.right && monitorInfo.rcMonitor.bottom == monitorInfo.rcWork.bottom)
|
||||
{
|
||||
// Taskbar on left
|
||||
tbWidth = monWidth - wrkWidth;
|
||||
tbHeight = monHeight;
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
|
||||
tbsr.Edge = TaskBarEdge.Left;
|
||||
}
|
||||
else if (monitorInfo.rcMonitor.left == monitorInfo.rcWork.left && monitorInfo.rcMonitor.top == monitorInfo.rcWork.top)
|
||||
{
|
||||
// Taskbar on right
|
||||
tbWidth = monWidth - wrkWidth;
|
||||
tbHeight = monHeight;
|
||||
tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.right, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
|
||||
tbsr.Edge = TaskBarEdge.Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid state
|
||||
SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Taskbar position was not on a vertical edge of a monitor!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid state
|
||||
SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Taskbar position was not fully along one of the monitor edges!");
|
||||
}
|
||||
|
||||
tbsr.MonitorLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monWidth, monHeight);
|
||||
tbsr.MainScreen = false;
|
||||
|
||||
// Now as a LAST step we update the Binary field just before we apply it to make sure that the correct binary settings are stored
|
||||
tbsr.PopulateBinaryFromFields();
|
||||
|
||||
if (!taskBarStuckRectangles.ContainsKey(monitorInfo.szDevice))
|
||||
{
|
||||
taskBarStuckRectangles.Add(monitorInfo.szDevice, tbsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Skipping grabbing Taskbar position from a cloned display {monitorInfo.szDevice}");
|
||||
}
|
||||
|
||||
// Prep the next taskbar window so we continue through them
|
||||
lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
|
||||
}
|
||||
|
||||
return taskBarStuckRectangles;
|
||||
}
|
||||
|
||||
public bool MoveTaskBar()
|
||||
{
|
||||
if (RegKeyValue.Equals("Settings") && MainScreen)
|
||||
{
|
||||
// We only want to set the position for the main screen if it has a "Settings" entry and is a main screen
|
||||
// Find the window to move
|
||||
IntPtr mainTaskbarHwnd = Utils.FindWindow("Shell_TrayWnd", "");
|
||||
//IntPtr startButtonHandle = Utils.FindWindowEx(mainTaskbarHwnd, IntPtr.Zero, "Start", null);
|
||||
IntPtr systemTrayNotifyHandle = Utils.FindWindowEx(mainTaskbarHwnd, IntPtr.Zero, "TrayNotifyWnd", null);
|
||||
//IntPtr rebarWindowHandle = Utils.FindWindowEx(mainTaskbarHwnd, IntPtr.Zero, "ReBarWindow32", null);
|
||||
//IntPtr trayDesktopShowButtonHandle = Utils.FindWindowEx(systemTrayNotifyHandle, IntPtr.Zero, "TrayShowDesktopButtonWClass", null);
|
||||
|
||||
IntPtr result;
|
||||
|
||||
// ===== MOVE THE MAIN TASKBAR WINDOW =====
|
||||
// Prepare the taskbar for moving
|
||||
Utils.SendMessageTimeout(mainTaskbarHwnd, Utils.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
|
||||
// Move the taskbar window
|
||||
Utils.MoveWindow(mainTaskbarHwnd, TaskBarLocation.X, TaskBarLocation.Y, TaskBarLocation.Width, TaskBarLocation.Height, false);
|
||||
|
||||
// ===== LOCK THE MAIN TASKBAR WINDOW BACK DOWN =====
|
||||
// Tell the taskbar we've stopped moving it now
|
||||
Utils.SendMessageTimeout(mainTaskbarHwnd, Utils.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
|
||||
// Tell the taskbar it needs to update it's theme
|
||||
Utils.PostMessage(mainTaskbarHwnd, Utils.WM_THEMECHANGED, IntPtr.Zero, IntPtr.Zero);
|
||||
// Tell the taskbar it needs to recalculate it's work area
|
||||
Utils.SendMessageTimeout(systemTrayNotifyHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
|
||||
|
||||
// We also save the taskbar position for the monitor in registry, so that Windows will actually properly update the position
|
||||
// after 5 seconds (and this one will stick between reboots too!).
|
||||
WriteToRegistry();
|
||||
|
||||
}
|
||||
else if (MainScreen && !RegKeyValue.Equals("Settings"))
|
||||
{
|
||||
// If it's a main screen, but not "settings", then its the registry key only taskbar setting we need to change
|
||||
// This is because hte only screen settings that matter are the StuckRect3 registry key (for the main screen) and
|
||||
// all of the secondary windows
|
||||
WriteToRegistry();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a secondary screen, so we need to set it's position
|
||||
// Then go through the secondary windows and get the position of them
|
||||
// Tell Windows to refresh the Other Windows Taskbars if needed
|
||||
//WriteToRegistry();
|
||||
|
||||
IntPtr mainTaskbarHwnd = Utils.FindWindow("Shell_TrayWnd", "");
|
||||
|
||||
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Find the next "Shell_SecondaryTrayWnd" window
|
||||
IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
|
||||
if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
|
||||
{
|
||||
// No more windows taskbars to notify
|
||||
break;
|
||||
}
|
||||
|
||||
IntPtr secMonitorHwnd = Utils.MonitorFromWindow(nextTaskBarWindowHwnd, Utils.MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
// Figure out this monitor coordinates
|
||||
MONITORINFOEX monitorInfo = new MONITORINFOEX();
|
||||
monitorInfo.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
|
||||
//monitorInfo.szDevice = new char[Utils.CCHDEVICENAME];
|
||||
Utils.GetMonitorInfo(secMonitorHwnd, ref monitorInfo);
|
||||
|
||||
// Figure out the position of the taskbar ourselves
|
||||
int monWidth = Math.Abs(monitorInfo.rcMonitor.left - monitorInfo.rcMonitor.right);
|
||||
int monHeight = Math.Abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom);
|
||||
Rectangle thisMonitorLocation = new Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monWidth, monHeight);
|
||||
if (MonitorLocation.Equals(thisMonitorLocation))
|
||||
{
|
||||
// This is the right monitor, so we should move the taskbar on it.
|
||||
|
||||
IntPtr result;
|
||||
|
||||
// ===== MOVE THE MAIN TASKBAR WINDOW =====
|
||||
// Prepare the taskbar for moving
|
||||
Utils.SendMessageTimeout(nextTaskBarWindowHwnd, Utils.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
|
||||
// Move the taskbar window
|
||||
Utils.MoveWindow(nextTaskBarWindowHwnd, TaskBarLocation.X, TaskBarLocation.Y, TaskBarLocation.Width, TaskBarLocation.Height, true);
|
||||
|
||||
// ===== LOCK THE MAIN TASKBAR WINDOW BACK DOWN =====
|
||||
// Tell the taskbar we've stopped moving it now
|
||||
//Utils.SendMessageTimeout(nextTaskBarWindowHwnd, Utils.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
|
||||
// Tell the taskbar it needs to update it's theme
|
||||
//Utils.PostMessage(nextTaskBarWindowHwnd, Utils.WM_THEMECHANGED, IntPtr.Zero, IntPtr.Zero);
|
||||
// Tell the taskbar it needs to recalculate it's work area
|
||||
//Utils.SendMessageTimeout(nextTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
|
||||
|
||||
// We also save the taskbar position for the monitor in registry, so that Windows will actually properly update the position
|
||||
// after 5 seconds (and this one will stick between reboots too!).
|
||||
WriteToRegistry();
|
||||
|
||||
|
||||
// We then want to stop as we've found the correct taskbar to move!
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Prep the next taskbar window so we continue through them
|
||||
lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static string GetRegKeyValueFromDevicePath(string devicePath)
|
||||
{
|
||||
string regKeyValue = "";
|
||||
// e.g. "\\\\?\\DISPLAY#NVS10DE#5&2b46c695&0&UID185344#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"
|
||||
string pattern = @"DISPLAY\#(.*)\#\{";
|
||||
Match match = Regex.Match(devicePath, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
regKeyValue = match.Groups[1].Value;
|
||||
SharedLogger.logger.Trace($"TaskBarLayout/GetRegKeyValueFromDevicePath: Found regKeyValue {regKeyValue } in the devicePath {devicePath }.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Warn($"TaskBarLayout/GetRegKeyValueFromDevicePath: We were unable to figure out the regKeyValue {regKeyValue } in the devicePath {devicePath }..");
|
||||
}
|
||||
return regKeyValue;
|
||||
}
|
||||
|
||||
public static bool ForceTaskBarRedraw(IntPtr mainToolBarHWnd)
|
||||
{
|
||||
// Tell Windows to refresh the Main Screen Windows Taskbar registry settings by telling Explorer to update.
|
||||
Utils.SendMessage(mainToolBarHWnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
// Tell Windows to refresh the child Windows in the taskbar
|
||||
IntPtr lastChildWindowHwnd = (IntPtr)Utils.NULL;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Find the next "Shell_SecondaryTrayWnd" window
|
||||
IntPtr nextChildWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, mainToolBarHWnd, "", null);
|
||||
if (nextChildWindowHwnd == (IntPtr)Utils.NULL)
|
||||
{
|
||||
// No more windows taskbars to notify
|
||||
break;
|
||||
}
|
||||
// Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
|
||||
Utils.SendMessage(lastChildWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
lastChildWindowHwnd = nextChildWindowHwnd;
|
||||
}
|
||||
|
||||
//IntPtr explorerToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
|
||||
//Utils.PostMessage((IntPtr)Utils.HWND_BROADCAST, Utils.SHELLHOOK, 0x13, (int) mainToolBarHWnd);
|
||||
//Utils.PostMessage((IntPtr)Utils.HWND_BROADCAST, Utils.WM_SETTINGCHANGE, (int)Utils.SPI_SETWORKAREA, (int)Utils.NULL);
|
||||
/*IntPtr result;
|
||||
Utils.SendMessageTimeout((IntPtr)Utils.HWND_BROADCAST, Utils.WM_USER_1, (IntPtr)Utils.NULL, (IntPtr)Utils.NULL, Utils.SendMessageTimeoutFlag.SMTO_ABORTIFHUNG, 15, out result);*/
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Serializable]
|
||||
public class TaskBarStuckRectangleException : Exception
|
||||
{
|
||||
public TaskBarStuckRectangleException() { }
|
||||
public TaskBarStuckRectangleException(string message) : base(message) { }
|
||||
public TaskBarStuckRectangleException(string message, Exception inner) : base(message, inner) { }
|
||||
protected TaskBarStuckRectangleException(
|
||||
System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Win32;
|
||||
|
||||
// This file is taken from Soroush Falahati's amazing HeliosDisplayManagement software
|
||||
// available at https://github.com/falahati/HeliosDisplayManagement
|
||||
|
||||
// Modifications made by Terry MacDonald
|
||||
|
||||
namespace DisplayMagicianShared.Windows
|
||||
{
|
||||
public class TaskBarSettings
|
||||
{
|
||||
private const string AdvancedSettingsAddress =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
|
||||
|
||||
private static List<string> WantedAdvancedSettingValues = new List<string>
|
||||
{
|
||||
// Win10/11 registry keys (not all will be populated, only those that the user modified from default at least once)
|
||||
"MMTaskbarEnabled", // Multiple Taskbars: 0 for show taskbar on main screen only, 1 for show taskbar on all screens
|
||||
"MMTaskbarMode", // Show taskbar buttons on: 0 = all taskbars, 1 = main taskbar and where windows is open, 2 = taskbar where window is open
|
||||
"MMTaskbarGlomLevel", // Buttons on other taskbars: 0 = always combine, combine when the taskbar is full, 2 = never combine
|
||||
"NoTaskGrouping", // Disable all Task Grouping (overrides "TaskbarGroupSize"): 0 = enable task grouping, 1 = disable task grouping
|
||||
"SearchboxTaskbarMode", // Show Search Button in Taskbar: 0 = remove search button, 1 = show search button
|
||||
"ShowTaskViewButton", // Show Taskview Button in Taskbar: 0 = remove taskview button, 1 = show taskview button
|
||||
"TaskbarAl", // Start Button Alignment: 0 for left, 1 for center,
|
||||
"TaskbarDa", // Show Widgets button in Taskbar: 0 = remove widgets button, 1 = Show widgets button
|
||||
"TaskbarGlomLevel", // Buttons on main screen: 0 = always combine, combine when the taskbar is full, 2 = never combine
|
||||
"TaskbarGroupSize", // TaskBar left/right grouping by age: 0 = oldest first (default), 1 = roup by size largest first, 2 = group all with 2 or more, 3 = group all with 3 or more (see NoTaskGrouping to prevent Grouping )
|
||||
"TaskbarMn", // Show Chat Button in Taskbar: 0 = remove chat button, 1 = show chat button
|
||||
"TaskbarSi", // Taskbar Size: 0 = small, 1 = medium, 2 = Large
|
||||
"TaskbarSizeMove", // Lock the Taskbar (prevent resizing): 0 = taskbar size is locked, 1 = taskbar size is unlocked
|
||||
"TaskbarSmallIcons", // Small Taskbar Icons: 0 = normal sized icons, 1 = small icons
|
||||
"TaskbarSd", // Show Desktop Button in Taskbar: 0 for hid the show desktop button, 1 for show the Show desktop button
|
||||
};
|
||||
|
||||
|
||||
public Tuple<string, int>[] Options { get; set; }
|
||||
|
||||
public override bool Equals(object obj) => obj is TaskBarSettings other && this.Equals(other);
|
||||
public bool Equals(TaskBarSettings other)
|
||||
=> Options.All(a => other.Options.Any(x => x.Item1 == a.Item1 && x.Item2 == a.Item2));
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Options).GetHashCode();
|
||||
}
|
||||
public static bool operator ==(TaskBarSettings lhs, TaskBarSettings rhs) => lhs.Equals(rhs);
|
||||
|
||||
public static bool operator !=(TaskBarSettings lhs, TaskBarSettings rhs) => !(lhs == rhs);
|
||||
|
||||
public static TaskBarSettings GetCurrent()
|
||||
{
|
||||
var taskBarOptions = new List<Tuple<string, int>>();
|
||||
|
||||
// Get modified and stored Taskbar options from the User Registry
|
||||
// Note: Only the taskbar options changed from default at least once in the past will be listed in Registry
|
||||
try
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
AdvancedSettingsAddress,
|
||||
RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
foreach (var valueName in WantedAdvancedSettingValues)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var value = key.GetValue(valueName, null,
|
||||
RegistryValueOptions.DoNotExpandEnvironmentNames);
|
||||
|
||||
if (value != null && value is int intValue)
|
||||
{
|
||||
taskBarOptions.Add(new Tuple<string, int>(valueName, intValue));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored, as this will happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (taskBarOptions.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TaskBarSettings
|
||||
{
|
||||
Options = taskBarOptions.ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
public bool Apply()
|
||||
{
|
||||
if (Options.Length == 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
using (var optionsKey = Registry.CurrentUser.OpenSubKey(
|
||||
AdvancedSettingsAddress,
|
||||
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
if (optionsKey == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write
|
||||
foreach (var option in Options)
|
||||
{
|
||||
try
|
||||
{
|
||||
optionsKey.SetValue(option.Item1, option.Item2);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,561 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using DisplayMagicianShared;
|
||||
using System.Linq;
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// This file is taken from Soroush Falahati's amazing HeliosDisplayManagement software
|
||||
// available at https://github.com/falahati/HeliosDisplayManagement
|
||||
|
||||
// Substantial modifications made by Terry MacDonald 2022 onwards
|
||||
// Modifications made by Terry MacDonald
|
||||
|
||||
namespace DisplayMagicianShared.Windows
|
||||
{
|
||||
public class TaskBarStuckRectangle
|
||||
public class TaskBarSettings
|
||||
{
|
||||
private const string AdvancedSettingsAddress =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
|
||||
|
||||
public enum TaskBarEdge : UInt32
|
||||
private static List<string> WantedAdvancedSettingValues = new List<string>
|
||||
{
|
||||
Left = 0,
|
||||
Top = 1,
|
||||
Right = 2,
|
||||
Bottom = 3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum TaskBarOptions : UInt32
|
||||
{
|
||||
None = 0,
|
||||
AutoHide = 1 << 0,
|
||||
KeepOnTop = 1 << 1,
|
||||
UseSmallIcons = 1 << 2,
|
||||
HideClock = 1 << 3,
|
||||
HideVolume = 1 << 4,
|
||||
HideNetwork = 1 << 5,
|
||||
HidePower = 1 << 6,
|
||||
WindowPreview = 1 << 7,
|
||||
Unknown1 = 1 << 8,
|
||||
Unknown2 = 1 << 9,
|
||||
HideActionCenter = 1 << 10,
|
||||
Unknown3 = 1 << 11,
|
||||
HideLocation = 1 << 12,
|
||||
HideLanguageBar = 1 << 13
|
||||
}
|
||||
|
||||
private const string MainDisplayAddress =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects{0:D}";
|
||||
|
||||
private const string MultiDisplayAddress =
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MMStuckRects{0:D}";
|
||||
|
||||
/*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}}
|
||||
// Win10/11 registry keys (not all will be populated, only those that the user modified from default at least once)
|
||||
"MMTaskbarEnabled", // Multiple Taskbars: 0 for show taskbar on main screen only, 1 for show taskbar on all screens
|
||||
"MMTaskbarMode", // Show taskbar buttons on: 0 = all taskbars, 1 = main taskbar and where windows is open, 2 = taskbar where window is open
|
||||
"MMTaskbarGlomLevel", // Buttons on other taskbars: 0 = always combine, combine when the taskbar is full, 2 = never combine
|
||||
"NoTaskGrouping", // Disable all Task Grouping (overrides "TaskbarGroupSize"): 0 = enable task grouping, 1 = disable task grouping
|
||||
"SearchboxTaskbarMode", // Show Search Button in Taskbar: 0 = remove search button, 1 = show search button
|
||||
"ShowTaskViewButton", // Show Taskview Button in Taskbar: 0 = remove taskview button, 1 = show taskview button
|
||||
"TaskbarAl", // Start Button Alignment: 0 for left, 1 for center,
|
||||
"TaskbarDa", // Show Widgets button in Taskbar: 0 = remove widgets button, 1 = Show widgets button
|
||||
"TaskbarGlomLevel", // Buttons on main screen: 0 = always combine, combine when the taskbar is full, 2 = never combine
|
||||
"TaskbarGroupSize", // TaskBar left/right grouping by age: 0 = oldest first (default), 1 = roup by size largest first, 2 = group all with 2 or more, 3 = group all with 3 or more (see NoTaskGrouping to prevent Grouping )
|
||||
"TaskbarMn", // Show Chat Button in Taskbar: 0 = remove chat button, 1 = show chat button
|
||||
"TaskbarSi", // Taskbar Size: 0 = small, 1 = medium, 2 = Large
|
||||
"TaskbarSizeMove", // Lock the Taskbar (prevent resizing): 0 = taskbar size is locked, 1 = taskbar size is unlocked
|
||||
"TaskbarSmallIcons", // Small Taskbar Icons: 0 = normal sized icons, 1 = small icons
|
||||
"TaskbarSd", // Show Desktop Button in Taskbar: 0 for hid the show desktop button, 1 for show the Show desktop button
|
||||
};
|
||||
*/
|
||||
public TaskBarStuckRectangle(string devicePath)
|
||||
{
|
||||
bool MMStuckRectVerFound = false;
|
||||
// Check if key exists
|
||||
int version = 3;
|
||||
string address = string.Format(MultiDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
MMStuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect3 registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's not version 3, then try version 2
|
||||
version = 2;
|
||||
address = string.Format(MultiDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
MMStuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect2 registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's not v2 or v3, so it must be a single display
|
||||
MMStuckRectVerFound = false;
|
||||
SharedLogger.logger.Warn($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an MMStuckRect2 or MMStuckRect3 registry key! Going to test if it is a single display only.");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
OriginalBinary = new byte[binary.Length];
|
||||
binary.CopyTo(OriginalBinary, 0);
|
||||
Version = version;
|
||||
|
||||
// Extract the values from the binary byte field
|
||||
PopulateFieldsFromBinary();
|
||||
public Tuple<string, int>[] Options { get; set; }
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: 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($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundDevicePath)
|
||||
{
|
||||
bool StuckRectVerFound = false;
|
||||
// Check if string exists
|
||||
version = 3;
|
||||
address = string.Format(MainDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
StuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect3 single display registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's not version 3, then try version 2
|
||||
version = 2;
|
||||
address = string.Format(MainDisplayAddress, version);
|
||||
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
||||
{
|
||||
StuckRectVerFound = true;
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect2 single display registry key! {address}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an single display StuckRect2 or StuckRect3 registry key! So we have to just return after doing nothing as there is nothing we can do.");
|
||||
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;
|
||||
OriginalBinary = new byte[binary.Length];
|
||||
binary.CopyTo(OriginalBinary, 0);
|
||||
Version = version;
|
||||
|
||||
// Extract the values from the binary byte field
|
||||
PopulateFieldsFromBinary();
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: 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($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TaskBarStuckRectangle()
|
||||
{
|
||||
}
|
||||
|
||||
public byte[] Binary { get; set; }
|
||||
|
||||
public byte[] OriginalBinary { get; set; }
|
||||
|
||||
public string DevicePath { get; set; }
|
||||
|
||||
public bool MainScreen { get; set; }
|
||||
|
||||
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; }
|
||||
|
||||
public int Version { get; set; }
|
||||
|
||||
public override bool Equals(object obj) => obj is TaskBarStuckRectangle other && this.Equals(other);
|
||||
public bool Equals(TaskBarStuckRectangle other)
|
||||
{
|
||||
return Version == other.Version &&
|
||||
DevicePath == other.DevicePath &&
|
||||
MainScreen == other.MainScreen &&
|
||||
DPI == other.DPI &&
|
||||
Edge == other.Edge &&
|
||||
Location == other.Location &&
|
||||
MinSize == other.MinSize &&
|
||||
Options == other.Options &&
|
||||
Rows == other.Rows;
|
||||
}
|
||||
public override bool Equals(object obj) => obj is TaskBarSettings other && this.Equals(other);
|
||||
public bool Equals(TaskBarSettings other)
|
||||
=> Options.All(a => other.Options.Any(x => x.Item1 == a.Item1 && x.Item2 == a.Item2));
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Version, MainScreen, DevicePath, DPI, Edge, Location, MinSize, Options, Rows).GetHashCode();
|
||||
return (Options).GetHashCode();
|
||||
}
|
||||
public static bool operator ==(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => lhs.Equals(rhs);
|
||||
public static bool operator ==(TaskBarSettings lhs, TaskBarSettings rhs) => lhs.Equals(rhs);
|
||||
|
||||
public static bool operator !=(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => !(lhs == rhs);
|
||||
public static bool operator !=(TaskBarSettings lhs, TaskBarSettings rhs) => !(lhs == rhs);
|
||||
|
||||
static bool Xor(byte[] a, byte[] b)
|
||||
public static TaskBarSettings GetCurrent()
|
||||
{
|
||||
var taskBarOptions = new List<Tuple<string, int>>();
|
||||
|
||||
{
|
||||
|
||||
int x = a.Length ^ b.Length;
|
||||
|
||||
for (int i = 0; i < a.Length && i < b.Length; ++i)
|
||||
|
||||
{
|
||||
|
||||
x |= a[i] ^ b[i];
|
||||
|
||||
}
|
||||
|
||||
return x == 0;
|
||||
|
||||
}
|
||||
|
||||
private bool PopulateFieldsFromBinary()
|
||||
{
|
||||
// Now we decipher the binary properties features to populate the stuckrectangle
|
||||
// DPI
|
||||
if (Binary.Length < 44)
|
||||
{
|
||||
DPI = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateFieldsFromBinary: Grabbed the following settings for {DevicePath} from the registry: DPI = {DPI}, Edge = {Edge}, Location = ({Location.X},{Location.Y}), MinSize = {Location.Width}x{Location.Height}, Options = {Options}, Rows = {Rows}.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool PopulateBinaryFromFields()
|
||||
{
|
||||
// Set the DPI
|
||||
if (Binary.Length < 44)
|
||||
{
|
||||
DPI = 0;
|
||||
var bytes = BitConverter.GetBytes(DPI);
|
||||
Array.Copy(bytes, 0, Binary, 40, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(DPI);
|
||||
Array.Copy(bytes, 0, Binary, 40, 4);
|
||||
}
|
||||
// Edge
|
||||
if (Binary.Length < 16)
|
||||
{
|
||||
Edge = TaskBarEdge.Bottom;
|
||||
var bytes = BitConverter.GetBytes((uint)Edge);
|
||||
Array.Copy(bytes, 0, Binary, 12, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var bytes = BitConverter.GetBytes((uint)Edge);
|
||||
Array.Copy(bytes, 0, Binary, 12, 1);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateBinaryFromFields: Set the following settings for {DevicePath} into registry: DPI = {DPI}, Edge = {Edge}, Location = ({Location.X},{Location.Y}), MinSize = {Location.Width}x{Location.Height}, Options = {Options}, Rows = {Rows}.");
|
||||
|
||||
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
|
||||
// Get modified and stored Taskbar options from the User Registry
|
||||
// Note: Only the taskbar options changed from default at least once in the past will be listed in Registry
|
||||
try
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
address,
|
||||
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
AdvancedSettingsAddress,
|
||||
RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
key.SetValue(DevicePath, Binary);
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (key != null)
|
||||
{
|
||||
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
|
||||
}
|
||||
}
|
||||
else
|
||||
foreach (var valueName in WantedAdvancedSettingValues)
|
||||
{
|
||||
address = string.Format(MultiDisplayAddress, Version);
|
||||
// Grab the main screen taskbar placement
|
||||
try
|
||||
{
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(
|
||||
address,
|
||||
|
||||
var value = key.GetValue(valueName, null,
|
||||
RegistryValueOptions.DoNotExpandEnvironmentNames);
|
||||
|
||||
if (value != null && value is int intValue)
|
||||
{
|
||||
taskBarOptions.Add(new Tuple<string, int>(valueName, intValue));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored, as this will happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (taskBarOptions.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TaskBarSettings
|
||||
{
|
||||
Options = taskBarOptions.ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
public bool Apply()
|
||||
{
|
||||
if (Options.Length == 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
using (var optionsKey = Registry.CurrentUser.OpenSubKey(
|
||||
AdvancedSettingsAddress,
|
||||
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
key.SetValue(DevicePath, Binary);
|
||||
SharedLogger.logger.Trace($"TaskBarStuckRectangle/WriteToRegistry: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (optionsKey == null)
|
||||
{
|
||||
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/WriteToRegistry: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write
|
||||
foreach (var option in Options)
|
||||
{
|
||||
try
|
||||
{
|
||||
optionsKey.SetValue(option.Item1, option.Item2);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RepositionMainTaskBar(TaskBarEdge edge)
|
||||
{
|
||||
// Tell Windows to refresh the Main Screen Windows Taskbar
|
||||
// Find the "Shell_TrayWnd" window
|
||||
IntPtr mainToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
|
||||
// Send the "Shell_TrayWnd" window a WM_USER_REFRESHTASKBAR with a wParameter of 0006 and a lParamater of the position (e.g. 0000 for left, 0001 for top, 0002 for right and 0003 for bottom)
|
||||
IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
|
||||
Utils.SendMessage(mainToolBarHWnd, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RepositionSecondaryTaskBars()
|
||||
{
|
||||
// Tell Windows to refresh the Other Windows Taskbars if needed
|
||||
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Find the next "Shell_SecondaryTrayWnd" window
|
||||
IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
|
||||
if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
|
||||
{
|
||||
// No more windows taskbars to notify
|
||||
break;
|
||||
}
|
||||
// Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
|
||||
Utils.SendMessage(lastTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void RefreshTrayArea()
|
||||
{
|
||||
// Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "Notification Area" containing the visible notification area icons (windows 7 version)
|
||||
IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
|
||||
IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
|
||||
IntPtr sysPagerHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
|
||||
IntPtr notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
|
||||
// If the visible notification area icons (Windows 7 aren't found, then we're on a later version of windows, and we need to look for different window names
|
||||
if (notificationAreaHandle == IntPtr.Zero)
|
||||
{
|
||||
// Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "User Promoted Notification Area" containing the visible notification area icons (windows 10+ version)
|
||||
notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
|
||||
// Also attempt to find the NotifyIconOverflowWindow -> "Overflow Notification Area' window which is the hidden windoww that notification icons live when they are
|
||||
// too numberous or are hidden by the user.
|
||||
IntPtr notifyIconOverflowWindowHandle = Utils.FindWindow("NotifyIconOverflowWindow", null);
|
||||
IntPtr overflowNotificationAreaHandle = Utils.FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
|
||||
// Fool the "Overflow Notification Area' window into thinking the mouse is moving over it
|
||||
// which will force windows to refresh the "Overflow Notification Area' window and remove old icons.
|
||||
RefreshTrayArea(overflowNotificationAreaHandle);
|
||||
notifyIconOverflowWindowHandle = IntPtr.Zero;
|
||||
overflowNotificationAreaHandle = IntPtr.Zero;
|
||||
}
|
||||
// Fool the "Notification Area" or "User Promoted Notification Area" window (depends on the version of windows) into thinking the mouse is moving over it
|
||||
// which will force windows to refresh the "Notification Area" or "User Promoted Notification Area" window and remove old icons.
|
||||
RefreshTrayArea(notificationAreaHandle);
|
||||
systemTrayContainerHandle = IntPtr.Zero;
|
||||
systemTrayHandle = IntPtr.Zero;
|
||||
sysPagerHandle = IntPtr.Zero;
|
||||
notificationAreaHandle = IntPtr.Zero;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void RefreshTrayArea(IntPtr windowHandle)
|
||||
{
|
||||
// Moves the mouse around within the window area of the supplied window
|
||||
Utils.RECT rect;
|
||||
Utils.GetClientRect(windowHandle, out rect);
|
||||
for (var x = 0; x < rect.right; x += 5)
|
||||
for (var y = 0; y < rect.bottom; y += 5)
|
||||
Utils.SendMessage(windowHandle, Utils.WM_MOUSEMOVE, 0, (y << 16) + x);
|
||||
}
|
||||
|
||||
/*public void DoMouseLeftClick(IntPtr handle, Point x)
|
||||
{
|
||||
Utils.SendMessage(handle, (int)Utils.WM_MOUSEMOVE, 0, Utils.MakeLParam(x.X, x.Y));
|
||||
//SendMessage(handle, (int)Utils.WM_LBUTTONUP, 0, Utils.MakeLParam(x.X, x.Y));
|
||||
|
||||
return;
|
||||
|
||||
//I have tried PostMessage, and SendMessage, and both of them at the same time, and neither works.
|
||||
|
||||
Utils.PostMessage(handle, Utils.WM_MOUSEMOVE, 0, Utils.MakeLParam(x.X, x.Y));
|
||||
//PostMessage(handle, (uint)Utils.WM_LBUTTONUP, 0, Utils.MakeLParam(x.X, x.Y));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ using System.IO;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.Win32;
|
||||
using System.Threading.Tasks;
|
||||
using static DisplayMagicianShared.Windows.TaskBarLayout;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace DisplayMagicianShared.Windows
|
||||
{
|
||||
@ -37,6 +39,27 @@ namespace DisplayMagicianShared.Windows
|
||||
public static bool operator !=(ADVANCED_HDR_INFO_PER_PATH lhs, ADVANCED_HDR_INFO_PER_PATH rhs) => !(lhs == rhs);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct DISPLAY_SOURCE : IEquatable<DISPLAY_SOURCE>
|
||||
{
|
||||
public LUID AdapterId;
|
||||
public UInt32 SourceId;
|
||||
public UInt32 TargetId;
|
||||
public string DevicePath;
|
||||
|
||||
public override bool Equals(object obj) => obj is DISPLAY_SOURCE other && this.Equals(other);
|
||||
public bool Equals(DISPLAY_SOURCE other)
|
||||
=> true;
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 300;
|
||||
}
|
||||
|
||||
public static bool operator ==(DISPLAY_SOURCE lhs, DISPLAY_SOURCE rhs) => lhs.Equals(rhs);
|
||||
|
||||
public static bool operator !=(DISPLAY_SOURCE lhs, DISPLAY_SOURCE rhs) => !(lhs == rhs);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WINDOWS_DISPLAY_CONFIG : IEquatable<WINDOWS_DISPLAY_CONFIG>
|
||||
{
|
||||
@ -45,13 +68,13 @@ namespace DisplayMagicianShared.Windows
|
||||
public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes;
|
||||
public List<ADVANCED_HDR_INFO_PER_PATH> DisplayHDRStates;
|
||||
public Dictionary<string, GDI_DISPLAY_SETTING> GdiDisplaySettings;
|
||||
public List<TaskBarStuckRectangle> TaskBarLayout;
|
||||
public Dictionary<string, TaskBarLayout> TaskBarLayout;
|
||||
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
|
||||
// and it is informational only and doesn't contribute to the configuration (it's used for generating the Screens structure, and therefore for
|
||||
// generating the profile icon.
|
||||
public Dictionary<string, List<uint>> DisplaySources;
|
||||
public Dictionary<string, List<DISPLAY_SOURCE>> DisplaySources;
|
||||
public List<string> DisplayIdentifiers;
|
||||
|
||||
public override bool Equals(object obj) => obj is WINDOWS_DISPLAY_CONFIG other && this.Equals(other);
|
||||
@ -64,9 +87,12 @@ namespace DisplayMagicianShared.Windows
|
||||
// Additionally, we had to disable the DEviceKey from the equality testing within the GDI library itself as that waould also change after changing back from NVIDIA surround
|
||||
// This still allows us to detect when refresh rates change, which will allow DisplayMagician to detect profile differences.
|
||||
GdiDisplaySettings.Values.SequenceEqual(other.GdiDisplaySettings.Values) &&
|
||||
DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers) &&
|
||||
DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers);
|
||||
// NOTE: I have disabled the TaskBar specific matching for now due to errors I cannot fix
|
||||
// WinLibrary will still track the location of the taskbars, but won't actually set them as the setting of the taskbars doesnt work at the moment.
|
||||
/*&&
|
||||
TaskBarLayout.SequenceEqual(other.TaskBarLayout) &&
|
||||
TaskBarSettings.Equals(other.TaskBarSettings);
|
||||
TaskBarSettings.Equals(other.TaskBarSettings);*/
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
@ -180,9 +206,9 @@ namespace DisplayMagicianShared.Windows
|
||||
myDefaultConfig.DisplayConfigPaths = new DISPLAYCONFIG_PATH_INFO[0];
|
||||
myDefaultConfig.DisplayHDRStates = new List<ADVANCED_HDR_INFO_PER_PATH>();
|
||||
myDefaultConfig.DisplayIdentifiers = new List<string>();
|
||||
myDefaultConfig.DisplaySources = new Dictionary<string, List<uint>>();
|
||||
myDefaultConfig.DisplaySources = new Dictionary<string, List<DISPLAY_SOURCE>>();
|
||||
myDefaultConfig.GdiDisplaySettings = new Dictionary<string, GDI_DISPLAY_SETTING>();
|
||||
myDefaultConfig.TaskBarLayout = new List<TaskBarStuckRectangle>();
|
||||
myDefaultConfig.TaskBarLayout = new Dictionary<string, TaskBarLayout>();
|
||||
myDefaultConfig.TaskBarSettings = new TaskBarSettings();
|
||||
myDefaultConfig.IsCloned = false;
|
||||
|
||||
@ -292,6 +318,34 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: Going through the display sources list info to update the adapter id");
|
||||
// Update the DisplaySources with the current adapter id
|
||||
for (int i = 0; i < savedDisplayConfig.DisplaySources.Count; i++)
|
||||
{
|
||||
List<DISPLAY_SOURCE> dsList = savedDisplayConfig.DisplaySources.ElementAt(i).Value;
|
||||
if (dsList.Count > 0)
|
||||
{
|
||||
for (int j = 0; j < dsList.Count; j++)
|
||||
{
|
||||
DISPLAY_SOURCE ds = dsList[j];
|
||||
// Change the Display Source AdapterID
|
||||
if (adapterOldToNewMap.ContainsKey(ds.AdapterId.Value))
|
||||
{
|
||||
// We get here if there is a matching adapter
|
||||
newAdapterValue = adapterOldToNewMap[ds.AdapterId.Value];
|
||||
ds.AdapterId = AdapterValueToLUID(newAdapterValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if there isn't a matching adapter, then we just pick the first current one and hope that works!
|
||||
// (it is highly likely to... its only if the user has multiple graphics cards with some weird config it may break)
|
||||
newAdapterValue = currentAdapterMap.First().Key;
|
||||
SharedLogger.logger.Warn($"WinLibrary/PatchAdapterIDs: Uh Oh. Adapter {savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value} didn't have a current match in Display Sources! It's possible the adapter was swapped or disabled. Attempting to use adapter {newAdapterValue} instead.");
|
||||
ds.AdapterId = AdapterValueToLUID(newAdapterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateActiveConfig()
|
||||
@ -320,6 +374,10 @@ namespace DisplayMagicianShared.Windows
|
||||
|
||||
private WINDOWS_DISPLAY_CONFIG GetWindowsDisplayConfig(QDC selector = QDC.QDC_ONLY_ACTIVE_PATHS | QDC.QDC_INCLUDE_HMD)
|
||||
{
|
||||
|
||||
// Prepare the empty windows display config
|
||||
WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = CreateDefaultConfig();
|
||||
|
||||
// Get the size of the largest Active Paths and Modes arrays
|
||||
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the size of the largest Active Paths and Modes arrays");
|
||||
int pathCount = 0;
|
||||
@ -368,12 +426,6 @@ namespace DisplayMagicianShared.Windows
|
||||
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
|
||||
}
|
||||
|
||||
// Prepare the empty windows display config
|
||||
WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = new WINDOWS_DISPLAY_CONFIG();
|
||||
windowsDisplayConfig.DisplayAdapters = new Dictionary<ulong, string>();
|
||||
windowsDisplayConfig.DisplayHDRStates = new List<ADVANCED_HDR_INFO_PER_PATH>();
|
||||
windowsDisplayConfig.DisplaySources = new Dictionary<string, List<uint>>();
|
||||
windowsDisplayConfig.IsCloned = false;
|
||||
|
||||
// First of all generate the current displayIdentifiers
|
||||
windowsDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers();
|
||||
@ -393,6 +445,7 @@ namespace DisplayMagicianShared.Windows
|
||||
|
||||
// Now cycle through the paths and grab the HDR state information
|
||||
// and map the adapter name to adapter id
|
||||
// and populate the display source information
|
||||
List<uint> targetPathIdsToChange = new List<uint>();
|
||||
List<uint> targetModeIdsToChange = new List<uint>();
|
||||
List<uint> targetIdsFound = new List<uint>();
|
||||
@ -432,7 +485,11 @@ namespace DisplayMagicianShared.Windows
|
||||
if (windowsDisplayConfig.DisplaySources.ContainsKey(sourceInfo.ViewGdiDeviceName))
|
||||
{
|
||||
// We already have at least one display using this source, so we need to add the other cloned display to the existing list
|
||||
windowsDisplayConfig.DisplaySources[sourceInfo.ViewGdiDeviceName].Add(paths[i].SourceInfo.Id);
|
||||
DISPLAY_SOURCE ds = new DISPLAY_SOURCE();
|
||||
ds.AdapterId = paths[i].SourceInfo.AdapterId;
|
||||
ds.SourceId = paths[i].SourceInfo.Id;
|
||||
ds.TargetId = paths[i].TargetInfo.Id;
|
||||
windowsDisplayConfig.DisplaySources[sourceInfo.ViewGdiDeviceName].Add(ds);
|
||||
isClonedPath = true;
|
||||
isClonedProfile = true;
|
||||
windowsDisplayConfig.IsCloned = true;
|
||||
@ -440,9 +497,13 @@ namespace DisplayMagicianShared.Windows
|
||||
else
|
||||
{
|
||||
// This is the first display to use this source
|
||||
List<uint> sourceIds = new List<uint>();
|
||||
sourceIds.Add(paths[i].SourceInfo.Id);
|
||||
windowsDisplayConfig.DisplaySources.Add(sourceInfo.ViewGdiDeviceName, sourceIds);
|
||||
List<DISPLAY_SOURCE> sources = new List<DISPLAY_SOURCE>();
|
||||
DISPLAY_SOURCE ds = new DISPLAY_SOURCE();
|
||||
ds.AdapterId = paths[i].SourceInfo.AdapterId;
|
||||
ds.SourceId = paths[i].SourceInfo.Id;
|
||||
ds.TargetId = paths[i].TargetInfo.Id;
|
||||
sources.Add(ds);
|
||||
windowsDisplayConfig.DisplaySources.Add(sourceInfo.ViewGdiDeviceName, sources);
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Display Source {sourceInfo.ViewGdiDeviceName} for source {paths[i].SourceInfo.Id}.");
|
||||
@ -618,33 +679,58 @@ namespace DisplayMagicianShared.Windows
|
||||
modes[i].Id = targetIdMap[modes[i].Id];
|
||||
}
|
||||
}
|
||||
|
||||
// And then we need to go through the list of display sources and patch the 'cloned' displays with a real display ID so the display layout is right in cloned displays
|
||||
for (int i = 0; i < windowsDisplayConfig.DisplaySources.Count; i++)
|
||||
{
|
||||
string key = windowsDisplayConfig.DisplaySources.ElementAt(i).Key;
|
||||
DISPLAY_SOURCE[] dsList = windowsDisplayConfig.DisplaySources.ElementAt(i).Value.ToArray();
|
||||
for (int j = 0; j < dsList.Length; j++)
|
||||
{
|
||||
// We only change the ids that match in InfoType for target displays
|
||||
if (targetIdMap.ContainsKey(dsList[j].TargetId))
|
||||
{
|
||||
// Patch the cloned ids with a real working one!
|
||||
dsList[j].TargetId = targetIdMap[dsList[j].TargetId];
|
||||
|
||||
}
|
||||
}
|
||||
windowsDisplayConfig.DisplaySources[key] = dsList.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = new List<TaskBarStuckRectangle>();
|
||||
foreach (var displayId in windowsDisplayConfig.DisplayIdentifiers)
|
||||
// Now we need to find the DevicePaths for the DisplaySources (as at this point the cloned display sources have been corrected)
|
||||
for (int i = 0; i < windowsDisplayConfig.DisplaySources.Count; i++)
|
||||
{
|
||||
// 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 key = windowsDisplayConfig.DisplaySources.ElementAt(i).Key;
|
||||
DISPLAY_SOURCE[] dsList = windowsDisplayConfig.DisplaySources.ElementAt(i).Value.ToArray();
|
||||
for (int j = 0; j < dsList.Length; j++)
|
||||
{
|
||||
string devicePath = match.Groups[1].Value;
|
||||
TaskBarStuckRectangle taskBarStuckRectangle = new TaskBarStuckRectangle(devicePath);
|
||||
taskBarStuckRectangles.Add(taskBarStuckRectangle);
|
||||
// get display target name
|
||||
var targetInfo = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
|
||||
targetInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
|
||||
targetInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_TARGET_DEVICE_NAME>();
|
||||
targetInfo.Header.AdapterId = dsList[j].AdapterId;
|
||||
targetInfo.Header.Id = dsList[j].TargetId;
|
||||
err = CCDImport.DisplayConfigGetDeviceInfo(ref targetInfo);
|
||||
if (err == WIN32STATUS.ERROR_SUCCESS)
|
||||
{
|
||||
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Successfully got the target info from {dsList[j].TargetId}.");
|
||||
dsList[j].DevicePath = targetInfo.MonitorDevicePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: We were unable to figure out the DevicePath for the '{displayId}' display identifier.");
|
||||
SharedLogger.logger.Warn($"WinLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{dsList[j].TargetId}");
|
||||
}
|
||||
}
|
||||
windowsDisplayConfig.DisplaySources[key] = dsList.ToList();
|
||||
}
|
||||
|
||||
}
|
||||
// And we get the Main Screen taskbar too
|
||||
TaskBarStuckRectangle mainTaskBarStuckRectangle = new TaskBarStuckRectangle("Settings");
|
||||
taskBarStuckRectangles.Add(mainTaskBarStuckRectangle);
|
||||
|
||||
Dictionary<string, TaskBarLayout> taskBarStuckRectangles = new Dictionary<string, TaskBarLayout>();
|
||||
|
||||
// Now attempt to get the windows taskbar location for each display
|
||||
taskBarStuckRectangles = TaskBarLayout.GetAllCurrentTaskBarLayouts(windowsDisplayConfig.DisplaySources);
|
||||
|
||||
// Now we try to get the taskbar settings too
|
||||
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get the Windows Taskbar settings.");
|
||||
@ -655,7 +741,6 @@ namespace DisplayMagicianShared.Windows
|
||||
windowsDisplayConfig.DisplayConfigModes = modes;
|
||||
windowsDisplayConfig.GdiDisplaySettings = GetGdiDisplaySettings();
|
||||
windowsDisplayConfig.TaskBarLayout = taskBarStuckRectangles;
|
||||
//windowsDisplayConfig.OriginalTaskBarLayout = new List<TaskBarStuckRectangle>(taskBarStuckRectangles);
|
||||
windowsDisplayConfig.TaskBarSettings = taskBarSettings;
|
||||
|
||||
return windowsDisplayConfig;
|
||||
@ -1380,36 +1465,65 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
|
||||
|
||||
// NOTE: I have disabled the TaskBar setting logic for now due to errors I cannot fix in this code.
|
||||
// WinLibrary will still track the location of the taskbars, but won't actually set them as the setting of the taskbars doesnt work at the moment.
|
||||
// I hope to eventually fix this code, but I don't want to hold up a new DisplayMagician release while troubleshooting this.
|
||||
/*
|
||||
// Now set the taskbar position for each screen
|
||||
if (displayConfig.TaskBarLayout.Count > 0)
|
||||
if (displayConfig.TaskBarLayout.Count > 0 && allWindowsDisplayConfig.TaskBarLayout.Count > 0)
|
||||
{
|
||||
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Setting the taskbar layout.");
|
||||
foreach (TaskBarStuckRectangle tbsr in displayConfig.TaskBarLayout)
|
||||
foreach (var tbrDictEntry in displayConfig.TaskBarLayout)
|
||||
{
|
||||
if (tbsr.Version >= 2 && tbsr.Version <= 3)
|
||||
// Look up the monitor location of the current monitor and find the matching taskbar location in the taskbar settings
|
||||
if (allWindowsDisplayConfig.TaskBarLayout.ContainsKey(tbrDictEntry.Key))
|
||||
{
|
||||
// Write the settings to registry
|
||||
tbsr.WriteToRegistry();
|
||||
|
||||
if (tbsr.MainScreen)
|
||||
// check the current monitor taskbar location
|
||||
// if the current monitor location is the same as the monitor we want to set then
|
||||
TaskBarLayout currentLayout = displayConfig.TaskBarLayout[tbrDictEntry.Key];
|
||||
TaskBarLayout wantedLayout = allWindowsDisplayConfig.TaskBarLayout[tbrDictEntry.Key];
|
||||
if (currentLayout.Equals(wantedLayout))
|
||||
{
|
||||
TaskBarStuckRectangle.RepositionMainTaskBar(tbsr.Edge);
|
||||
}
|
||||
|
||||
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Display {tbrDictEntry.Key} ({tbrDictEntry.Value.RegKeyValue}) has the taskbar with the correct position, size and settings, so no need to move it");
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Unable to set the {tbsr.DevicePath} TaskBarStuckRectangle registry settings as the version isn't v2 or v3!");
|
||||
// if the current monitor taskbar location is not where we want it then
|
||||
// move the taskbar manually
|
||||
TaskBarLayout tbr = tbrDictEntry.Value;
|
||||
tbr.MoveTaskBar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tell Windows to refresh the Other Windows Taskbars if needed
|
||||
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
|
||||
if (displayConfig.TaskBarLayout.Count > 1)
|
||||
else
|
||||
{
|
||||
TaskBarStuckRectangle.RepositionSecondaryTaskBars();
|
||||
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Display {tbrDictEntry.Key} ({tbrDictEntry.Value.RegKeyValue}) is not currently in use, so cannot set any taskbars on it!");
|
||||
}
|
||||
}
|
||||
|
||||
// This will actually move the taskbars by forcing Explorer to read from registry key
|
||||
/*RestartManagerSession.RestartExplorer();
|
||||
Process[] explorers = Process.GetProcessesByName("Explorer");
|
||||
for (int i = 0; i < explorers.Length; i++)
|
||||
{
|
||||
kill
|
||||
}
|
||||
// Enum all the monitors
|
||||
//List<MONITORINFOEX> currentMonitors = Utils.EnumMonitors();
|
||||
// Go through each monitor
|
||||
//foreach (MONITORINFOEX mi in currentMonitors)
|
||||
//{
|
||||
// Look up the monitor location of the current monitor and find the matching taskbar location in the taskbar settings
|
||||
//if (current)
|
||||
// check the current monitor taskbar location
|
||||
// if the current monitor location is the same as the monitor we want to set then
|
||||
// if the current monitor taskbar location where we want it then
|
||||
// move the taskbar manually
|
||||
// Find the registry key for the monitor we are modifying
|
||||
// save the taskbar position for the monitor in registry
|
||||
// else
|
||||
// log the fact that the monitor is in the right place so skipping moving it
|
||||
// if we didn't find a taskbar location for this monitor
|
||||
// log the fact that the taskbar location wasnt foound for this monitor
|
||||
//}
|
||||
|
||||
}
|
||||
else
|
||||
@ -1437,7 +1551,7 @@ namespace DisplayMagicianShared.Windows
|
||||
{
|
||||
// The settings are the same, so we should skip applying them
|
||||
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The current taskbar settings are the same as the one's we want, so skipping setting them!");
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1960,6 +2074,117 @@ namespace DisplayMagicianShared.Windows
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static bool RepositionMainTaskBar(TaskBarEdge edge)
|
||||
{
|
||||
// Tell Windows to refresh the Main Screen Windows Taskbar
|
||||
// Find the "Shell_TrayWnd" window
|
||||
IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
|
||||
IntPtr startButtonHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "Start", null);
|
||||
IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
|
||||
IntPtr rebarWindowHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "ReBarWindow32", null);
|
||||
IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
|
||||
IntPtr trayDesktopShowButtonHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "TrayShowDesktopButtonWClass", null);
|
||||
IntPtr trayInputIndicatorHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "TrayInputIndicatorWClass", null);
|
||||
|
||||
// Send messages
|
||||
// Send the "TrayNotifyWnd" window a WM_USER+13 (0x040D) message with a wParameter of 0x0 and a lParameter of the position (e.g. 0x0000 for left, 0x0001 for top, 0x0002 for right and 0x0003 for bottom)
|
||||
Utils.SendMessage(systemTrayHandle, Utils.WM_USER_13, IntPtr.Zero, taskBarPositionBuffer);
|
||||
Utils.SendMessage(systemTrayHandle, Utils.WM_USER_100, (IntPtr)0x3e, (IntPtr)0x21c);
|
||||
Utils.SendMessage(systemTrayHandle, Utils.WM_THEMECHANGED, (IntPtr)0xffffffffffffffff, (IntPtr)0x000000008000001);
|
||||
// Next, send the "TrayShowDesktopButtonWClass" window a WM_USER+13 (0x040D) message with a wParameter of 0x0 and a lParameter of the position (e.g. 0x0000 for left, 0x0001 for top, 0x0002 for right and 0x0003 for bottom)
|
||||
Utils.SendMessage(trayDesktopShowButtonHandle, Utils.WM_USER_13, IntPtr.Zero, taskBarPositionBuffer);
|
||||
Utils.SendMessage(startButtonHandle, Utils.WM_USER_440, (IntPtr)0x0, (IntPtr)0x0);
|
||||
Utils.SendMessage(systemTrayHandle, Utils.WM_USER_1, (IntPtr)0x0, (IntPtr)0x0);
|
||||
Utils.SendMessage(systemTrayContainerHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
Utils.PostMessage(systemTrayHandle, Utils.WM_SETTINGCHANGE, Utils.SPI_SETWORKAREA, Utils.NULL);
|
||||
Utils.SendMessage(systemTrayContainerHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
Utils.SendMessage(rebarWindowHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
//Utils.SendMessage(trayInputIndicatorHandle, Utils.WM_USER_100, (IntPtr)0x3e, (IntPtr)0x21c);
|
||||
//Utils.SendMessage(systemTrayHandle, Utils.WM_USER_1, (IntPtr)0x0, (IntPtr)0x0);
|
||||
// Move all the taskbars to this location
|
||||
//Utils.SendMessage(systemTrayContainerHandle, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
|
||||
//Utils.SendMessage(systemTrayContainerHandle, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RepositionAllTaskBars(TaskBarEdge edge)
|
||||
{
|
||||
// Tell Windows to refresh the Main Screen Windows Taskbar
|
||||
// Find the "Shell_TrayWnd" window
|
||||
IntPtr mainToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
|
||||
// Send the "Shell_TrayWnd" window a WM_USER_REFRESHTASKBAR with a wParameter of 0006 and a lParameter of the position (e.g. 0000 for left, 0001 for top, 0002 for right and 0003 for bottom)
|
||||
IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
|
||||
Utils.SendMessage(mainToolBarHWnd, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RepositionSecondaryTaskBars()
|
||||
{
|
||||
// Tell Windows to refresh the Other Windows Taskbars if needed
|
||||
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Find the next "Shell_SecondaryTrayWnd" window
|
||||
IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
|
||||
if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
|
||||
{
|
||||
// No more windows taskbars to notify
|
||||
break;
|
||||
}
|
||||
// Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
|
||||
Utils.SendMessage(lastTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
||||
lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void RefreshTrayArea()
|
||||
{
|
||||
// Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "Notification Area" containing the visible notification area icons (windows 7 version)
|
||||
IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
|
||||
IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
|
||||
IntPtr sysPagerHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
|
||||
IntPtr notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
|
||||
// If the visible notification area icons (Windows 7 aren't found, then we're on a later version of windows, and we need to look for different window names
|
||||
if (notificationAreaHandle == IntPtr.Zero)
|
||||
{
|
||||
// Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "User Promoted Notification Area" containing the visible notification area icons (windows 10+ version)
|
||||
notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
|
||||
// Also attempt to find the NotifyIconOverflowWindow -> "Overflow Notification Area' window which is the hidden windoww that notification icons live when they are
|
||||
// too numberous or are hidden by the user.
|
||||
IntPtr notifyIconOverflowWindowHandle = Utils.FindWindow("NotifyIconOverflowWindow", null);
|
||||
IntPtr overflowNotificationAreaHandle = Utils.FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
|
||||
// Fool the "Overflow Notification Area' window into thinking the mouse is moving over it
|
||||
// which will force windows to refresh the "Overflow Notification Area' window and remove old icons.
|
||||
RefreshTrayArea(overflowNotificationAreaHandle);
|
||||
notifyIconOverflowWindowHandle = IntPtr.Zero;
|
||||
overflowNotificationAreaHandle = IntPtr.Zero;
|
||||
}
|
||||
// Fool the "Notification Area" or "User Promoted Notification Area" window (depends on the version of windows) into thinking the mouse is moving over it
|
||||
// which will force windows to refresh the "Notification Area" or "User Promoted Notification Area" window and remove old icons.
|
||||
RefreshTrayArea(notificationAreaHandle);
|
||||
systemTrayContainerHandle = IntPtr.Zero;
|
||||
systemTrayHandle = IntPtr.Zero;
|
||||
sysPagerHandle = IntPtr.Zero;
|
||||
notificationAreaHandle = IntPtr.Zero;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void RefreshTrayArea(IntPtr windowHandle)
|
||||
{
|
||||
// Moves the mouse around within the window area of the supplied window
|
||||
RECT rect;
|
||||
Utils.GetClientRect(windowHandle, out rect);
|
||||
for (var x = 0; x < rect.right; x += 5)
|
||||
for (var y = 0; y < rect.bottom; y += 5)
|
||||
Utils.SendMessage(windowHandle, Utils.WM_MOUSEMOVE, 0, (y << 16) + x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[global::System.Serializable]
|
||||
|
Loading…
Reference in New Issue
Block a user