Add some WinUI work

This commit is contained in:
Dan Clark
2024-11-17 21:25:27 +00:00
parent b5bf17821c
commit 796ef41e3f
25 changed files with 426 additions and 159 deletions
-1
View File
@@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Interactivity;
using Microsoft.Extensions.DependencyInjection;
using Toolkit.Foundation;
@@ -7,14 +7,14 @@ public class AsyncHandlerInitialization<TMessage, TResponse, THandler>(IServiceP
IInitialization where THandler : class, IAsyncHandler<TMessage, TResponse>
where TMessage : class
{
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, TResponse>>(provider,
async (provider, args) => args.Reply(await provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken)));
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, TResponse>>(provider,
(provider, args) => args.Reply(provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken)));
}
public class AsyncHandlerInitialization<TMessage, THandler>(IServiceProvider provider) :
IInitialization where THandler : class, IAsyncHandler<TMessage>
where TMessage : class
{
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, Unit>>(provider,
async (provider, args) => await provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken));
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, Unit>>(provider,
(provider, args) => provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken));
}
+1 -1
View File
@@ -5,7 +5,7 @@ namespace Toolkit.Foundation;
public class AsyncResponseEventArgs<TMessage, TResponse> :
AsyncRequestMessage<TResponse>
{
public TMessage? Message { get; set; }
public required TMessage Message { get; set; }
public CancellationToken CancellationToken { get; set; }
}
+4 -10
View File
@@ -20,14 +20,8 @@ public class DefaultHostBuilder :
ComponentHostCollection>();
services.AddSingleton<IDisposer, Disposer>();
services.AddSingleton<IMessenger, WeakReferenceMessenger>(_ => WeakReferenceMessenger.Default);
services.AddSingleton<IMessenger, StrongReferenceMessenger>(_ => StrongReferenceMessenger.Default);
//services.AddScoped<SubscriptionCollection>();
//services.AddTransient<IHandlerProvider, HandlerProvider>();
//services.AddScoped<ISubscriber, Subscriber>();
//services.AddTransient<IPublisher, Publisher>();
//services.AddTransient<IMediator, Mediator>();
services.AddTransient<IValidation, Validation>();
services.AddTransient<IValidatorCollection, ValidatorCollection>();
@@ -57,10 +51,10 @@ public class DefaultHostBuilder :
services.AddTransient<IComponentFactory, ComponentFactory>();
services.AddTransient<IComponentScopeProvider, ComponentScopeProvider>();
//services.AddHandler<NavigateHandler>();
//services.AddHandler<NavigateBackHandler>();
services.AddHandler<NavigateEventArgs, NavigateHandler>();
services.AddHandler<NavigateBackEventArgs, NavigateBackHandler>();
//services.AddInitialization<ComponentInitializer>();
services.AddInitialization<ComponentInitializer>();
services.AddHostedService<AppService>();
});
}
+3 -3
View File
@@ -7,7 +7,7 @@ public class HandlerInitialization<TMessage, TResponse, THandler>(IServiceProvid
IInitialization where THandler : class, IHandler<TMessage, TResponse>
where TMessage : class
{
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, ResponseEventArgs<TMessage, TResponse>>(provider,
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, ResponseEventArgs<TMessage, TResponse>>(provider,
(provider, args) => args.Reply(provider.GetRequiredService<THandler>().Handle(args.Message)));
}
@@ -15,7 +15,7 @@ public class HandlerInitialization<TMessage, THandler>(IServiceProvider provider
IInitialization where THandler : class, IHandler<TMessage>
where TMessage : class
{
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, TMessage>(provider,
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, TMessage>(provider,
(provider, args) => provider.GetRequiredService<THandler>().Handle(args));
}
@@ -23,6 +23,6 @@ public class HandlerKeyedInitialization<TMessage, THandler>(string key, IService
IInitialization where THandler : class, IHandler<TMessage>
where TMessage : class
{
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, TMessage, string>(provider, key,
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, TMessage, string>(provider, key,
(provider, args) => provider.GetRequiredKeyedService<THandler>(key).Handle(args));
}
+21 -3
View File
@@ -11,9 +11,27 @@ public static class IMessengerExtensions
return args.Response;
}
public static void Send<TMessage>(this IMessenger messenger, string key)
where TMessage : class, new() => messenger.Send(new TMessage(), key);
public static TResponse Send<TMessage, TResponse>(this IMessenger messenger,
TMessage message)
where TMessage : class
{
ResponseEventArgs<TMessage, TResponse> args = messenger.Send(new ResponseEventArgs<TMessage, TResponse> { Message = message });
return args.Response;
}
public static void Send<TMessage>(this IMessenger messenger,
TMessage message, string key) where TMessage : class =>
messenger.Send(message, key);
public static void Send<TMessage>(this IMessenger messenger,
string key) where TMessage : class, new() =>
messenger.Send(new TMessage(), key);
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger)
where TMessage : class, new() => await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = new TMessage() });
where TMessage : class, new() =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = new TMessage() });
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger,
TMessage message) where TMessage : class =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = message });
}
+21
View File
@@ -0,0 +1,21 @@
using System.Drawing;
using System.IO;
using Toolkit.Windows;
using Toolkit.WinUI;
namespace Toolkit.UI.WinUI;
public static class NotifyIconExtensions
{
public static void SetIcon(this INotifyIcon notifyIcon,
Stream? stream)
{
nint shellTrayHandle = WindowHelper.GetWindowHandle("Shell_TrayWnd");
uint dpi = WindowHelper.GetDpi(shellTrayHandle);
if (stream?.ConvertToIcon(dpi) is Icon icon)
{
notifyIcon.SetIcon(icon.Handle);
}
}
}
+1
View File
@@ -23,5 +23,6 @@
<ItemGroup>
<ProjectReference Include="..\Toolkit.Windows\Toolkit.Windows.csproj" />
<ProjectReference Include="..\Toolkit.WinUI\Toolkit.WinUI.csproj" />
</ItemGroup>
</Project>
+83 -14
View File
@@ -7,6 +7,9 @@ using Windows.Win32.Graphics.Gdi;
using System.Drawing;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.WindowsAndMessaging;
using Toolkit.Windows;
using Rect = Windows.Foundation.Rect;
using WinUIEx;
namespace Toolkit.UI.WinUI;
@@ -14,16 +17,74 @@ public static partial class WindowExtensions
{
private static SUBCLASSPROC? SubClassDelegate;
public static void Hide(this Window window)
{
nint handle = WindowNative.GetWindowHandle(window);
if (handle == 0) return;
WindowHelper.HideWindow(new HWND(handle));
}
public static void IsShownInSwitchers(this Window window,
bool value)
{
if (window.AppWindow is AppWindow appWindow)
{
appWindow.IsShownInSwitchers = value;
}
}
public static void MoveAndResize(this Window window,
Rect rect)
{
nint handle = WindowNative.GetWindowHandle(window);
if (handle == 0) return;
WindowHelper.MoveAndResizeWindow(new HWND(handle),
(int)rect.Left,
(int)rect.Top,
(int)rect.Width,
(int)rect.Height);
}
public static void SetBorderless(this Window window,
bool value)
{
WindowStyle windowStyle = window.GetWindowStyle();
if (value)
{
windowStyle &= ~(WindowStyle.Caption |
WindowStyle.ThickFrame |
WindowStyle.Border |
WindowStyle.SysMenu);
}
else
{
windowStyle |= WindowStyle.Caption |
WindowStyle.ThickFrame |
WindowStyle.Border |
WindowStyle.SysMenu;
}
window.SetWindowStyle(windowStyle);
}
public static void SetForeground(this Window window)
{
nint handle = WindowNative.GetWindowHandle(window);
if (handle == 0) return;
WindowHelper.SetForegroundWindow(new HWND(handle));
}
public static void SetTopMost(this Window window,
bool value)
{
if (window.AppWindow is AppWindow appWindow &&
appWindow.Presenter is OverlappedPresenter presenter)
{
presenter.IsMaximizable = !value;
presenter.IsMinimizable = !value;
presenter.IsResizable = !value;
presenter.SetBorderAndTitleBar(!value, !value);
presenter.IsAlwaysOnTop = value;
}
}
@@ -44,18 +105,12 @@ public static partial class WindowExtensions
}
}
private static unsafe void EnableTransparency(HWND hWnd)
public static void Show(this Window window)
{
SubClassDelegate = new SUBCLASSPROC(WindowSubClass);
_ = PInvoke.SetWindowSubclass(hWnd, SubClassDelegate, 0, 0);
nint handle = WindowNative.GetWindowHandle(window);
if (handle == 0) return;
WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE,
(int)(exStyle | WINDOW_EX_STYLE.WS_EX_LAYERED));
COLORREF blackColor = new COLORREF((uint)ToWin32(Color.Black));
_ = PInvoke.SetLayeredWindowAttributes(hWnd, blackColor, 0, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY |
LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA);
WindowHelper.ShowWindow(new HWND(handle));
}
private static unsafe void DisableTransparency(HWND hWnd)
@@ -70,6 +125,20 @@ public static partial class WindowExtensions
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)(exStyle & ~WINDOW_EX_STYLE.WS_EX_LAYERED));
}
private static unsafe void EnableTransparency(HWND hWnd)
{
SubClassDelegate = new SUBCLASSPROC(WindowSubClass);
_ = PInvoke.SetWindowSubclass(hWnd, SubClassDelegate, 0, 0);
WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE,
(int)(exStyle | WINDOW_EX_STYLE.WS_EX_LAYERED));
COLORREF blackColor = new COLORREF((uint)ToWin32(Color.Black));
_ = PInvoke.SetLayeredWindowAttributes(hWnd, blackColor, 0, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY |
LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA);
}
private static int ToWin32(Color c) => c.B << 16 | c.G << 8 | c.R;
private static unsafe LRESULT WindowSubClass(HWND hWnd,
+45
View File
@@ -0,0 +1,45 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using Toolkit.Foundation;
namespace Toolkit.WinUI;
public class ContentTemplate :
DataTemplateSelector,
IContentTemplate
{
protected override DataTemplate? SelectTemplateCore(object item)
{
if (item is IObservableViewModel observableViewModel)
{
if (observableViewModel.Provider is IServiceProvider provider)
{
Type itemType = item.GetType();
if (provider.GetRequiredKeyedService<IContentTemplateDescriptor>(itemType.Name.Replace("ViewModel", ""))
is IContentTemplateDescriptor descriptor)
{
return CreateDataTemplate(descriptor);
}
}
}
return default;
}
protected override DataTemplate? SelectTemplateCore(object item,
DependencyObject container) => SelectTemplateCore(item);
private static DataTemplate CreateDataTemplate(IContentTemplateDescriptor descriptor)
{
string xamlString = @$"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
xmlns:local=""using:Toolkit.WinUI"">
<local:TemplateControl />
</DataTemplate>";
return (DataTemplate)XamlReader.Load(xamlString);
}
}
@@ -11,6 +11,8 @@ public static class IServiceCollectionExtensions
services.AddTransient<IDispatcherTimerFactory, DispatcherTimerFactory>();
services.AddSingleton<IWindowRegistry, WindowRegistry>();
services.AddTransient<IContentTemplate, ContentTemplate>();
services.AddTransient((Func<IServiceProvider, IProxyServiceCollection<IComponentBuilder>>)(provider =>
new ProxyServiceCollection<IComponentBuilder>(services =>
{
+79
View File
@@ -0,0 +1,79 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Toolkit.Foundation;
namespace Toolkit.WinUI;
[Bindable]
public class TemplateControl :
ContentControl
{
public TemplateControl()
{
DefaultStyleKey = typeof(TemplateControl);
Loaded += OnLoaded;
}
private void OnLoaded(object sender,
RoutedEventArgs args)
{
Loaded -= OnLoaded;
if (DataContext is IObservableViewModel observableViewModel)
{
if (observableViewModel.Provider is IServiceProvider provider)
{
if (provider.GetRequiredKeyedService<IContentTemplateDescriptor>(DataContext.GetType().Name.Replace("ViewModel", ""))
is IContentTemplateDescriptor descriptor)
{
if (provider.GetRequiredKeyedService(descriptor.TemplateType, descriptor.Key)
is FrameworkElement control)
{
void HandleLoaded(object? sender, RoutedEventArgs args)
{
control.Loaded -= HandleLoaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
}
}
void HandleDataContextChanged(FrameworkElement? sender, DataContextChangedEventArgs args)
{
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
}
}
void HandleUnloaded(object? sender, RoutedEventArgs args)
{
control.Unloaded -= HandleUnloaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
}
}
control.Loaded += HandleLoaded;
control.Unloaded += HandleUnloaded;
control.DataContextChanged += HandleDataContextChanged;
Content = control;
}
}
}
}
}
}
-1
View File
@@ -22,7 +22,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Toolkit.Foundation\Toolkit.Foundation.csproj" />
<ProjectReference Include="..\Toolkit.Windows\Toolkit.Windows.csproj" />
</ItemGroup>
@@ -2,6 +2,6 @@
namespace Toolkit.Windows;
public interface IPointerMonitor :
public interface IPointer :
IInitialization,
IDisposable;
+45 -35
View File
@@ -1,41 +1,51 @@
SetWindowsHookEx
GetModuleHandle
CallNextHookEx
GetPhysicalCursorPos
FindWindowEx
FindWindow
GetWindowRect
DestroyWindow
DefWindowProcW
CallNextHookEx
CreateSolidBrush
CreateWindowExW
RegisterClassW
GetSystemMetrics
MonitorFromWindow
RegisterWindowMessage
GetDpiForWindow
SetWindowPos
SHCreateShellItemArrayFromDataObject
Shell_NotifyIcon
GetSystemMetricsForDpi
GetSystemMetrics
DWM_WINDOW_CORNER_PREFERENCE
DefSubclassProc
DefWindowProcW
DeleteObject
DestroyWindow
DwmSetWindowAttribute
FillRect
FindWindow
FindWindowEx
GetClientRect
GetCurrentProcess
SetProcessInformation
PROCESS_POWER_THROTTLING_STATE
GetDpiForWindow
GetPhysicalCursorPos
GetSystemMetrics
GetSystemMetricsForDpi
GetWindowLong
GetWindowRect
MonitorFromWindow
PROCESS_POWER_THROTTLING_CURRENT_VERSION
PROCESS_POWER_THROTTLING_EXECUTION_SPEED
SetPriorityClass
WINDOW_STYLE
DefSubclassProc
SetLayeredWindowAttributes
WM_ERASEBKGND
SetWindowSubclass
GetClientRect
CreateSolidBrush
DwmSetWindowAttribute
DWM_WINDOW_CORNER_PREFERENCE
FillRect
SetLayeredWindowAttributes
DeleteObject
PROCESS_POWER_THROTTLING_STATE
RegisterClassW
RegisterWindowMessage
RemoveWindowSubclass
GetWindowLong
SHCreateShellItemArrayFromDataObject
SetLayeredWindowAttributes
SetPriorityClass
SetProcessInformation
SetWindowLong
SetWindowPos
SetWindowSubclass
SetWindowsHookEx
Shell_NotifyIcon
WINDOW_STYLE
WM_ERASEBKGND
SetForegroundWindow
ShowWindow
GetCursorPos
UnregisterClass
CreateWindowEx
RegisterClass
DefWindowProc
GetMessage
TranslateMessage
DispatchMessage
PostQuitMessage
DestroyWindow
GetModuleHandle
+17 -10
View File
@@ -1,11 +1,12 @@
using CommunityToolkit.Mvvm.Messaging;
using System.Drawing;
using System.Runtime.InteropServices;
using Toolkit.Foundation;
using Windows.Win32;
namespace Toolkit.Windows;
public partial class NotifyIcon(IWndProc wndProc,
public class NotifyIcon(IWndProc wndProc,
IMessenger messenger) :
INotifyIcon,
IRecipient<WndProcEventArgs>
@@ -17,11 +18,6 @@ public partial class NotifyIcon(IWndProc wndProc,
private bool isDisposed;
private NotifyIconData notifyIconData;
~NotifyIcon()
{
Dispose(false);
}
private enum NotifyIconBalloonType
{
None = 0x00,
@@ -66,6 +62,14 @@ public partial class NotifyIcon(IWndProc wndProc,
GC.SuppressFinalize(this);
}
public unsafe PointerLocation GetPointerPosition()
{
Point point = new();
_ = PInvoke.GetCursorPos(&point);
return new PointerLocation(point.X, point.Y);
}
public void Initialize()
{
messenger.RegisterAll(this);
@@ -79,15 +83,18 @@ public partial class NotifyIcon(IWndProc wndProc,
switch (message.LParam)
{
case (uint)WndProcMessages.WM_LBUTTONUP:
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Left));
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Left,
GetPointerPosition()));
break;
case (uint)WndProcMessages.WM_MBUTTONUP:
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Middle));
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Middle,
GetPointerPosition()));
break;
case (uint)WndProcMessages.WM_RBUTTONUP:
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Right));
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Right,
GetPointerPosition()));
break;
}
}
@@ -1,3 +1,4 @@
namespace Toolkit.Windows;
public record NotifyIconInvokedEventArgs(PointerButton PointerButton);
public record NotifyIconInvokedEventArgs(PointerButton Button,
PointerLocation Location);
+5
View File
@@ -59,4 +59,9 @@ public static partial class PInvoke
public static void GetAppBarPosition(ref AppBarData appBarData) =>
SHAppBarMessage(AppBarMessage.GetTaskbarPos, ref appBarData);
internal static bool SetWindowSubclass(HWND value1, Func<HWND, uint, WPARAM, LPARAM, nuint, nuint, LRESULT> value2, int v1, nuint v2)
{
throw new NotImplementedException();
}
}
@@ -7,8 +7,8 @@ using Windows.Win32.UI.WindowsAndMessaging;
namespace Toolkit.Windows;
public class PointerMonitor(IMessenger messenger) :
IPointerMonitor
public class Pointer(IMessenger messenger) :
IPointer
{
private bool isDisposed;
private bool isPointerDrag;
@@ -16,7 +16,7 @@ public class PointerMonitor(IMessenger messenger) :
private HOOKPROC? mouseEventDelegate;
private UnhookWindowsHookExSafeHandle? mouseHandle;
~PointerMonitor()
~Pointer()
{
Dispose(false);
}
@@ -126,9 +126,9 @@ public class PointerMonitor(IMessenger messenger) :
}
}
private unsafe bool TryGetPointer(out Point point)
private unsafe bool TryGetPointer(out System.Drawing.Point point)
{
fixed (Point* lpPointLocal = &point)
fixed (System.Drawing.Point* lpPointLocal = &point)
{
return PInvoke.GetPhysicalCursorPos(lpPointLocal);
}
@@ -136,7 +136,7 @@ public class PointerMonitor(IMessenger messenger) :
private bool TryGetPointerLocation([MaybeNullWhen(false)] out PointerLocation location)
{
if (TryGetPointer(out Point point))
if (TryGetPointer(out System.Drawing.Point point))
{
location = new PointerLocation(point.X, point.Y);
return true;
+3
View File
@@ -16,7 +16,10 @@ public record Rect
}
public int X { get; }
public int Y { get; }
public int Width { get; }
public int Height { get; }
}
+2 -2
View File
@@ -40,7 +40,7 @@ public class Taskbar(IMessenger messenger,
return state;
}
public IntPtr GetHandle() => WindowHelper.Find("Shell_TrayWnd");
public IntPtr GetHandle() => WindowHelper.FindWindow("Shell_TrayWnd");
public void Receive(WndProcEventArgs args)
{
@@ -63,7 +63,7 @@ public class Taskbar(IMessenger messenger,
public void Receive(PointerMovedEventArgs args)
{
nint taskbarHandle = GetHandle();
if (WindowHelper.TryGetBounds(taskbarHandle, out Rect? rect))
if (WindowHelper.TryGetWindowBounds(taskbarHandle, out Rect? rect))
{
if (args.Location.IsWithinBounds(rect))
{
+2 -2
View File
@@ -49,7 +49,7 @@ public class TaskbarButtonMonitor :
taskListHandle = taskbarList.GetHandle();
taskListElement = clientUIAutomation.ElementFromHandle(taskListHandle);
if (WindowHelper.TryGetBounds(taskListHandle, out Rect? rect))
if (WindowHelper.TryGetWindowBounds(taskListHandle, out Rect? rect))
{
taskbarRectCache = rect;
}
@@ -60,7 +60,7 @@ public class TaskbarButtonMonitor :
private bool CheckDirtyTaskbarRegion()
{
if (WindowHelper.TryGetBounds(taskListHandle, out Rect? rect))
if (WindowHelper.TryGetWindowBounds(taskListHandle, out Rect? rect))
{
if (taskbarRectCache?.Width != rect.Width ||
taskbarRectCache?.Height != rect.Height)
+3 -3
View File
@@ -5,8 +5,8 @@ public class TaskbarList(ITaskbar taskbar) :
{
public IntPtr GetHandle()
{
nint rebarHandle = WindowHelper.Find("ReBarWindow32", taskbar.GetHandle());
nint taskHandle = WindowHelper.Find("MSTaskSwWClass", rebarHandle);
return WindowHelper.Find("MSTaskListWClass", taskHandle);
nint rebarHandle = WindowHelper.FindWindow("ReBarWindow32", taskbar.GetHandle());
nint taskHandle = WindowHelper.FindWindow("MSTaskSwWClass", rebarHandle);
return WindowHelper.FindWindow("MSTaskListWClass", taskHandle);
}
}
+28 -19
View File
@@ -7,35 +7,44 @@ namespace Toolkit.Windows;
public class WindowHelper
{
public static IntPtr GetHandle(string windowName) => PInvoke.FindWindow(windowName, null);
public static IntPtr FindWindow(string name) =>
PInvoke.FindWindow(name, null);
public static uint GetDpi(IntPtr handle) => PInvoke.GetDpiForWindow((HWND)handle);
public static IntPtr FindWindow(string name, IntPtr handle) =>
PInvoke.FindWindowEx(new HWND(handle), new HWND(), name, null);
public static void BringToForeground(HWND handle)
{
if (TryGetBoundsUnsafe(handle, out RECT bounds))
{
PInvoke.SetWindowPos(handle, new HWND(), bounds.left, bounds.top, bounds.right -
bounds.left, bounds.bottom - bounds.top, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
}
}
public static uint GetDpi(IntPtr handle) =>
PInvoke.GetDpiForWindow((HWND)handle);
public static IntPtr Find(string windowName) =>
PInvoke.FindWindow(windowName, null);
public static IntPtr GetWindowHandle(string name) =>
PInvoke.FindWindow(name, null);
public static IntPtr Find(string windowName, IntPtr parentHandle) =>
PInvoke.FindWindowEx(new HWND(parentHandle), new HWND(), windowName, null);
public static bool HideWindow(IntPtr hWnd) =>
PInvoke.ShowWindow(new HWND(hWnd), SHOW_WINDOW_CMD.SW_HIDE);
public static void MoveAndResize(HWND handle, int x, int y, int width, int height) =>
public static void MoveAndResizeWindow(HWND handle, int x, int y, int width, int height) =>
PInvoke.SetWindowPos(handle, new HWND(), x, y, width, height, 0);
public static bool TryGetBounds(IntPtr handle,
public static bool SetForegroundWindow(HWND handle)
{
if (TryGetWindowBoundsUnsafe(handle, out RECT bounds))
{
return PInvoke.SetWindowPos(handle, new HWND(), bounds.left, bounds.top, bounds.right -
bounds.left, bounds.bottom - bounds.top, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE) == 1;
}
return false;
}
public static bool ShowWindow(IntPtr hWnd) =>
PInvoke.ShowWindow(new HWND(hWnd), SHOW_WINDOW_CMD.SW_SHOW);
public static bool TryGetWindowBounds(IntPtr handle,
[MaybeNullWhen(false)] out Rect rect)
{
if (TryGetBoundsUnsafe(handle, out RECT unsafeRect))
if (TryGetWindowBoundsUnsafe(handle, out RECT unsafeRect))
{
rect = new Rect(unsafeRect.left, unsafeRect.top, unsafeRect.right - unsafeRect.left, unsafeRect.bottom - unsafeRect.top);
return true;
}
@@ -43,7 +52,7 @@ public class WindowHelper
return false;
}
private static unsafe bool TryGetBoundsUnsafe(IntPtr handle, out RECT rect)
private static unsafe bool TryGetWindowBoundsUnsafe(IntPtr handle, out RECT rect)
{
fixed (RECT* lpRectLocal = &rect)
{
+41 -36
View File
@@ -1,7 +1,7 @@
using CommunityToolkit.Mvvm.Messaging;
using Toolkit.Foundation;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Toolkit.Windows;
@@ -10,56 +10,61 @@ public class WndProc(IMessenger messenger) :
IWndProc
{
private WNDPROC? handler;
private bool isDisposed;
~WndProc()
{
Dispose(false);
}
public IntPtr Handle { get; private set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Initialize() => InitializeWndProc();
protected virtual void Dispose(bool disposing)
{
if (isDisposed)
{
return;
}
isDisposed = true;
PInvoke.DestroyWindow((HWND)Handle);
}
private LRESULT HandleWndProc(HWND hWnd, uint msg,
WPARAM wParam, LPARAM lParam)
{
messenger.Send(new WndProcEventArgs(msg,
(uint)wParam.Value,
(uint)lParam.Value));
return PInvoke.DefWindowProc(hWnd, msg, wParam, lParam);
}
private unsafe void InitializeWndProc()
{
string windowName = Guid.NewGuid().ToString();
handler = Wndproc;
string windowId = $"WndProc_Handler_{Guid.NewGuid()}";
handler = HandleWndProc;
WNDCLASSW wndProcWindow;
wndProcWindow.style = 0;
wndProcWindow.lpfnWndProc = handler;
wndProcWindow.cbClsExtra = 0;
wndProcWindow.cbWndExtra = 0;
wndProcWindow.hInstance = new HINSTANCE();
wndProcWindow.hIcon = new HICON();
wndProcWindow.hCursor = new HCURSOR();
wndProcWindow.hbrBackground = new HBRUSH();
fixed (char* menuName = "")
fixed (char* className = windowId)
{
wndProcWindow.lpszMenuName = new PCWSTR(menuName);
}
fixed (char* className = windowName)
WNDCLASSW wndCLass = new()
{
wndProcWindow.lpszClassName = new PCWSTR(className);
lpfnWndProc = handler,
lpszClassName = className,
};
_ = PInvoke.RegisterClass(wndCLass);
}
PInvoke.RegisterClass(wndProcWindow);
Handle = PInvoke.CreateWindowEx(0, wndProcWindow.lpszClassName,
new PCWSTR(), 0, 0, 0, 0, 0, new HWND(),
new HMENU(),
new HINSTANCE());
}
private LRESULT Wndproc(HWND param0, uint param1, WPARAM param2, LPARAM param3)
{
messenger.Send(new WndProcEventArgs(param1, (uint)param2.Value, (uint)param3.Value));
return PInvoke.DefWindowProc(param0, param1, param2, param3);
}
public void Initialize()
{
InitializeWndProc();
Handle = PInvoke.CreateWindowEx(0, windowId, windowId, 0, 0, 0, 0, 0,
new HWND(IntPtr.Zero), null, null, null);
}
}