add simplified win32 implementation

This commit is contained in:
DismissedLight
2022-08-02 16:14:54 +08:00
parent 6d94ab9bd7
commit ed1706b78e
12 changed files with 168 additions and 53 deletions

View File

@@ -7,7 +7,7 @@
<Style x:Key="SettingButtonStyle" TargetType="Button" BasedOn="{StaticResource DefaultButtonStyle}" >
<Setter Property="BorderBrush" Value="{ThemeResource CardBorderBrush}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Padding" Value="16,4,16,4" />
<Setter Property="Padding" Value="16,5,16,6" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>

View File

@@ -0,0 +1,10 @@
namespace Windows.Win32.Foundation;
public partial struct POINT
{
public POINT(int x,int y)
{
this.x = x;
this.y = y;
}
}

View File

@@ -0,0 +1,19 @@
namespace Windows.Win32.Foundation;
public partial struct RECT
{
public RECT(int left, int top, int right, int bottom)
{
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public int Size
{
get
{
return (right - left) * (bottom - top);
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Runtime.InteropServices;
using Windows.Win32.Foundation;
namespace Windows.Win32.UI.WindowsAndMessaging;
public partial struct WINDOWPLACEMENT
{
/// <summary>
/// Gets the default (empty) value.
/// </summary>
public static WINDOWPLACEMENT Default
{
get
{
return new WINDOWPLACEMENT()
{
length = (uint)Marshal.SizeOf<WINDOWPLACEMENT>(),
};
}
}
/// <summary>
/// 构造一个新的<see cref="WINDOWPLACEMENT"/>
/// </summary>
/// <param name="ptMaxPosition">最大点</param>
/// <param name="rcNormalPosition">正常位置</param>
/// <param name="showCmd">显示命令</param>
/// <returns>窗体位置</returns>
public static WINDOWPLACEMENT Create(POINT ptMaxPosition, RECT rcNormalPosition, SHOW_WINDOW_CMD showCmd)
{
WINDOWPLACEMENT result = Default;
result.ptMaxPosition = ptMaxPosition;
result.rcNormalPosition = rcNormalPosition;
result.showCmd = showCmd;
return result;
}
}

View File

@@ -0,0 +1,18 @@
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao.Win32;
public class Unsafe
{
/// <summary>
/// 使用指针操作简化封送
/// </summary>
/// <param name="lPARAM"></param>
/// <param name="minWidth"></param>
/// <param name="minHeight"></param>
public static unsafe void SetMinTrackSize(nint lPARAM, float minWidth, float minHeight)
{
MINMAXINFO* rect2 = (MINMAXINFO*)lPARAM;
rect2->ptMinTrackSize.x = (int)Math.Max(minWidth, rect2->ptMinTrackSize.x);
rect2->ptMinTrackSize.y = (int)Math.Max(minHeight, rect2->ptMinTrackSize.y);
}
}

View File

@@ -25,7 +25,6 @@
<CornerRadius x:Key="CompatCornerRadiusTop">6,6,0,0</CornerRadius>
<CornerRadius x:Key="CompatCornerRadiusRight">0,6,6,0</CornerRadius>
<CornerRadius x:Key="CompatCornerRadiusBottom">0,0,6,6</CornerRadius>
<CornerRadius x:Key="SmallCompatCornerRadius">4</CornerRadius>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -0,0 +1,34 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.UI.Behaviors;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Shapes;
namespace Snap.Hutao.Control.Behavior;
/// <summary>
/// Make ContentDialog's SmokeLayerBackground dsiplay over custom titleBar
/// </summary>
public class ContentDialogBehavior : BehaviorBase<FrameworkElement>
{
/// <inheritdoc/>
protected override void OnAssociatedObjectLoaded()
{
DependencyObject parent = VisualTreeHelper.GetParent(AssociatedObject);
DependencyObject child = VisualTreeHelper.GetChild(parent, 2);
Rectangle smokeLayerBackground = (Rectangle)child;
smokeLayerBackground.Margin = new Thickness(0);
smokeLayerBackground.RegisterPropertyChangedCallback(FrameworkElement.MarginProperty, OnMarginChanged);
}
private static void OnMarginChanged(DependencyObject sender, DependencyProperty property)
{
if (property == FrameworkElement.MarginProperty)
{
sender.ClearValue(property);
}
}
}

View File

@@ -78,4 +78,9 @@ internal static class EventIds
/// 背景状态
/// </summary>
public static readonly EventId BackdropState = 200001;
/// <summary>
/// 子类控制
/// </summary>
public static readonly EventId SubClassing = 200002;
}

View File

@@ -5,30 +5,30 @@ using Microsoft.UI.Xaml;
using Snap.Hutao.Control.HostBackdrop;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Core.Setting;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.WindowsAndMessaging;
using WinRT.Interop;
using static Windows.Win32.PInvoke;
namespace Snap.Hutao.Core;
/// <summary>
/// 窗口状态管理器
/// 主要包含了各类 P/Inoke 代码
/// 窗口管理器
/// 主要包含了针对窗体的 P/Inoke 逻辑
/// </summary>
internal class WindowManager
{
private const int MinWidth = 800;
private const int MinHeight = 600;
private const int MinWidth = 848;
private const int MinHeight = 524;
private const int SubclassId = 101;
private readonly HWND handle;
private readonly Window window;
private readonly UIElement titleBar;
private readonly ILogger<WindowManager> logger;
// We have to explictly hold a reference to the SUBCLASSPROC
// We have to explictly hold a reference to the SUBCLASSPROC,
// otherwise will casuse System.ExecutionEngineException
private SUBCLASSPROC? subClassProc;
@@ -53,17 +53,14 @@ internal class WindowManager
int right = LocalSetting.GetValueType<int>(SettingKeys.WindowRight);
int bottom = LocalSetting.GetValueType<int>(SettingKeys.WindowBottom);
return new() { left = left, top = top, right = right, bottom = bottom };
return new(left, top, right, bottom);
}
private static void SaveWindowRect(HWND handle)
{
WINDOWPLACEMENT windowPlacement = new()
{
length = (uint)Marshal.SizeOf<WINDOWPLACEMENT>(),
};
WINDOWPLACEMENT windowPlacement = WINDOWPLACEMENT.Default;
PInvoke.GetWindowPlacement(handle, ref windowPlacement);
GetWindowPlacement(handle, ref windowPlacement);
LocalSetting.Set(SettingKeys.WindowLeft, windowPlacement.rcNormalPosition.left);
LocalSetting.Set(SettingKeys.WindowTop, windowPlacement.rcNormalPosition.top);
@@ -77,52 +74,42 @@ internal class WindowManager
window.SetTitleBar(titleBar);
window.Closed += OnWindowClosed;
PInvoke.SetWindowText(handle, "胡桃");
SetWindowText(handle, "胡桃");
RECT rect = RetriveWindowRect();
if ((rect.right - rect.left) * (rect.bottom - rect.top) > 0)
if (rect.Size > 0)
{
WINDOWPLACEMENT windowPlacement = new()
{
length = (uint)Marshal.SizeOf<WINDOWPLACEMENT>(),
showCmd = SHOW_WINDOW_CMD.SW_SHOWNORMAL,
ptMaxPosition = new() { x = -1, y = -1 },
rcNormalPosition = rect,
};
PInvoke.SetWindowPlacement(handle, in windowPlacement);
WINDOWPLACEMENT windowPlacement = WINDOWPLACEMENT.Create(new(-1, -1), rect, SHOW_WINDOW_CMD.SW_SHOWNORMAL);
SetWindowPlacement(handle, in windowPlacement);
}
bool micaApplied = new SystemBackdrop(window).TrySetBackdrop();
logger.LogInformation(EventIds.BackdropState, "Apply {name} : {result}", nameof(SystemBackdrop), micaApplied ? "succeed" : "failed");
subClassProc = new(OnWindowProcedure);
_ = PInvoke.SetWindowSubclass(handle, subClassProc, 101, 0);
subClassProc = new(OnSubclassProcedure);
bool subClassApplied = SetWindowSubclass(handle, subClassProc, SubclassId, 0);
logger.LogInformation(EventIds.SubClassing, "Apply {name} : {result}", nameof(SUBCLASSPROC), subClassApplied ? "succeed" : "failed");
}
private void OnWindowClosed(object sender, WindowEventArgs args)
{
PInvoke.RemoveWindowSubclass(handle, subClassProc, 101);
RemoveWindowSubclass(handle, subClassProc, SubclassId);
subClassProc = null;
SaveWindowRect(handle);
}
private LRESULT OnWindowProcedure(HWND hwnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
private LRESULT OnSubclassProcedure(HWND hwnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
{
switch (uMsg)
{
case PInvoke.WM_GETMINMAXINFO:
case WM_GETMINMAXINFO:
{
uint dpi = PInvoke.GetDpiForWindow(handle);
uint dpi = GetDpiForWindow(handle);
float scalingFactor = dpi / 96f;
MINMAXINFO minMaxInfo = Marshal.PtrToStructure<MINMAXINFO>(lParam);
minMaxInfo.ptMinTrackSize.x = (int)Math.Max(MinWidth * scalingFactor, minMaxInfo.ptMinTrackSize.x);
minMaxInfo.ptMinTrackSize.y = (int)Math.Max(MinHeight * scalingFactor, minMaxInfo.ptMinTrackSize.y);
Marshal.StructureToPtr(minMaxInfo, lParam, true);
Win32.Unsafe.SetMinTrackSize(lParam, MinWidth * scalingFactor, MinHeight * scalingFactor);
break;
}
}
return PInvoke.DefSubclassProc(hwnd, uMsg, wParam, lParam);
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
}

View File

@@ -1,11 +1,12 @@
<ContentDialog
x:Class="Snap.Hutao.View.Dialog.UserDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Snap.Hutao.View.Dialog"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
xmlns:settings="using:SettingsUI.Controls"
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
mc:Ignorable="d"
IsPrimaryButtonEnabled="False"
Title="设置米游社Cookie"
@@ -13,7 +14,10 @@
PrimaryButtonText="请输入Cookie"
CloseButtonText="取消"
Style="{StaticResource DefaultContentDialogStyle}">
<mxi:Interaction.Behaviors>
<shcb:ContentDialogBehavior/>
</mxi:Interaction.Behaviors>
<StackPanel>
<TextBox
Margin="0,0,0,8"
@@ -22,16 +26,16 @@
PlaceholderText="在此处输入"
VerticalAlignment="Top"/>
<settings:Setting
Margin="0,8,0,0"
Icon="&#xEB41;"
Header="手动获取"
Description="进入我们的文档页面并按指示操作"
HorizontalAlignment="Stretch">
Margin="0,8,0,0"
Icon="&#xEB41;"
Header="手动获取"
Description="进入我们的文档页面并按指示操作"
HorizontalAlignment="Stretch">
<HyperlinkButton
Margin="12,0,0,0"
Padding="4"
Content="立即前往"
NavigateUri="https://www.snapgenshin.com/documents/features/mhy-account-switch.html#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-cookie"/>
Margin="12,0,0,0"
Padding="4"
Content="立即前往"
NavigateUri="https://www.snapgenshin.com/documents/features/mhy-account-switch.html#%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96-cookie"/>
</settings:Setting>
</StackPanel>
</ContentDialog>

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core.Threading;
@@ -15,7 +16,7 @@ public sealed partial class UserDialog : ContentDialog
/// 构造一个新的添加用户对话框
/// </summary>
/// <param name="window">呈现的父窗口</param>
public UserDialog(Microsoft.UI.Xaml.Window window)
public UserDialog(Window window)
{
InitializeComponent();
XamlRoot = window.Content.XamlRoot;

View File

@@ -29,6 +29,6 @@ public sealed partial class MainView : UserControl
navigationService = Ioc.Default.GetRequiredService<INavigationService>();
navigationService.Initialize(NavView, ContentFrame);
//navigationService.Navigate<AnnouncementPage>(INavigationAwaiter.Default, true);
navigationService.Navigate<AnnouncementPage>(INavigationAwaiter.Default, true);
}
}