Made display changes reliable

This commit is contained in:
Terry MacDonald 2022-02-12 09:18:03 +13:00
parent 963b267158
commit 87f62aa322
14 changed files with 233 additions and 121 deletions

View File

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

View File

@ -1922,11 +1922,12 @@ namespace DisplayMagician
// Shutdown the processes
ProcessUtils.StopProcess(startProgramsToStop);
// Refresh the system tray / notification tray area to clean out any applications we stopped
DisplayMagicianShared.Windows.TaskBarStuckRectangle.RefreshTrayArea();
// Refresh the system tray / notification tray area to clean out any applications we stopped
DisplayMagicianShared.Windows.WinLibrary.RefreshTrayArea();
}
// Change Audio Device back (if one specified)
if (activeAudioDevices.Count > 0)
{

View File

@ -289,6 +289,7 @@ namespace DisplayMagician.UIForms
this.lbl_save_profile.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.lbl_save_profile.BackColor = System.Drawing.Color.Brown;
this.lbl_save_profile.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_save_profile.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.lbl_save_profile.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_save_profile.ForeColor = System.Drawing.Color.White;
this.lbl_save_profile.ImeMode = System.Windows.Forms.ImeMode.NoControl;

View File

@ -518,9 +518,13 @@ namespace DisplayMagician.UIForms
protected override void WndProc(ref Message m)
{
const int WM_DISPLAYCHANGE = 0x007E;
const int WM_SETTINGCHANGE = 0x001A;
const int WM_DEVICECHANGE = 0x0219;
switch (m.Msg)
{
case WM_DEVICECHANGE:
case WM_SETTINGCHANGE:
case WM_DISPLAYCHANGE:
btn_view_current.PerformClick();
break;

View File

@ -160,7 +160,7 @@
<value>248, 17</value>
</metadata>
<data name="lbl_save_profile.Text" xml:space="preserve">
<value>Setup your display layout in NVIDIA Control Panel, AMD Radeon Adrenaline or Windows Display Settings, then return to DisplayMagician and click 'Save' to store this Display Profile for later. Click the Help button for step-by-step instructions.</value>
<value>Setup your display layout in NVIDIA Control Panel, AMD Radeon Adrenaline or Windows Display Settings, then return to DisplayMagician and click 'Save' to store this Display Profile for later use. Taskbar changes will show up after a few seconds.</value>
</data>
<metadata name="dialog_save.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>358, 17</value>

View File

@ -9,7 +9,6 @@ using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using DisplayMagicianShared.Windows;
namespace DisplayMagician.UIForms
{
@ -117,7 +116,7 @@ namespace DisplayMagician.UIForms
if (tbsr.MainScreen)
{
TaskBarStuckRectangle.RepositionMainTaskBar(taskbarForcedEdge);
WinLibrary.RepositionMainTaskBar(taskbarForcedEdge);
}
}
@ -132,7 +131,7 @@ namespace DisplayMagician.UIForms
{
SharedLogger.logger.Trace($"ProfileToolsForm/btn_apply_Click: No taskbar layout in display profile so skipping setting it!");
}
TaskBarStuckRectangle.RepositionSecondaryTaskBars();
WinLibrary.RepositionSecondaryTaskBars();
// Now set the option to completed.
DialogResult = DialogResult.OK;

View File

@ -318,6 +318,7 @@ namespace DisplayMagicianShared.AMD
// so that we won't break json.net when we save a default config
myDefaultConfig.AdapterConfigs = new List<AMD_ADAPTER_CONFIG>();
myDefaultConfig.SlsConfig.IsSlsEnabled = false;
myDefaultConfig.SlsConfig.SLSMapConfigs = new List<AMD_SLSMAP_CONFIG>();
myDefaultConfig.SlsConfig.SLSEnabledDisplayTargets = new List<ADL_MODE>();
myDefaultConfig.DisplayMaps = new List<ADL_DISPLAY_MAP>();
@ -353,13 +354,7 @@ namespace DisplayMagicianShared.AMD
private AMD_DISPLAY_CONFIG GetAMDDisplayConfig(bool allDisplays = false)
{
AMD_DISPLAY_CONFIG myDisplayConfig = new AMD_DISPLAY_CONFIG();
myDisplayConfig.AdapterConfigs = new List<AMD_ADAPTER_CONFIG>();
// We set up the default for this display config as SLS disabled
// (We will change this later if it turns out we're using SLS)
myDisplayConfig.SlsConfig.IsSlsEnabled = false;
myDisplayConfig.SlsConfig.SLSEnabledDisplayTargets = new List<ADL_MODE>();
AMD_DISPLAY_CONFIG myDisplayConfig = CreateDefaultConfig();
if (_initialised)
{

View File

@ -59,8 +59,9 @@ namespace DisplayMagicianShared.NVIDIA
public override bool Equals(object obj) => obj is NVIDIA_HDR_CONFIG other && this.Equals(other);
public bool Equals(NVIDIA_HDR_CONFIG other)
=> HdrCapabilities.SequenceEqual(other.HdrCapabilities) &&
HdrColorData.SequenceEqual(other.HdrColorData) &&
IsNvHdrEnabled == other.IsNvHdrEnabled;
HdrColorData.SequenceEqual(other.HdrColorData) &&
IsNvHdrEnabled == other.IsNvHdrEnabled;
public override int GetHashCode()
{
@ -124,12 +125,13 @@ namespace DisplayMagicianShared.NVIDIA
public override bool Equals(object obj) => obj is NVIDIA_DISPLAY_CONFIG other && this.Equals(other);
public bool Equals(NVIDIA_DISPLAY_CONFIG other)
=> MosaicConfig.Equals(other.MosaicConfig) &&
HdrConfig.Equals(other.HdrConfig) &&
=> HdrConfig.Equals(other.HdrConfig) &&
MosaicConfig.Equals(other.MosaicConfig) &&
ColorConfig.Equals(other.ColorConfig) &&
CustomDisplays.SequenceEqual(other.CustomDisplays) &&
DisplayConfigs.SequenceEqual(other.DisplayConfigs) &&
DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers);
public override int GetHashCode()
{
@ -282,6 +284,7 @@ namespace DisplayMagicianShared.NVIDIA
// Fill in the minimal amount we need to avoid null references
// so that we won't break json.net when we save a default config
myDefaultConfig.MosaicConfig.IsMosaicEnabled = false;
myDefaultConfig.MosaicConfig.MosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V2[0];
myDefaultConfig.MosaicConfig.MosaicViewports = new List<NV_RECT[]>();
myDefaultConfig.HdrConfig.HdrCapabilities = new Dictionary<string, NV_HDR_CAPABILITIES_V2>();
@ -320,7 +323,7 @@ namespace DisplayMagicianShared.NVIDIA
private NVIDIA_DISPLAY_CONFIG GetNVIDIADisplayConfig(bool allDisplays = false)
{
NVIDIA_DISPLAY_CONFIG myDisplayConfig = new NVIDIA_DISPLAY_CONFIG();
NVIDIA_DISPLAY_CONFIG myDisplayConfig = CreateDefaultConfig();
if (_initialised)
{

View File

@ -350,12 +350,19 @@ namespace DisplayMagicianShared
{
get
{
if (_profileShortcutBitmap != null)
return _profileShortcutBitmap;
if (ProfileRepository.ProfilesLoaded)
{
if (_profileShortcutBitmap != null)
return _profileShortcutBitmap;
else
{
_profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap();
return _profileShortcutBitmap;
}
}
else
{
_profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap();
return _profileShortcutBitmap;
return null;
}
}
set
@ -1280,18 +1287,7 @@ namespace DisplayMagicianShared
screen.IsSpanned = false;
screen.Colour = normalScreenColor; // this is the default unless overridden by the primary screen
screen.IsClone = false;
screen.ClonedCopies = 0;
try
{
screen.TaskBarEdge = _windowsDisplayConfig.TaskBarLayout.First(tbr => tbr.DevicePath.Contains($"UID{targetId}")).Edge;
SharedLogger.logger.Trace($"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen.");
}
catch (Exception ex)
{
// Guess that it is at the bottom (90% correct)
SharedLogger.logger.Error(ex, $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}");
screen.TaskBarEdge = TaskBarStuckRectangle.TaskBarEdge.Bottom;
}
screen.ClonedCopies = 0;
foreach (var displaySource in _windowsDisplayConfig.DisplaySources)
{
if (displaySource.Value.Contains(sourceId))
@ -1357,6 +1353,39 @@ namespace DisplayMagicianShared
}
}
// Now we try to set the taskbar positions
if (screen.IsPrimary)
{
// If the screen is the primary screen, then we check if we need to use the StuckRect 'Settings' reg keys
// rather than the MMStuckRect reg keys
try
{
screen.TaskBarEdge = _windowsDisplayConfig.TaskBarLayout.First(tb => tb.DevicePath.Contains("Settings")).Edge;
SharedLogger.logger.Trace($"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on the primary display {targetId} is on the {screen.TaskBarEdge } of the screen.");
}
catch (Exception ex)
{
// Guess that it is at the bottom (90% correct)
SharedLogger.logger.Error(ex, $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on primary display {targetId}");
screen.TaskBarEdge = TaskBarStuckRectangle.TaskBarEdge.Bottom;
}
}
else
{
try
{
screen.TaskBarEdge = _windowsDisplayConfig.TaskBarLayout.First(tbr => tbr.DevicePath.Contains($"UID{targetId}")).Edge;
SharedLogger.logger.Trace($"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen.");
}
catch (Exception ex)
{
// Guess that it is at the bottom (90% correct)
SharedLogger.logger.Error(ex, $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}");
screen.TaskBarEdge = TaskBarStuckRectangle.TaskBarEdge.Bottom;
}
}
SharedLogger.logger.Trace($"ProfileItem/GetWindowsScreenPositions: Added a new Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}.");
_screens.Add(screen);

View File

@ -639,6 +639,10 @@ namespace DisplayMagicianShared
SharedLogger.logger.Trace($"ProfileRepository/UpdateActiveProfile: Paused updating display settings for {totalDelay} milliseconds.");
}
// Force explorer to update the TaskBar settings just in case they were moved
//ShellHelper.TellShellToWriteSettings();
//WinLibrary.RefreshTaskBars();
profile.CreateProfileFromCurrentDisplaySettings();
if (_profilesLoaded && _allProfiles.Count > 0)

View File

@ -42,7 +42,7 @@ namespace DisplayMagicianShared
return null;
}
public static async Task IntrigueShellToWriteSettings()
public static async Task TellShellToWriteSettings()
{
try
{

View File

@ -349,7 +349,12 @@ namespace DisplayMagicianShared
public const int WM_SETTINGCHANGE = 0x001a;
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_440 = 0x05B8;
public const int WM_USER_92 = 0x045C;
public const int WM_USER_1 = 0x0401;
public const int WM_USER_100 = 0x0464;
public const int wParam_SHELLTRAY = 0x00000006;
}

View File

@ -112,6 +112,9 @@ namespace DisplayMagicianShared.Windows
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.");
// If we get here then we're done and don't need to continue with the rest of the code.
return;
}
else
{
@ -119,6 +122,14 @@ namespace DisplayMagicianShared.Windows
}
}
}
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");
}
if (!foundDevicePath)
@ -180,6 +191,23 @@ namespace DisplayMagicianShared.Windows
}
}
}
else
{
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A StuckRect entry was found, but the version of the field is wrong.");
}
}
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.");
throw new TaskBarStuckRectangleException("A StuckRect entry was NOT found. This means we're unable to get the taskbar location, an unable to return a sensible TaskBarStuckRectangle object.");
//SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A StuckRect entry was NOT found. This means we're unable to get the taskbar location, so we'll return a default object instead.");
/*Version = 3;
DPI = 0;
Edge = TaskBarEdge.Bottom;
Location = Rectangle.Empty;
MinSize = new Size(48,48);
Options = 0;
Rows = 1;*/
}
}
}
@ -470,79 +498,7 @@ namespace DisplayMagicianShared.Windows
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)
{
@ -558,4 +514,15 @@ namespace DisplayMagicianShared.Windows
}
*/
}
[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) { }
}
}

