mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
support show icon
This commit is contained in:
@@ -12,6 +12,7 @@ internal static class SettingKeys
|
||||
{
|
||||
#region MainWindow
|
||||
public const string WindowRect = "WindowRect";
|
||||
public const string GuideWindowRect = "GuideWindowRect";
|
||||
public const string IsNavPaneOpen = "IsNavPaneOpen";
|
||||
public const string IsInfoBarToggleChecked = "IsInfoBarToggleChecked";
|
||||
public const string ExcludedAnnouncementIds = "ExcludedAnnouncementIds";
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage;
|
||||
using static Snap.Hutao.Win32.ConstValues;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.NotifyIcon;
|
||||
|
||||
internal sealed class NotifyIconController : IDisposable
|
||||
{
|
||||
private readonly NotifyIconMessageWindow messageWindow;
|
||||
private readonly System.Drawing.Icon icon;
|
||||
|
||||
public NotifyIconController()
|
||||
{
|
||||
messageWindow = new();
|
||||
|
||||
NotifyIconMethods.Delete(Id);
|
||||
|
||||
StorageFile iconFile = StorageFile.GetFileFromApplicationUriAsync("ms-appx:///Assets/Logo.ico".ToUri()).AsTask().GetAwaiter().GetResult();
|
||||
icon = new(iconFile.Path);
|
||||
|
||||
if (!NotifyIconMethods.Add(Id, messageWindow.HWND, "Snap Hutao", NotifyIconMessageWindow.WM_NOTIFYICON_CALLBACK, (HICON)icon.Handle))
|
||||
{
|
||||
HutaoException.InvalidOperation("Failed to create NotifyIcon");
|
||||
}
|
||||
|
||||
if (!NotifyIconMethods.SetVersion(Id, NOTIFYICON_VERSION_4))
|
||||
{
|
||||
HutaoException.InvalidOperation("Failed to set NotifyIcon version");
|
||||
}
|
||||
}
|
||||
|
||||
private static ref readonly Guid Id
|
||||
{
|
||||
get
|
||||
{
|
||||
// MD5 for "Snap.Hutao"
|
||||
ReadOnlySpan<byte> data = [0xEE, 0x01, 0x5C, 0xCB, 0xF3, 0x97, 0xC6, 0x93, 0xE8, 0x77, 0xCE, 0x09, 0x54, 0x90, 0xEE, 0xAC];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
messageWindow.Dispose();
|
||||
NotifyIconMethods.Delete(Id);
|
||||
icon.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Snap.Hutao.Win32.User32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.NotifyIcon;
|
||||
|
||||
[SuppressMessage("", "SA1310")]
|
||||
internal sealed class NotifyIconMessageWindow : IDisposable
|
||||
{
|
||||
public const uint WM_NOTIFYICON_CALLBACK = 0x444U;
|
||||
private const string WindowClassName = "SnapHutaoNotifyIconMessageWindowClass";
|
||||
|
||||
private static readonly ConcurrentDictionary<HWND, NotifyIconMessageWindow> WindowTable = [];
|
||||
|
||||
public readonly HWND HWND;
|
||||
|
||||
[SuppressMessage("", "SA1306")]
|
||||
private uint WM_TASKBARCREATED;
|
||||
|
||||
private bool isDisposed;
|
||||
|
||||
public unsafe NotifyIconMessageWindow()
|
||||
{
|
||||
ushort atom;
|
||||
fixed (char* className = WindowClassName)
|
||||
{
|
||||
WNDCLASSW wc = new()
|
||||
{
|
||||
lpfnWndProc = WNDPROC.Create(&OnWindowProcedure),
|
||||
lpszClassName = className,
|
||||
};
|
||||
|
||||
atom = RegisterClassW(&wc);
|
||||
}
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfEqual<ushort>(atom, 0);
|
||||
|
||||
// https://learn.microsoft.com/zh,cn/windows/win32/shell/taskbar#taskbar,creation,notification
|
||||
WM_TASKBARCREATED = RegisterWindowMessageW("TaskbarCreated");
|
||||
|
||||
HWND = CreateWindowExW(0, WindowClassName, WindowClassName, 0, 0, 0, 0, 0, default, default, default, default);
|
||||
|
||||
if (HWND == default)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
|
||||
}
|
||||
|
||||
WindowTable.TryAdd(HWND, this);
|
||||
}
|
||||
|
||||
~NotifyIconMessageWindow()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isDisposed = true;
|
||||
|
||||
DestroyWindow(HWND);
|
||||
WindowTable.TryRemove(HWND, out _);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
[SuppressMessage("", "SH002")]
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
|
||||
private static unsafe LRESULT OnWindowProcedure(HWND hwnd, uint uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (WindowTable.TryGetValue(hwnd, out NotifyIconMessageWindow? window))
|
||||
{
|
||||
if (uMsg == window.WM_TASKBARCREATED)
|
||||
{
|
||||
// TODO: Re-add the notify icon.
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/zh-cn/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
|
||||
if (uMsg == WM_NOTIFYICON_CALLBACK)
|
||||
{
|
||||
LPARAM2 lParam2 = *(LPARAM2*)&lParam;
|
||||
WPARAM2 wParam2 = *(WPARAM2*)&wParam;
|
||||
Debug.WriteLine($"[uMsg: 0x{uMsg:X8}] [X: {wParam2.X} Y: {wParam2.Y}] [Low: 0x{lParam2.Low:X8} High: 0x{lParam2.High:X8}]");
|
||||
switch (lParam.Value)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
private readonly struct LPARAM2
|
||||
{
|
||||
public readonly uint Low;
|
||||
public readonly uint High;
|
||||
}
|
||||
|
||||
private readonly struct WPARAM2
|
||||
{
|
||||
public readonly ushort X;
|
||||
public readonly ushort Y;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.Shell;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using static Snap.Hutao.Win32.Shell32;
|
||||
|
||||
namespace Snap.Hutao.Core.Windowing.NotifyIcon;
|
||||
|
||||
internal sealed class NotifyIconMethods
|
||||
{
|
||||
public static BOOL Add(ref readonly NOTIFYICONDATAW data)
|
||||
{
|
||||
return Shell_NotifyIconW(NOTIFY_ICON_MESSAGE.NIM_ADD, in data);
|
||||
}
|
||||
|
||||
[SuppressMessage("", "SH002")]
|
||||
public static unsafe BOOL Add(Guid id, HWND hWnd, string tip, uint uCallbackMessage, HICON hIcon)
|
||||
{
|
||||
NOTIFYICONDATAW data = default;
|
||||
data.cbSize = (uint)sizeof(NOTIFYICONDATAW);
|
||||
data.uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP | NOTIFY_ICON_DATA_FLAGS.NIF_GUID;
|
||||
data.guidItem = id;
|
||||
data.hWnd = hWnd;
|
||||
tip.AsSpan().CopyTo(new(data.szTip, 128));
|
||||
data.uCallbackMessage = uCallbackMessage;
|
||||
data.hIcon = hIcon;
|
||||
data.dwState = NOTIFY_ICON_STATE.NIS_HIDDEN;
|
||||
data.dwStateMask = NOTIFY_ICON_STATE.NIS_HIDDEN;
|
||||
|
||||
return Add(in data);
|
||||
}
|
||||
|
||||
public static BOOL Modify(ref readonly NOTIFYICONDATAW data)
|
||||
{
|
||||
return Shell_NotifyIconW(NOTIFY_ICON_MESSAGE.NIM_MODIFY, in data);
|
||||
}
|
||||
|
||||
public static BOOL Delete(ref readonly NOTIFYICONDATAW data)
|
||||
{
|
||||
return Shell_NotifyIconW(NOTIFY_ICON_MESSAGE.NIM_DELETE, in data);
|
||||
}
|
||||
|
||||
public static unsafe BOOL Delete(Guid id)
|
||||
{
|
||||
NOTIFYICONDATAW data = default;
|
||||
data.cbSize = (uint)sizeof(NOTIFYICONDATAW);
|
||||
data.uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_GUID;
|
||||
data.guidItem = id;
|
||||
|
||||
return Delete(in data);
|
||||
}
|
||||
|
||||
public static BOOL SetFocus(ref readonly NOTIFYICONDATAW data)
|
||||
{
|
||||
return Shell_NotifyIconW(NOTIFY_ICON_MESSAGE.NIM_SETFOCUS, in data);
|
||||
}
|
||||
|
||||
public static BOOL SetVersion(ref readonly NOTIFYICONDATAW data)
|
||||
{
|
||||
return Shell_NotifyIconW(NOTIFY_ICON_MESSAGE.NIM_SETVERSION, in data);
|
||||
}
|
||||
|
||||
public static unsafe BOOL SetVersion(Guid id, uint version)
|
||||
{
|
||||
NOTIFYICONDATAW data = default;
|
||||
data.cbSize = (uint)sizeof(NOTIFYICONDATAW);
|
||||
data.uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_GUID;
|
||||
data.guidItem = id;
|
||||
data.Anonymous.uVersion = version;
|
||||
|
||||
return SetVersion(in data);
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,9 @@ internal sealed class WindowController
|
||||
SizeInt32 scaledSize = options.InitSize.Scale(scale);
|
||||
RectInt32 rect = StructMarshal.RectInt32(scaledSize);
|
||||
|
||||
if (options.PersistSize)
|
||||
if (!string.IsNullOrEmpty(options.PersistRectKey))
|
||||
{
|
||||
RectInt32 persistedRect = (CompactRect)LocalSetting.Get(SettingKeys.WindowRect, (CompactRect)rect);
|
||||
RectInt32 persistedRect = (CompactRect)LocalSetting.Get(options.PersistRectKey, (CompactRect)rect);
|
||||
if (persistedRect.Size() >= options.InitSize.Size())
|
||||
{
|
||||
rect = persistedRect.Scale(scale);
|
||||
@@ -104,7 +104,7 @@ internal sealed class WindowController
|
||||
|
||||
private void SaveOrSkipWindowSize()
|
||||
{
|
||||
if (!options.PersistSize)
|
||||
if (string.IsNullOrEmpty(options.PersistRectKey))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -116,7 +116,7 @@ internal sealed class WindowController
|
||||
if (!windowPlacement.ShowCmd.HasFlag(SHOW_WINDOW_CMD.SW_SHOWMAXIMIZED))
|
||||
{
|
||||
double scale = 1.0 / options.GetRasterizationScale();
|
||||
LocalSetting.Set(SettingKeys.WindowRect, (CompactRect)window.AppWindow.GetRect().Scale(scale));
|
||||
LocalSetting.Set(options.PersistRectKey, (CompactRect)window.AppWindow.GetRect().Scale(scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,15 +38,18 @@ internal readonly struct WindowOptions
|
||||
/// <summary>
|
||||
/// 是否持久化尺寸
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
public readonly bool PersistSize;
|
||||
|
||||
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, bool persistSize = false)
|
||||
public readonly string? PersistRectKey;
|
||||
|
||||
public WindowOptions(Window window, FrameworkElement titleBar, SizeInt32 initSize, string? persistSize = default)
|
||||
{
|
||||
Hwnd = WindowNative.GetWindowHandle(window);
|
||||
InputNonClientPointerSource = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
|
||||
TitleBar = titleBar;
|
||||
InitSize = initSize;
|
||||
PersistSize = persistSize;
|
||||
PersistRectKey = persistSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing.Backdrop;
|
||||
using Snap.Hutao.Core.Windowing.HotKey;
|
||||
using Snap.Hutao.Win32;
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.UI.Shell;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Snap.Hutao.Win32.ComCtl32;
|
||||
using static Snap.Hutao.Win32.ConstValues;
|
||||
|
||||
@@ -27,6 +30,7 @@ internal sealed class WindowSubclass : IDisposable
|
||||
|
||||
// We have to explicitly hold a reference to SUBCLASSPROC
|
||||
private SUBCLASSPROC windowProc = default!;
|
||||
private UnmanagedAccess<WindowSubclass> unmanagedAccess = default!;
|
||||
|
||||
public WindowSubclass(Window window, in WindowOptions options, IServiceProvider serviceProvider)
|
||||
{
|
||||
@@ -41,10 +45,11 @@ internal sealed class WindowSubclass : IDisposable
|
||||
/// 尝试设置窗体子类
|
||||
/// </summary>
|
||||
/// <returns>是否设置成功</returns>
|
||||
public bool Initialize()
|
||||
public unsafe bool Initialize()
|
||||
{
|
||||
windowProc = OnSubclassProcedure;
|
||||
bool windowHooked = SetWindowSubclass(options.Hwnd, windowProc, WindowSubclassId, 0);
|
||||
windowProc = SUBCLASSPROC.Create(&OnSubclassProcedure);
|
||||
unmanagedAccess = UnmanagedAccess.Create(this);
|
||||
bool windowHooked = SetWindowSubclass(options.Hwnd, windowProc, WindowSubclassId, unmanagedAccess);
|
||||
hotKeyController.RegisterAll();
|
||||
|
||||
return windowHooked;
|
||||
@@ -57,18 +62,23 @@ internal sealed class WindowSubclass : IDisposable
|
||||
|
||||
RemoveWindowSubclass(options.Hwnd, windowProc, WindowSubclassId);
|
||||
windowProc = default!;
|
||||
unmanagedAccess.Dispose();
|
||||
}
|
||||
|
||||
[SuppressMessage("", "SH002")]
|
||||
private unsafe LRESULT OnSubclassProcedure(HWND hwnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
|
||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
|
||||
private static unsafe LRESULT OnSubclassProcedure(HWND hwnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
|
||||
{
|
||||
WindowSubclass? state = UnmanagedAccess.Get<WindowSubclass>(dwRefData);
|
||||
ArgumentNullException.ThrowIfNull(state);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
if (window is IMinMaxInfoHandler handler)
|
||||
if (state.window is IMinMaxInfoHandler handler)
|
||||
{
|
||||
handler.HandleMinMaxInfo(ref *(MINMAXINFO*)lParam, options.GetRasterizationScale());
|
||||
handler.HandleMinMaxInfo(ref *(MINMAXINFO*)lParam, state.options.GetRasterizationScale());
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -82,13 +92,13 @@ internal sealed class WindowSubclass : IDisposable
|
||||
|
||||
case WM_HOTKEY:
|
||||
{
|
||||
hotKeyController.OnHotKeyPressed(*(HotKeyParameter*)&lParam);
|
||||
state.hotKeyController.OnHotKeyPressed(*(HotKeyParameter*)&lParam);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
{
|
||||
if (window.SystemBackdrop is IBackdropNeedEraseBackground)
|
||||
if (state.window.SystemBackdrop is IBackdropNeedEraseBackground)
|
||||
{
|
||||
return (LRESULT)(int)BOOL.TRUE;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
@@ -24,7 +25,7 @@ internal sealed partial class GuideWindow : Window, IWindowOptionsSource, IMinMa
|
||||
public GuideWindow(IServiceProvider serviceProvider)
|
||||
{
|
||||
InitializeComponent();
|
||||
windowOptions = new(this, DragableGrid, new(MinWidth, MinHeight));
|
||||
windowOptions = new(this, DragableGrid, new(MinWidth, MinHeight), SettingKeys.GuideWindowRect);
|
||||
this.InitializeController(serviceProvider);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Snap.Hutao.ViewModel.Game;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Core.Windowing;
|
||||
using Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
@@ -27,7 +28,7 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IMinMax
|
||||
public MainWindow(IServiceProvider serviceProvider)
|
||||
{
|
||||
InitializeComponent();
|
||||
windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), true);
|
||||
windowOptions = new(this, TitleBarView.DragArea, new(1200, 741), SettingKeys.WindowRect);
|
||||
this.InitializeController(serviceProvider);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Windowing.NotifyIcon;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using WinRT;
|
||||
@@ -49,9 +50,12 @@ public static partial class Program
|
||||
// By adding the using statement, we can dispose the injected services when we closing
|
||||
using (ServiceProvider serviceProvider = DependencyInjection.Initialize())
|
||||
{
|
||||
// In a Desktop app this runs a message pump internally,
|
||||
// and does not return until the application shuts down.
|
||||
Application.Start(AppInitializationCallback);
|
||||
using (NotifyIconController notifyIconController = new())
|
||||
{
|
||||
// In a Desktop app this runs a message pump internally,
|
||||
// and does not return until the application shuts down.
|
||||
Application.Start(AppInitializationCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Snap.Hutao.Win32;
|
||||
[SuppressMessage("", "SYSLIB1054")]
|
||||
internal static class AdvApi32
|
||||
{
|
||||
[DllImport("ADVAPI32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("ADVAPI32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.1.2600")]
|
||||
public static unsafe extern BOOL ConvertSidToStringSidW(PSID Sid, PWSTR* StringSid);
|
||||
|
||||
@@ -26,7 +26,7 @@ internal static class AdvApi32
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("ADVAPI32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("ADVAPI32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.1.2600")]
|
||||
public static unsafe extern BOOL ConvertStringSidToSidW(PCWSTR StringSid, PSID* Sid);
|
||||
|
||||
@@ -53,7 +53,7 @@ internal static class AdvApi32
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern WIN32_ERROR RegNotifyChangeKeyValue(HKEY hKey, BOOL bWatchSubtree, REG_NOTIFY_FILTER dwNotifyFilter, [AllowNull] HANDLE hEvent, BOOL fAsynchronous);
|
||||
|
||||
[DllImport("ADVAPI32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||
[DllImport("ADVAPI32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static unsafe extern WIN32_ERROR RegOpenKeyExW(HKEY hKey, [AllowNull] PCWSTR lpSubKey, [AllowNull] uint ulOptions, REG_SAM_FLAGS samDesired, HKEY* phkResult);
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ internal static class ComCtl32
|
||||
|
||||
[DllImport("COMCTL32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[SupportedOSPlatform("windows5.1.2600")]
|
||||
public static extern BOOL RemoveWindowSubclass(HWND hWnd, [MarshalAs(UnmanagedType.FunctionPtr)] SUBCLASSPROC pfnSubclass, nuint uIdSubclass);
|
||||
public static extern BOOL RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, nuint uIdSubclass);
|
||||
|
||||
[DllImport("COMCTL32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[SupportedOSPlatform("windows5.1.2600")]
|
||||
public static unsafe extern BOOL SetWindowSubclass(HWND hWnd, [MarshalAs(UnmanagedType.FunctionPtr)] SUBCLASSPROC pfnSubclass, nuint uIdSubclass, nuint dwRefData);
|
||||
public static unsafe extern BOOL SetWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, nuint uIdSubclass, nuint dwRefData);
|
||||
}
|
||||
@@ -7,6 +7,8 @@ namespace Snap.Hutao.Win32;
|
||||
internal static class ConstValues
|
||||
{
|
||||
public const uint D3D11_SDK_VERSION = 0x00000007U;
|
||||
public const uint NOTIFYICON_VERSION = 0x00000003U;
|
||||
public const uint NOTIFYICON_VERSION_4 = 0x00000004U;
|
||||
public const uint WM_NULL = 0x00000000U;
|
||||
public const uint WM_ERASEBKGND = 0x00000014U;
|
||||
public const uint WM_GETMINMAXINFO = 0x00000024U;
|
||||
|
||||
@@ -7,8 +7,6 @@ internal readonly struct HWND
|
||||
{
|
||||
public readonly nint Value;
|
||||
|
||||
public HWND(nint value) => Value = value;
|
||||
|
||||
public static unsafe implicit operator HWND(nint value) => *(HWND*)&value;
|
||||
|
||||
public static unsafe implicit operator nint(HWND value) => *(nint*)&value;
|
||||
|
||||
@@ -22,7 +22,7 @@ internal static class Kernel32
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern BOOL CloseHandle(HANDLE hObject);
|
||||
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.1.2600")]
|
||||
public static unsafe extern HANDLE CreateEventW([AllowNull] SECURITY_ATTRIBUTES* lpEventAttributes, BOOL bManualReset, BOOL bInitialState, [AllowNull] PCWSTR lpName);
|
||||
|
||||
@@ -72,7 +72,7 @@ internal static class Kernel32
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern uint K32GetModuleBaseNameW(HANDLE hProcess, [AllowNull] HMODULE hModule, PWSTR lpBaseName, uint nSize);
|
||||
|
||||
[DebuggerStepThrough]
|
||||
@@ -128,7 +128,7 @@ internal static class Kernel32
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
public static extern BOOL SetConsoleMode(HANDLE hConsoleHandle, CONSOLE_MODE dwMode);
|
||||
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("KERNEL32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern BOOL SetConsoleTitleW(PCWSTR lpConsoleTitle);
|
||||
|
||||
[DebuggerStepThrough]
|
||||
|
||||
@@ -6,5 +6,17 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
internal delegate LRESULT SUBCLASSPROC(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData);
|
||||
internal unsafe readonly struct SUBCLASSPROC
|
||||
{
|
||||
private readonly delegate* unmanaged[Stdcall]<HWND, uint, WPARAM, LPARAM, nuint, nuint, LRESULT> value;
|
||||
|
||||
public SUBCLASSPROC(delegate* unmanaged[Stdcall]<HWND, uint, WPARAM, LPARAM, nuint, nuint, LRESULT> method)
|
||||
{
|
||||
value = method;
|
||||
}
|
||||
|
||||
public static SUBCLASSPROC Create(delegate* unmanaged[Stdcall]<HWND, uint, WPARAM, LPARAM, nuint, nuint, LRESULT> method)
|
||||
{
|
||||
return new(method);
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,8 @@ namespace Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
internal readonly struct HICON
|
||||
{
|
||||
public readonly nint Value;
|
||||
|
||||
public static unsafe implicit operator HICON(nint value) => *(HICON*)&value;
|
||||
|
||||
public static unsafe implicit operator nint(HICON value) => *(nint*)&value;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
// RAIIFree: DestroyMenu
|
||||
// InvalidHandleValue: -1, 0
|
||||
internal readonly struct HMENU
|
||||
{
|
||||
public readonly nint Value;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
[Flags]
|
||||
[SuppressMessage("", "CA1069")]
|
||||
internal enum WINDOW_STYLE : uint
|
||||
{
|
||||
WS_OVERLAPPED = 0x0U,
|
||||
WS_POPUP = 0x80000000U,
|
||||
WS_CHILD = 0x40000000U,
|
||||
WS_MINIMIZE = 0x20000000U,
|
||||
WS_VISIBLE = 0x10000000U,
|
||||
WS_DISABLED = 0x8000000U,
|
||||
WS_CLIPSIBLINGS = 0x4000000U,
|
||||
WS_CLIPCHILDREN = 0x2000000U,
|
||||
WS_MAXIMIZE = 0x1000000U,
|
||||
WS_CAPTION = 0xC00000U,
|
||||
WS_BORDER = 0x800000U,
|
||||
WS_DLGFRAME = 0x400000U,
|
||||
WS_VSCROLL = 0x200000U,
|
||||
WS_HSCROLL = 0x100000U,
|
||||
WS_SYSMENU = 0x80000U,
|
||||
WS_THICKFRAME = 0x40000U,
|
||||
WS_GROUP = 0x20000U,
|
||||
WS_TABSTOP = 0x10000U,
|
||||
WS_MINIMIZEBOX = 0x20000U,
|
||||
WS_MAXIMIZEBOX = 0x10000U,
|
||||
WS_TILED = 0x0U,
|
||||
WS_ICONIC = 0x20000000U,
|
||||
WS_SIZEBOX = 0x40000U,
|
||||
WS_TILEDWINDOW = 0xCF0000U,
|
||||
WS_OVERLAPPEDWINDOW = 0xCF0000U,
|
||||
WS_POPUPWINDOW = 0x80880000U,
|
||||
WS_CHILDWINDOW = 0x40000000U,
|
||||
WS_ACTIVECAPTION = 0x1U,
|
||||
}
|
||||
@@ -10,8 +10,6 @@ namespace Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
internal struct WNDCLASSW
|
||||
{
|
||||
public WNDCLASS_STYLES style;
|
||||
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public WNDPROC lpfnWndProc;
|
||||
public int cbClsExtra;
|
||||
public int cbWndExtra;
|
||||
|
||||
@@ -2,9 +2,20 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
internal delegate LRESULT WNDPROC(HWND param0, uint param1, WPARAM param2, LPARAM param3);
|
||||
internal unsafe readonly struct WNDPROC
|
||||
{
|
||||
private readonly delegate* unmanaged[Stdcall]<HWND, uint, WPARAM, LPARAM, LRESULT> value;
|
||||
|
||||
public WNDPROC(delegate* unmanaged[Stdcall]<HWND, uint, WPARAM, LPARAM, LRESULT> method)
|
||||
{
|
||||
value = method;
|
||||
}
|
||||
|
||||
public static WNDPROC Create(delegate* unmanaged[Stdcall]<HWND, uint, WPARAM, LPARAM, LRESULT> method)
|
||||
{
|
||||
return new(method);
|
||||
}
|
||||
}
|
||||
53
src/Snap.Hutao/Snap.Hutao/Win32/UnmanagedAccess.cs
Normal file
53
src/Snap.Hutao/Snap.Hutao/Win32/UnmanagedAccess.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Snap.Hutao.Win32;
|
||||
|
||||
internal readonly struct UnmanagedAccess<T> : IDisposable
|
||||
where T : class
|
||||
{
|
||||
private readonly nint handle;
|
||||
|
||||
public UnmanagedAccess(T value)
|
||||
{
|
||||
handle = GCHandle.ToIntPtr(GCHandle.Alloc(value));
|
||||
}
|
||||
|
||||
public static implicit operator nint(UnmanagedAccess<T> access)
|
||||
{
|
||||
return access.handle;
|
||||
}
|
||||
|
||||
public static implicit operator nuint(UnmanagedAccess<T> access)
|
||||
{
|
||||
return (nuint)access.handle;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GCHandle.FromIntPtr(handle).Free();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class UnmanagedAccess
|
||||
{
|
||||
public static UnmanagedAccess<T> Create<T>(T value)
|
||||
where T : class
|
||||
{
|
||||
return new UnmanagedAccess<T>(value);
|
||||
}
|
||||
|
||||
public static T? Get<T>(nint handle)
|
||||
where T : class
|
||||
{
|
||||
return GCHandle.FromIntPtr(handle).Target as T;
|
||||
}
|
||||
|
||||
public static T? Get<T>(nuint handle)
|
||||
where T : class
|
||||
{
|
||||
return GCHandle.FromIntPtr((nint)handle).Target as T;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using System.Runtime.Versioning;
|
||||
namespace Snap.Hutao.Win32;
|
||||
|
||||
[SuppressMessage("", "SH002")]
|
||||
[SuppressMessage("", "SA1313")]
|
||||
[SuppressMessage("", "SYSLIB1054")]
|
||||
internal static class User32
|
||||
{
|
||||
@@ -19,7 +20,30 @@ internal static class User32
|
||||
[SupportedOSPlatform("windows5.1.2600")]
|
||||
public static extern BOOL AttachThreadInput(uint idAttach, uint idAttachTo, BOOL fAttach);
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("USER32.dll", ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static unsafe extern HWND CreateWindowExW(WINDOW_EX_STYLE dwExStyle, [AllowNull] PCWSTR lpClassName, [AllowNull] PCWSTR lpWindowName, WINDOW_STYLE dwStyle, int X, int Y, int nWidth, int nHeight, [AllowNull] HWND hWndParent, [AllowNull] HMENU hMenu, [AllowNull] HINSTANCE hInstance, [AllowNull] void* lpParam);
|
||||
|
||||
public static unsafe HWND CreateWindowExW(WINDOW_EX_STYLE dwExStyle, [AllowNull] string className, [AllowNull] string windowName, WINDOW_STYLE dwStyle, int X, int Y, int nWidth, int nHeight, [AllowNull] HWND hWndParent, [AllowNull] HMENU hMenu, [AllowNull] HINSTANCE hInstance, [AllowNull] void* lpParam)
|
||||
{
|
||||
fixed (char* lpClassName = className)
|
||||
{
|
||||
fixed (char* lpWindowName = windowName)
|
||||
{
|
||||
return CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern LRESULT DefWindowProcW(HWND hWnd, uint Msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern BOOL DestroyWindow(HWND hWnd);
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern HWND FindWindowExW([AllowNull] HWND hWndParent, [AllowNull] HWND hWndChildAfter, [AllowNull] PCWSTR lpszClass, [AllowNull] PCWSTR lpszWindow);
|
||||
|
||||
@@ -47,7 +71,7 @@ internal static class User32
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern HWND GetForegroundWindow();
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern nint GetWindowLongPtrW(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex);
|
||||
|
||||
@@ -93,6 +117,18 @@ internal static class User32
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
public static extern BOOL RegisterHotKey([AllowNull] HWND hWnd, int id, HOT_KEY_MODIFIERS fsModifiers, uint vk);
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern uint RegisterWindowMessageW(PCWSTR lpString);
|
||||
|
||||
public static unsafe uint RegisterWindowMessageW(string @string)
|
||||
{
|
||||
fixed (char* lpString = @string)
|
||||
{
|
||||
return RegisterWindowMessageW(lpString);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern int ReleaseDC([AllowNull] HWND hWnd, HDC hDC);
|
||||
@@ -127,7 +163,7 @@ internal static class User32
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern BOOL SetForegroundWindow(HWND hWnd);
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern BOOL SetPropW(HWND hWnd, PCWSTR lpString, [AllowNull] HANDLE hData);
|
||||
|
||||
@@ -140,7 +176,7 @@ internal static class User32
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
[DllImport("USER32.dll", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true)]
|
||||
[SupportedOSPlatform("windows5.0")]
|
||||
public static extern nint SetWindowLongPtrW(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, nint dwNewLong);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user