feat: winapi 关机/睡眠/休眠

This commit is contained in:
uye
2024-08-17 15:49:02 +08:00
parent 7b7dcc81f5
commit 6ed153dfb7
4 changed files with 173 additions and 8 deletions

View File

@@ -31,6 +31,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=WSA/@EntryIndexedValue">WSA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/Abbreviations/=XYAZ/@EntryIndexedValue">XYAZ</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acast/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=advapi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aero/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Affero/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=aguard/@EntryIndexedValue">True</s:Boolean>
@@ -92,6 +93,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pallas/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pidl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pormpt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=powrprof/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ppidl/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pwfi/@EntryIndexedValue">True</s:Boolean>

View File

@@ -0,0 +1,144 @@
// <copyright file="PowerManagement.cs" company="MaaAssistantArknights">
// 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
// </copyright>
using System;
using System.Runtime.InteropServices;
using Serilog;
namespace MaaWpfGui.Utilities
{
public class PowerManagement
{
private static readonly ILogger _logger = Log.ForContext<PowerManagement>();
[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;
}
}
}
}

View File

@@ -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<bool> TimerCanceledAsync()
private static async Task<bool> 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;

View File

@@ -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"