using BetterGenshinImpact.View.Windows; using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Vanara.PInvoke; namespace BetterGenshinImpact.GameTask; public class SystemControl { public static nint FindGenshinImpactHandle() { return FindHandleByProcessName("YuanShen", "GenshinImpact", "Genshin Impact Cloud Game", "Genshin Impact Cloud"); } public static async Task StartFromLocalAsync(string path) { if (!File.Exists(path)) { await ThemedMessageBox.ErrorAsync($"原神启动路径 {path} 不存在,请前往 启动——同时启动原神——原神安装路径 重新进行配置!"); return IntPtr.Zero; } var cfg = TaskContext.Instance().Config.GenshinStartConfig; var workdir = Path.GetDirectoryName(path) ?? ""; var arg = cfg.GenshinStartArgs; if (cfg.StartGameWithCmd) { var psi = new ProcessStartInfo { FileName = "cmd.exe", Arguments = $"/c start \"\" /d \"{workdir}\" \"{path}\" {arg}", UseShellExecute = false, CreateNoWindow = true }; Process.Start(psi); } else { Process.Start(new ProcessStartInfo(path) { UseShellExecute = true, Arguments = arg, WorkingDirectory = workdir }); } for (var i = 0; i < 5; i++) { var handle = FindGenshinImpactHandle(); if (handle != 0) { await Task.Delay(2333); handle = FindGenshinImpactHandle(); await Task.Delay(2577); return handle; } await Task.Delay(5577); } return FindGenshinImpactHandle(); } public static bool IsGenshinImpactActiveByProcess() { var name = GetActiveProcessName(); return name is "YuanShen" or "yuanshen" or "GenshinImpact" or "Genshin Impact Cloud Game"; } public static string GetActiveByProcess() { return GetActiveProcessName() ?? "Unknown"; } public static bool IsGenshinImpactActive() { var hWnd = User32.GetForegroundWindow(); return hWnd == TaskContext.Instance().GameHandle; } public static nint GetForegroundWindowHandle() { return (nint)User32.GetForegroundWindow(); } public static nint FindHandleByProcessName(params string[] names) { foreach (var name in names) { var pros = Process.GetProcessesByName(name); if (pros.Length is not 0) { return pros[0].MainWindowHandle; } } return 0; } public static nint FindHandleByWindowName() { var handle = (nint)User32.FindWindow("UnityWndClass", "原神"); if (handle != 0) { return handle; } handle = (nint)User32.FindWindow("UnityWndClass", "Genshin Impact"); if (handle != 0) { return handle; } handle = (nint)User32.FindWindow("Qt5152QWindowIcon", "云·原神"); if (handle != 0) { return handle; } return 0; } public static string? GetActiveProcessName() { try { var hWnd = User32.GetForegroundWindow(); _ = User32.GetWindowThreadProcessId(hWnd, out var pid); var p = Process.GetProcessById((int)pid); return p.ProcessName; } catch { return null; } } public static Process? GetProcessByHandle(nint hWnd) { try { _ = User32.GetWindowThreadProcessId(hWnd, out var pid); var p = Process.GetProcessById((int)pid); return p; } catch (Exception ex) { Debug.WriteLine(ex); return null; } } /// /// 获取窗口位置 /// /// /// public static RECT GetWindowRect(nint hWnd) { // User32.GetWindowRect(hWnd, out var windowRect); DwmApi.DwmGetWindowAttribute(hWnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out var windowRect); return windowRect; } /// /// 游戏本身分辨率获取 /// /// /// public static RECT GetGameScreenRect(nint hWnd) { User32.GetClientRect(hWnd, out var clientRect); return clientRect; } /// /// GetWindowRect or GetGameScreenRect /// /// /// public static RECT GetCaptureRect(nint hWnd) { var windowRect = GetWindowRect(hWnd); var gameScreenRect = GetGameScreenRect(hWnd); var left = windowRect.Left; var top = windowRect.Top + windowRect.Height - gameScreenRect.Height; var right = left + gameScreenRect.Width; var bottom = top + gameScreenRect.Height; return new RECT(left, top, right, bottom); } public static void ActivateWindow(nint hWnd) { User32.ShowWindow(hWnd, ShowWindowCommand.SW_RESTORE); User32.SetForegroundWindow(hWnd); } public static void ActivateWindow() { if (!TaskContext.Instance().IsInitialized) { throw new Exception("请先启动BetterGI"); } ActivateWindow(TaskContext.Instance().GameHandle); } public static void RestartApplication(string[] newArgs) { // 获取当前程序路径 string exePath = Process.GetCurrentProcess().MainModule.FileName; // 构建参数字符串 string arguments = string.Join(" ", [..newArgs,"--no-single"]); // 启动新进程 Process.Start(new ProcessStartInfo { FileName = exePath, Arguments = arguments, UseShellExecute = false }); // 关闭当前程序 Environment.Exit(0); } public static void FocusWindow(nint hWnd) { if (User32.IsWindow(hWnd)) { _ = User32.SendMessage(hWnd, User32.WindowMessage.WM_SYSCOMMAND, User32.SysCommand.SC_RESTORE, 0); _ = User32.SetForegroundWindow(hWnd); while (User32.IsIconic(hWnd)) { continue; } _ = User32.BringWindowToTop(hWnd); _ = User32.SetActiveWindow(hWnd); } } public static void MinimizeAndActivateWindow(nint hWnd) { HWND hShell = User32.FindWindow("Shell_TrayWnd", null); User32.SendMessage(hShell, 0x0111, (IntPtr)419, IntPtr.Zero); Thread.Sleep(500); FocusWindow(hWnd); } public static void RestoreWindow(nint hWnd) { if (User32.IsWindow(hWnd)) { _ = User32.SendMessage(hWnd, User32.WindowMessage.WM_SYSCOMMAND, User32.SysCommand.SC_RESTORE, 0); _ = User32.SetForegroundWindow(hWnd); if (User32.IsIconic(hWnd)) { _ = User32.ShowWindow(hWnd, ShowWindowCommand.SW_RESTORE); } _ = User32.BringWindowToTop(hWnd); _ = User32.SetActiveWindow(hWnd); } } public static bool IsFullScreenMode(IntPtr hWnd) { if (hWnd == IntPtr.Zero) { return false; } var exStyle = User32.GetWindowLong(hWnd, User32.WindowLongFlags.GWL_EXSTYLE); return (exStyle & (int)User32.WindowStylesEx.WS_EX_TOPMOST) != 0; } // private static void StartFromLauncher(string path) // { // // 通过launcher启动 // var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); // Thread.Sleep(1000); // // 获取launcher窗口句柄 // var hWnd = FindHandleByProcessName("launcher"); // var rect = GetWindowRect(hWnd); // var dpiScale = Helpers.DpiHelper.ScaleY; // // 对于launcher,启动按钮的位置时固定的,在launcher窗口的右下角 // Thread.Sleep(1000); // Simulation.MouseEvent.Click((int)((float)rect.right * dpiScale) - (rect.Width / 5), (int)((float)rect.bottom * dpiScale) - (rect.Height / 8)); // } // // private static void StartCloudYaunShen(string path) // { // // 通过launcher启动 // var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); // Thread.Sleep(10000); // // 获取launcher窗口句柄 // var hWnd = FindHandleByProcessName("Genshin Impact Cloud Game"); // var rect = GetWindowRect(hWnd); // var dpiScale = Helpers.DpiHelper.ScaleY; // // 对于launcher,启动按钮的位置时固定的,在launcher窗口的右下角 // Simulation.MouseEvent.Click(rect.right - (rect.Width / 6), rect.bottom - (rect.Height / 13 * 3)); // // TODO:点完之后有个15s的倒计时,好像不处理也没什么问题,直接睡个20s吧 // Thread.Sleep(20000); // } public static void CloseGame() { try { // 尝试通过进程名称查找原神进程 var processes = Process.GetProcessesByName("YuanShen") .Concat(Process.GetProcessesByName("GenshinImpact")) .Concat(Process.GetProcessesByName("Genshin Impact Cloud Game")) .ToArray(); if (processes.Length > 0) { foreach (var process in processes) { try { // 尝试正常关闭进程 process.CloseMainWindow(); // 给进程一些时间来响应关闭请求 if (!process.WaitForExit(5000)) { // 如果进程没有在5秒内关闭,则强制终止它 process.Kill(); } } catch (Exception ex) { Debug.WriteLine($"关闭游戏进程时出错: {ex.Message}"); } finally { process.Dispose(); } } } } catch (Exception ex) { Debug.WriteLine($"CloseGame方法执行出错: {ex.Message}"); } } public static void Shutdown() { try { // 使用Windows API安全关闭系统 // 这里使用的是标准的Windows关机命令,需要适当的权限 Process.Start("shutdown", "/s /t 60 /c \"系统将在60秒后关闭,请保存您的工作。\""); } catch (Exception ex) { Debug.WriteLine($"Shutdown方法执行出错: {ex.Message}"); } } }