View File

@ -9,6 +9,7 @@ using System.IO;
using System.ComponentModel;
using Microsoft.Win32;
using System.Threading.Tasks;
using static DisplayMagicianShared.Windows.TaskBarStuckRectangle;
namespace DisplayMagicianShared.Windows
{
@ -320,6 +321,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,13 +373,7 @@ 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();
@ -633,6 +632,7 @@ namespace DisplayMagicianShared.Windows
if (match.Success)
{
string devicePath = match.Groups[1].Value;
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found devicePath {devicePath} from the display identifier {displayId}.");
TaskBarStuckRectangle taskBarStuckRectangle = new TaskBarStuckRectangle(devicePath);
taskBarStuckRectangles.Add(taskBarStuckRectangle);
}
@ -1393,7 +1393,7 @@ namespace DisplayMagicianShared.Windows
if (tbsr.MainScreen)
{
TaskBarStuckRectangle.RepositionMainTaskBar(tbsr.Edge);
RepositionMainTaskBar(tbsr.Edge);
}
}
@ -1408,7 +1408,7 @@ namespace DisplayMagicianShared.Windows
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
if (displayConfig.TaskBarLayout.Count > 1)
{
TaskBarStuckRectangle.RepositionSecondaryTaskBars();
RepositionSecondaryTaskBars();
}
}
@ -1958,7 +1958,111 @@ namespace DisplayMagicianShared.Windows
{
return false;
}
}
}
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 bool RefreshTaskBars()
{
// Tell Windows to refresh the Main Screen Windows Taskbar registry settings by telling Explorer to update.
// Find the "Shell_TrayWnd" window
IntPtr mainToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
Utils.SendMessage(mainToolBarHWnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
// 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;
}
//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;
}
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);
}
}