Closed WizardCM closed 7 years ago
Yeah, the HWND is not the same anymore when you restart Explorer. The app would need to check if the window exists before applying settings in the while(true)
loop and if it doesn't, try to find the new one
You can check using IsWindow.
I don't re-check the HWND in the loop, since that would drive CPU usage up pretty high. I'll have it look every 10 or so seconds, though. Once I get a chance to dive back in to coding I'll get this done!
If you register for the TaskbarCreated message (and probably call ChangeWindowMessageFilterEx
to ensure the message gets through even if TT happens to be running elevated), you can get Explorer to tell your application that the taskbar has been recreated instead of checking for it yourself.
That sounds cool, I'll look into it. If you'd like to make the change yourself, go for it!
I don't know C#, sorry - I'd be at a loss trying to work out how to safely synchronise receiving the message with the HWND(s) the SetWindowCompositionAttribute
loop is looking at...
Looks like I'll have to create a C++ DLL to do this anyway. Urgh. I'm not great in C++.
I don't think that would be required; even the AutoHotkey script I have running in the background on my system listens for the same message. P/Invoking RegisterWindowMessage
and then listening for the message returned by that function using something like this would probably be enough.
(Apologies for half-heartedly bringing this up when I don't know C#, but I figured sharing the idea was better than nothing...)
I was thinking I could use a couple of different techniques to try and capture the message, but it might be too low-level to reach. I'm going to try doing it in C# before going to C++, believe me. I'll do some research on the topic and see what comes up.
Alright, this has been enough to reaffirm my love for C and my already-heavily-beloved AutoHotkey, but here's something basic that does, indeed, listen for that message. I'm doing the lazy thing and just pasting a diff because this is unlikely to get applied (if at all) as-is:
I'm copying and pasting code from elsewhere in the file. The Proper Thing™ to do would be of course to put the duplicated stuff into its own function
I also got rid of the loop that keeps checking if the accent colour has changed if said option is enabled, and replaced it with a check for the WM_DWMCOLORIZATIONCOLORCHANGED
message but:
I suspect WPF may have a native way to detect this instead of listening for the message directly
in the process I forgot to add code that sets accentPolicy.GradientColor initially if the option is enabled so it only takes effect once WM_DWMCOLORIZATIONCOLORCHANGED
has been received. Oops.
While it is admittedly unlikely, you may want to consider P/Invoking ChangeWindowMessageFilterEx
on the messages to protect yourself against users who may think that this needs to be run elevated and then post issues saying Explorer-restart detection isn't working/the accent colour applied to the taskbar isn't changing.
diff --git a/TaskbarTool/MainWindow.xaml.cs b/TaskbarTool/MainWindow.xaml.cs
index a9d80e1..2a5c759 100644
--- a/TaskbarTool/MainWindow.xaml.cs
+++ b/TaskbarTool/MainWindow.xaml.cs
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Interop;
using System.Windows.Media;
namespace TaskbarTool
@@ -25,6 +26,10 @@ namespace TaskbarTool
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ static extern uint RegisterWindowMessage(string msgString);
+
#endregion Invokes
#region Enums
@@ -85,6 +90,8 @@ namespace TaskbarTool
static AccentPolicy accentPolicy = new AccentPolicy();
static System.Windows.Forms.NotifyIcon SysTrayIcon;
ContextMenu SysTrayContextMenu;
+ private static readonly uint WM_TASKBARCREATED = RegisterWindowMessage("TaskbarCreated");
+ private const uint WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
#endregion Declarations
#region Initializations
@@ -115,6 +122,34 @@ namespace TaskbarTool
base.OnStateChanged(e);
}
+ protected override void OnSourceInitialized(EventArgs e)
+ {
+ base.OnSourceInitialized(e);
+
+ IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
+ HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
+ mainWindowSrc.AddHook(WndProc);
+ }
+
+ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+ {
+ if (msg == WM_TASKBARCREATED)
+ {
+ RunApplyTask = false;
+ ApplyTask?.Wait(100);
+ RunApplyTask = true;
+ ApplyTask = new Task(() => ApplyToAllTaskbars());
+ ApplyTask.Start();
+
+ handled = true;
+ } else if (msg == WM_DWMCOLORIZATIONCOLORCHANGED && RunAccentTask) {
+ accentPolicy.GradientColor = WindowsAccentColor.GetColorAsInt(); // TODO: use colour from wParam
+ handled = true;
+ }
+
+ return IntPtr.Zero;
+ }
+
private void PopulateComboBoxes()
{
AccentStateComboBox.ItemsSource = Enum.GetValues(typeof(AccentState)).Cast<AccentState>();
@@ -222,14 +257,6 @@ namespace TaskbarTool
Marshal.FreeHGlobal(policyPtr);
}
- private void GetWindowsAccentColorLoop()
- {
- while (RunAccentTask) {
- accentPolicy.GradientColor = WindowsAccentColor.GetColorAsInt();
- Thread.Sleep(900);
- }
- }
-
#endregion Functions
#region Control Handles
@@ -283,8 +310,6 @@ namespace TaskbarTool
{
GradientColorPicker.IsEnabled = false;
RunAccentTask = true;
- WindowsAccentColorTask = new Task(() => GetWindowsAccentColorLoop());
- WindowsAccentColorTask.Start();
}
else
{
I've found a way to detect new processes using WMI, but it requires elevation. It's a pretty simple approach, but I'm not sure if users will want to run elevated.
I could try the RegisterWindowMessage approach and see how that goes!
but I'm not sure if users will want to run elevated.
I don't see why any user won't run it as elevated if they want the feature they will and if you don't want to give them elevation warning every time they open your program then there is a windows program called task scheduler it will Skip-UAC warning/consent/elevation messages if you set it up user will see the warning message the first time they run your program then they will never see it again there are other methods to skip UAC but first tell me what do you think.
Right now I'm playing with qwerty12's solution. It doesn't require administrator privileges, so it could be the right fix. The reason I don't want to require elevation is that some people might want to use this on a work computer, where permissions are restricted.
some people might want to use this on a work computer, where permissions are restricted.
Okay I didn't thought about that.... see if it work's via qwerty method...
Implemented in v1.0.6.
I still don't know how to use Github properly.
I still don't know how to use Github properly.
you will know with time.
I have a version which doesn't require elevation on my fork of @ethanhs' TranslucentTb.
On 12 Jan. 2017, at 3:31 am, Emily Maxwell notifications@github.com wrote:
Implemented in v1.0.6.
I still don't know how to use Github properly.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.
This one doesn't require elevation! :)
Yeah, @qwerty12's solution is pretty neat.
For an unrelated issue, I had to restart Explorer. When my taskbar returned, it was the default accent colour without the adjustments in TaskbarTools.