Improvements

- Update to .NET 10
- Set actual window title to window name
- Add new way to identify other windows
This commit is contained in:
2026-02-24 17:11:21 -05:00
parent 72ddd0ad88
commit e2236ddc16
11 changed files with 91 additions and 117 deletions

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows7.0</TargetFramework> <TargetFramework>net10.0-windows7.0</TargetFramework>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<RootNamespace>ChrisKaczor.Wpf.Windows.FloatingStatusWindow</RootNamespace> <RootNamespace>ChrisKaczor.Wpf.Windows.FloatingStatusWindow</RootNamespace>
<AssemblyName>ChrisKaczor.Wpf.Windows.FloatingStatusWindow</AssemblyName> <AssemblyName>ChrisKaczor.Wpf.Windows.FloatingStatusWindow</AssemblyName>

View File

@@ -1,5 +1,4 @@
using ChrisKaczor.Wpf.Windows; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Interop; using System.Windows.Interop;
@@ -20,25 +19,23 @@ internal partial class MainWindow
public WindowSettings WindowSettings { get; set; } public WindowSettings WindowSettings { get; set; }
private bool _locked;
public bool Locked public bool Locked
{ {
get => _locked; get;
set set
{ {
_locked = value; field = value;
_windowChrome.CaptionHeight = (_locked ? 0 : WindowCaptionHeight); _windowChrome.CaptionHeight = (field ? 0 : WindowCaptionHeight);
HtmlLabel.Margin = new Thickness(0, (_locked ? 0 : WindowCaptionHeight), 0, 0); HtmlLabel.Margin = new Thickness(0, (field ? 0 : WindowCaptionHeight), 0, 0);
// Show the header border if the window is unlocked // Show the header border if the window is unlocked
HeaderBorder.Visibility = (_locked ? Visibility.Collapsed : Visibility.Visible); HeaderBorder.Visibility = (field ? Visibility.Collapsed : Visibility.Visible);
// Show and enable the window border if the window is unlocked // Show and enable the window border if the window is unlocked
BorderFull.BorderBrush = (_locked ? Brushes.Transparent : SystemColors.ActiveCaptionBrush); BorderFull.BorderBrush = (field ? Brushes.Transparent : SystemColors.ActiveCaptionBrush);
BorderFull.IsEnabled = !_locked; BorderFull.IsEnabled = !field;
LockStateChanged(null, EventArgs.Empty); LockStateChanged(null, EventArgs.Empty);
} }
@@ -85,26 +82,37 @@ internal partial class MainWindow
WindowManager.AllowMessagesThroughFilter(windowHandle); WindowManager.AllowMessagesThroughFilter(windowHandle);
} }
private void SetLocked(bool locked)
{
WindowSettings.Locked = locked;
Locked = locked;
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{ {
if (msg == WindowManager.SetLockMessage) if (msg == WindowManager.SetLockMessage)
{ {
var lockState = (wParam == 1); _dispatcher.InvokeAsync(() => SetLocked(wParam == 1));
_dispatcher.InvokeAsync(() =>
{
WindowSettings.Locked = lockState;
Locked = lockState;
});
handled = true;
return IntPtr.Zero; return IntPtr.Zero;
} }
if (msg != WindowManager.CloseMessage) if (msg == WindowManager.IdentifyMessage)
return base.WndProc(hwnd, msg, wParam, lParam, ref handled); {
handled = true;
return msg;
}
_dispatcher.InvokeAsync(Close); if (msg == WindowManager.CloseMessage)
return IntPtr.Zero; {
_dispatcher.InvokeAsync(Close);
handled = true;
return IntPtr.Zero;
}
return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
} }
protected override void OnLocationChanged(EventArgs e) protected override void OnLocationChanged(EventArgs e)

View File

@@ -1,6 +1,5 @@
using ChrisKaczor.Wpf.Application; using ChrisKaczor.Wpf.Application;
using System; using System;
using System.Windows;
namespace ChrisKaczor.Wpf.Windows.FloatingStatusWindow; namespace ChrisKaczor.Wpf.Windows.FloatingStatusWindow;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading;
namespace ChrisKaczor.Wpf.Windows.FloatingStatusWindow; namespace ChrisKaczor.Wpf.Windows.FloatingStatusWindow;
@@ -19,7 +20,7 @@ public static partial class WindowManager
private static partial void EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); private static partial void EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[LibraryImport("user32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16, EntryPoint = "RegisterWindowMessageW")] [LibraryImport("user32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16, EntryPoint = "RegisterWindowMessageW")]
private static partial uint RegisterWindowMessage(string lpString); private static partial int RegisterWindowMessage(string lpString);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
@@ -27,26 +28,29 @@ public static partial class WindowManager
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowTextLengthW")] [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowTextLengthW")]
private static partial int GetWindowTextLength(IntPtr hWnd); private static partial int GetWindowTextLength(IntPtr hWnd);
[LibraryImport("user32.dll", EntryPoint = "SendMessageW")] [LibraryImport("user32.dll", EntryPoint = "SendMessageW", SetLastError = true)]
private static partial void SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); private static partial IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[LibraryImport("user32.dll", SetLastError = true)] [LibraryImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static partial void ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, ChangeWindowMessageFilterExAction action, IntPtr changeInfo); private static partial void ChangeWindowMessageFilterEx(IntPtr hWnd, int msg, ChangeWindowMessageFilterExAction action, IntPtr changeInfo);
private const string WindowMessageIdentify = "FloatingStatusWindowLibrary_Identify";
private const string WindowMessageSetLock = "FloatingStatusWindowLibrary_SetLock"; private const string WindowMessageSetLock = "FloatingStatusWindowLibrary_SetLock";
private const string WindowMessageClose = "FloatingStatusWindowLibrary_Close"; private const string WindowMessageClose = "FloatingStatusWindowLibrary_Close";
public static uint SetLockMessage { get; set; } public static int IdentifyMessage { get; set; }
public static uint CloseMessage { get; set; } public static int SetLockMessage { get; set; }
public static int CloseMessage { get; set; }
static WindowManager() static WindowManager()
{ {
IdentifyMessage = RegisterWindowMessage(WindowMessageIdentify);
SetLockMessage = RegisterWindowMessage(WindowMessageSetLock); SetLockMessage = RegisterWindowMessage(WindowMessageSetLock);
CloseMessage = RegisterWindowMessage(WindowMessageClose); CloseMessage = RegisterWindowMessage(WindowMessageClose);
} }
private static readonly object WindowLocker = new(); private static readonly Lock WindowLocker = new();
private static List<WindowInformation> _windowList; private static List<WindowInformation> _windowList;
private static IntPtr _excludeHandle; private static IntPtr _excludeHandle;
@@ -61,7 +65,7 @@ public static partial class WindowManager
{ {
lock (WindowLocker) lock (WindowLocker)
{ {
_windowList = new List<WindowInformation>(); _windowList = [];
_excludeHandle = IntPtr.Zero; _excludeHandle = IntPtr.Zero;
EnumWindows(EnumWindowProc, IntPtr.Zero); EnumWindows(EnumWindowProc, IntPtr.Zero);
@@ -74,7 +78,7 @@ public static partial class WindowManager
{ {
lock (WindowLocker) lock (WindowLocker)
{ {
_windowList = new List<WindowInformation>(); _windowList = [];
_excludeHandle = excludeHandle; _excludeHandle = excludeHandle;
EnumWindows(EnumWindowProc, IntPtr.Zero); EnumWindows(EnumWindowProc, IntPtr.Zero);
@@ -94,9 +98,20 @@ public static partial class WindowManager
private static bool EnumWindowProc(IntPtr hWnd, IntPtr lParam) private static bool EnumWindowProc(IntPtr hWnd, IntPtr lParam)
{ {
if (hWnd == _excludeHandle)
return true;
var identifyResult = SendMessage(hWnd, IdentifyMessage, IntPtr.Zero, IntPtr.Zero);
if (identifyResult == IdentifyMessage)
{
_windowList.Add(new WindowInformation(hWnd));
return true;
}
var windowText = GetText(hWnd); var windowText = GetText(hWnd);
if (windowText == "FloatingStatusWindow" && hWnd != _excludeHandle) if (windowText == "FloatingStatusWindow")
_windowList.Add(new WindowInformation(hWnd)); _windowList.Add(new WindowInformation(hWnd));
return true; return true;
@@ -107,12 +122,12 @@ public static partial class WindowManager
var lockState = locked ? 1 : 0; var lockState = locked ? 1 : 0;
foreach (var w in GetWindowList()) foreach (var w in GetWindowList())
SendMessage(w.Handle, SetLockMessage, lockState, IntPtr.Zero); _ = SendMessage(w.Handle, SetLockMessage, lockState, IntPtr.Zero);
} }
public static void CloseAll() public static void CloseAll()
{ {
foreach (var w in GetWindowList()) foreach (var w in GetWindowList())
SendMessage(w.Handle, CloseMessage, IntPtr.Zero, IntPtr.Zero); _ = SendMessage(w.Handle, CloseMessage, IntPtr.Zero, IntPtr.Zero);
} }
} }

View File

@@ -64,6 +64,8 @@ public class WindowSettings : ICloneable
internal void Apply() internal void Apply()
{ {
Window.Title = Name;
// Configure the text label // Configure the text label
HtmlLabel.FontFamily = new FontFamily(FontName); HtmlLabel.FontFamily = new FontFamily(FontName);
HtmlLabel.FontSize = FontSize; HtmlLabel.FontSize = FontSize;
@@ -98,9 +100,9 @@ public class WindowSettings : ICloneable
return new WindowSettings(); return new WindowSettings();
var serializer = new XmlSerializer(typeof(WindowSettings)); var serializer = new XmlSerializer(typeof(WindowSettings));
TextReader textReader = new StringReader(settings); var stringReader = new StringReader(settings);
var windowSettings = (WindowSettings)serializer.Deserialize(textReader); var windowSettings = (WindowSettings)serializer.Deserialize(stringReader);
textReader.Close(); stringReader.Close();
return windowSettings; return windowSettings;
} }
@@ -110,9 +112,9 @@ public class WindowSettings : ICloneable
var builder = new StringBuilder(); var builder = new StringBuilder();
var serializer = new XmlSerializer(typeof(WindowSettings)); var serializer = new XmlSerializer(typeof(WindowSettings));
TextWriter textWriter = new StringWriter(builder); var stringWriter = new StringWriter(builder);
serializer.Serialize(textWriter, this); serializer.Serialize(stringWriter, this);
textWriter.Close(); stringWriter.Close();
return builder.ToString(); return builder.ToString();
} }

View File

@@ -1,6 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Resources; using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Windows; using System.Windows;

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows7.0</TargetFramework> <TargetFramework>net10.0-windows7.0</TargetFramework>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
@@ -14,7 +14,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ChrisKaczor.Wpf.Application.StartWithWindows" Version="1.0.5" /> <PackageReference Include="ChrisKaczor.Wpf.Application.StartWithWindows" Version="1.0.5" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" /> <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -41,36 +41,24 @@ internal class WindowSource1 : IWindowSource, IDisposable
public Guid Id => Guid.Parse("0329D04D-B89B-4FEC-AFD0-4CB972E47FC8"); public Guid Id => Guid.Parse("0329D04D-B89B-4FEC-AFD0-4CB972E47FC8");
public string Name public string Name => "Test Window 1";
{
get { return "Test Window 1"; }
}
public System.Drawing.Icon Icon public System.Drawing.Icon Icon => Properties.Resources.ApplicationIcon;
{
get { return Properties.Resources.ApplicationIcon; }
}
public bool HasSettingsMenu public bool HasSettingsMenu => true;
{
get { return true; }
}
public bool HasAboutMenu => true; public bool HasAboutMenu => true;
public void ShowAbout() public void ShowAbout()
{ {
_floatingStatusWindow.SetText(Assembly.GetEntryAssembly().GetName().Version.ToString()); _floatingStatusWindow.SetText(Assembly.GetEntryAssembly()?.GetName().Version?.ToString());
} }
public void ShowSettings() public void ShowSettings()
{ {
} }
public bool HasRefreshMenu public bool HasRefreshMenu => true;
{
get { return true; }
}
public void Refresh() public void Refresh()
{ {
@@ -78,7 +66,7 @@ internal class WindowSource1 : IWindowSource, IDisposable
public string WindowSettings public string WindowSettings
{ {
get { return Properties.Settings.Default.WindowSettings1; } get => Properties.Settings.Default.WindowSettings1;
set set
{ {
Properties.Settings.Default.WindowSettings1 = value; Properties.Settings.Default.WindowSettings1 = value;

View File

@@ -41,36 +41,24 @@ internal class WindowSource2 : IWindowSource, IDisposable
public Guid Id => Guid.Parse("F42F92BC-D397-497A-8E01-E71D084BEDB6"); public Guid Id => Guid.Parse("F42F92BC-D397-497A-8E01-E71D084BEDB6");
public string Name public string Name => "Test Window 2";
{
get { return "Test Window 2"; }
}
public System.Drawing.Icon Icon public System.Drawing.Icon Icon => Properties.Resources.ApplicationIcon;
{
get { return Properties.Resources.ApplicationIcon; }
}
public bool HasSettingsMenu public bool HasSettingsMenu => true;
{
get { return true; }
}
public bool HasAboutMenu => true; public bool HasAboutMenu => true;
public void ShowAbout() public void ShowAbout()
{ {
_floatingStatusWindow.SetText(Assembly.GetEntryAssembly().GetName().Version.ToString()); _floatingStatusWindow.SetText(Assembly.GetEntryAssembly()?.GetName().Version?.ToString());
} }
public void ShowSettings() public void ShowSettings()
{ {
} }
public bool HasRefreshMenu public bool HasRefreshMenu => true;
{
get { return true; }
}
public void Refresh() public void Refresh()
{ {
@@ -78,7 +66,7 @@ internal class WindowSource2 : IWindowSource, IDisposable
public string WindowSettings public string WindowSettings
{ {
get { return Properties.Settings.Default.WindowSettings2; } get => Properties.Settings.Default.WindowSettings2;
set set
{ {
Properties.Settings.Default.WindowSettings2 = value; Properties.Settings.Default.WindowSettings2 = value;

View File

@@ -41,36 +41,24 @@ internal class WindowSource3 : IWindowSource, IDisposable
public Guid Id => Guid.Parse("CF7466DF-8980-452B-B2FA-290B26204BF2"); public Guid Id => Guid.Parse("CF7466DF-8980-452B-B2FA-290B26204BF2");
public string Name public string Name => "Test Window 3";
{
get { return "Test Window 3"; }
}
public System.Drawing.Icon Icon public System.Drawing.Icon Icon => Properties.Resources.ApplicationIcon;
{
get { return Properties.Resources.ApplicationIcon; }
}
public bool HasSettingsMenu public bool HasSettingsMenu => true;
{
get { return true; }
}
public bool HasAboutMenu => true; public bool HasAboutMenu => true;
public void ShowAbout() public void ShowAbout()
{ {
_floatingStatusWindow.SetText(Assembly.GetEntryAssembly().GetName().Version.ToString()); _floatingStatusWindow.SetText(Assembly.GetEntryAssembly()?.GetName().Version?.ToString());
} }
public void ShowSettings() public void ShowSettings()
{ {
} }
public bool HasRefreshMenu public bool HasRefreshMenu => true;
{
get { return true; }
}
public void Refresh() public void Refresh()
{ {
@@ -78,7 +66,7 @@ internal class WindowSource3 : IWindowSource, IDisposable
public string WindowSettings public string WindowSettings
{ {
get { return Properties.Settings.Default.WindowSettings3; } get => Properties.Settings.Default.WindowSettings3;
set set
{ {
Properties.Settings.Default.WindowSettings3 = value; Properties.Settings.Default.WindowSettings3 = value;

View File

@@ -41,36 +41,24 @@ internal class WindowSource4 : IWindowSource, IDisposable
public Guid Id => Guid.Parse("0DD89F7E-3AD4-4226-8CBD-B75C8EBEEF32"); public Guid Id => Guid.Parse("0DD89F7E-3AD4-4226-8CBD-B75C8EBEEF32");
public string Name public string Name => "Test Window 4";
{
get { return "Test Window 4"; }
}
public System.Drawing.Icon Icon public System.Drawing.Icon Icon => Properties.Resources.ApplicationIcon;
{
get { return Properties.Resources.ApplicationIcon; }
}
public bool HasSettingsMenu public bool HasSettingsMenu => true;
{
get { return true; }
}
public bool HasAboutMenu => true; public bool HasAboutMenu => true;
public void ShowAbout() public void ShowAbout()
{ {
_floatingStatusWindow.SetText(Assembly.GetEntryAssembly().GetName().Version.ToString()); _floatingStatusWindow.SetText(Assembly.GetEntryAssembly()?.GetName().Version?.ToString());
} }
public void ShowSettings() public void ShowSettings()
{ {
} }
public bool HasRefreshMenu public bool HasRefreshMenu => true;
{
get { return true; }
}
public void Refresh() public void Refresh()
{ {
@@ -78,7 +66,7 @@ internal class WindowSource4 : IWindowSource, IDisposable
public string WindowSettings public string WindowSettings
{ {
get { return Properties.Settings.Default.WindowSettings4; } get => Properties.Settings.Default.WindowSettings4;
set set
{ {
Properties.Settings.Default.WindowSettings4 = value; Properties.Settings.Default.WindowSettings4 = value;