From 6ed153dfb77a71032db8db8b310e579cb54a64bf Mon Sep 17 00:00:00 2001
From: uye <99072975+ABA2396@users.noreply.github.com>
Date: Sat, 17 Aug 2024 15:49:02 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20winapi=20=E5=85=B3=E6=9C=BA/=E7=9D=A1?=
=?UTF-8?q?=E7=9C=A0/=E4=BC=91=E7=9C=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
MAA.sln.DotSettings | 2 +
src/MaaWpfGui/Utilities/PowerManagement.cs | 144 ++++++++++++++++++
.../ViewModels/UI/TaskQueueViewModel.cs | 33 +++-
src/MaaWpfGui/Views/UI/ErrorView.xaml | 2 +-
4 files changed, 173 insertions(+), 8 deletions(-)
create mode 100644 src/MaaWpfGui/Utilities/PowerManagement.cs
diff --git a/MAA.sln.DotSettings b/MAA.sln.DotSettings
index 1fa37b254d..3e53fc188c 100644
--- a/MAA.sln.DotSettings
+++ b/MAA.sln.DotSettings
@@ -31,6 +31,7 @@
WSA
XYAZ
True
+ True
True
True
True
@@ -92,6 +93,7 @@
True
True
True
+ True
True
True
True
diff --git a/src/MaaWpfGui/Utilities/PowerManagement.cs b/src/MaaWpfGui/Utilities/PowerManagement.cs
new file mode 100644
index 0000000000..fa0fe60972
--- /dev/null
+++ b/src/MaaWpfGui/Utilities/PowerManagement.cs
@@ -0,0 +1,144 @@
+//
+// MaaWpfGui - A part of the MaaCoreArknights project
+// Copyright (C) 2021 MistEO and Contributors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License v3.0 only as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY
+//
+
+using System;
+using System.Runtime.InteropServices;
+using Serilog;
+
+namespace MaaWpfGui.Utilities
+{
+ public class PowerManagement
+ {
+ private static readonly ILogger _logger = Log.ForContext();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern bool ExitWindowsEx(uint uFlags, uint dwReason);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLengthInBytes, IntPtr PreviousState, IntPtr ReturnLengthInBytes);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr GetCurrentProcess();
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
+ private static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);
+
+ [DllImport("powrprof.dll", SetLastError = true, ExactSpelling = true)]
+ private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool CloseHandle(IntPtr hObject);
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ private struct TOKEN_PRIVILEGES
+ {
+ public int PrivilegeCount;
+ public LUID Luid;
+ public int Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct LUID
+ {
+ public uint LowPart;
+ public int HighPart;
+ }
+
+ private const int SE_PRIVILEGE_ENABLED = 0x00000002;
+ private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
+ private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
+ private const int TOKEN_QUERY = 0x0008;
+ private const int EWX_SHUTDOWN = 0x00000001;
+ private const int EWX_FORCE = 0x00000004;
+
+ public static bool Shutdown()
+ {
+ IntPtr hToken = IntPtr.Zero;
+ TOKEN_PRIVILEGES tkp;
+
+ try
+ {
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken))
+ {
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ if (!LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, out tkp.Luid))
+ {
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ tkp.PrivilegeCount = 1;
+ tkp.Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!AdjustTokenPrivileges(hToken, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero))
+ {
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ if (Marshal.GetLastWin32Error() != 0)
+ {
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0))
+ {
+ throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ _logger.Error($"Shutdown error: {ex.Message}");
+ return false;
+ }
+ finally
+ {
+ if (hToken != IntPtr.Zero)
+ {
+ CloseHandle(hToken);
+ }
+ }
+ }
+
+ public static bool Hibernate()
+ {
+ try
+ {
+ return SetSuspendState(true, true, true);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error($"Hibernate error: {ex.Message}");
+ return false;
+ }
+ }
+
+ public static bool Sleep()
+ {
+ try
+ {
+ return SetSuspendState(false, true, true);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error($"Sleep error: {ex.Message}");
+ return false;
+ }
+ }
+ }
+}
diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs
index c49f0a65ea..d4c95178f9 100644
--- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs
+++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs
@@ -197,12 +197,16 @@ namespace MaaWpfGui.ViewModels.UI
// 休眠提示
AddLog(LocalizationHelper.GetString("HibernatePrompt"), UiLogColor.Error);
+ /*
// 休眠不能加时间参数,https://github.com/MaaAssistantArknights/MaaAssistantArknights/issues/1133
Process.Start("shutdown.exe", "-h");
+ */
+ PowerManagement.Hibernate();
}
- void DoShutDown()
+ async void DoShutDown()
{
+ /*
Process.Start("shutdown.exe", "-s -t 60");
// 关机询问
@@ -211,6 +215,17 @@ namespace MaaWpfGui.ViewModels.UI
{
Process.Start("shutdown.exe", "-a");
}
+ */
+ if (await TimerCanceledAsync(
+ LocalizationHelper.GetString("Shutdown"),
+ LocalizationHelper.GetString("AboutToShutdown"),
+ LocalizationHelper.GetString("Cancel"),
+ 60))
+ {
+ return;
+ }
+
+ PowerManagement.Shutdown();
}
}
@@ -432,7 +447,11 @@ namespace MaaWpfGui.ViewModels.UI
Instances.MainWindowManager?.Show();
}
- if (await TimerCanceledAsync())
+ if (await TimerCanceledAsync(
+ LocalizationHelper.GetString("ForceScheduledStart"),
+ LocalizationHelper.GetString("ForceScheduledStartTip"),
+ LocalizationHelper.GetString("Cancel"),
+ 10))
{
return;
}
@@ -456,13 +475,13 @@ namespace MaaWpfGui.ViewModels.UI
LinkStart();
}
- private static async Task TimerCanceledAsync()
+ private static async Task TimerCanceledAsync(string content = "", string tipContent = "", string buttonContent="", int seconds = 10)
{
- var delay = TimeSpan.FromSeconds(10);
+ var delay = TimeSpan.FromSeconds(seconds);
var dialogUserControl = new Views.UserControl.TextDialogWithTimerUserControl(
- LocalizationHelper.GetString("ForceScheduledStart"),
- LocalizationHelper.GetString("ForceScheduledStartTip"),
- LocalizationHelper.GetString("Cancel"),
+ content,
+ tipContent,
+ buttonContent,
delay.TotalMilliseconds);
var dialog = HandyControl.Controls.Dialog.Show(dialogUserControl, nameof(Views.UI.RootView));
var canceled = false;
diff --git a/src/MaaWpfGui/Views/UI/ErrorView.xaml b/src/MaaWpfGui/Views/UI/ErrorView.xaml
index 21e5b9263b..8770401762 100644
--- a/src/MaaWpfGui/Views/UI/ErrorView.xaml
+++ b/src/MaaWpfGui/Views/UI/ErrorView.xaml
@@ -11,12 +11,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:styles="clr-namespace:MaaWpfGui.Styles"
x:Name="ErrorViewWindow"
- Icon="../../newlogo.ico"
Title="{DynamicResource Error}"
Width="600"
Height="480"
MinWidth="400"
MinHeight="200"
+ Icon="../../newlogo.ico"
ResizeMode="CanResize"
Topmost="True"
WindowStartupLocation="CenterScreen"