From bbe7c2cd034bb0b16b41b62bae1800b9bcf62c8a Mon Sep 17 00:00:00 2001 From: HolographicHat Date: Mon, 13 Jun 2022 17:43:02 +0800 Subject: [PATCH] update --- src/GlobalVars.cs | 16 +++++++-- src/Program.cs | 15 ++++---- src/Utils.cs | 72 +++++++++++++++++++++++++++++++++++++- src/Win32/Native.cs | 14 ++++++-- src/Win32/OpenFileFlags.cs | 9 +++++ src/Win32/OpenFileName.cs | 32 +++++++++++++++++ 6 files changed, 145 insertions(+), 13 deletions(-) create mode 100644 src/Win32/OpenFileFlags.cs create mode 100644 src/Win32/OpenFileName.cs diff --git a/src/GlobalVars.cs b/src/GlobalVars.cs index ad77b11..710627b 100644 --- a/src/GlobalVars.cs +++ b/src/GlobalVars.cs @@ -1,8 +1,18 @@ -namespace YaeAchievement; +using System.Diagnostics.CodeAnalysis; +namespace YaeAchievement; + +[SuppressMessage("Usage", "CA2211:非常量字段应当不可见")] +[SuppressMessage("ReSharper", "ConvertToConstant.Global")] +[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Global")] public static class GlobalVars { + public static bool Verbose = false; - public const string LibName = "YaeAchievementLib.dll"; - public const string PipeName = "YaeAchievementPipe"; public static bool UnexpectedExit = true; + public static string GamePath = ""; + + public const string LibName = "YaeLib.dll"; + public const string PipeName = "YaeAchievementPipe"; + public const string ConfigFileName = "YaeAchievement.runtimeconfig.json"; + } diff --git a/src/Program.cs b/src/Program.cs index c18b624..1887594 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,11 +1,12 @@ -using System.ComponentModel; -using System.Diagnostics; -using System.IO.Pipes; -using YaeAchievement; -using YaeAchievement.Win32; +using YaeAchievement; +using static YaeAchievement.Utils; - -Utils.StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => { +InstallExitHook(); +InstallExceptionHook(); +CheckGenshinIsRunning(); +LoadConfig(); +return; +StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => { GlobalVars.UnexpectedExit = false; //AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str)).List; //var notify = Serializer.Deserialize(stream)!; diff --git a/src/Utils.cs b/src/Utils.cs index 555279f..6fcc45e 100644 --- a/src/Utils.cs +++ b/src/Utils.cs @@ -1,11 +1,81 @@ using System.ComponentModel; using System.Diagnostics; using System.IO.Pipes; +using System.Runtime.InteropServices; +using System.Text.Json.Nodes; using YaeAchievement.Win32; +using static YaeAchievement.Win32.OpenFileFlags; namespace YaeAchievement; public static class Utils { + + public static void LoadConfig() { + var conf = JsonNode.Parse(File.ReadAllText(GlobalVars.ConfigFileName))!; + var path = conf["genshinPath"]; + if (path == null || CheckGamePathValid(path.GetValue())) { + GlobalVars.GamePath = SelectGameExecutable(); + conf["genshinPath"] = GlobalVars.GamePath; + File.WriteAllText(GlobalVars.ConfigFileName, conf.ToJsonString()); + } else { + GlobalVars.GamePath = path.GetValue(); + } + } + + private static bool CheckGamePathValid(string path) { + var dir = Path.GetDirectoryName(path)!; + return File.Exists($"{dir}/UnityPlayer.dll") && File.Exists($"{dir}/mhypbase.dll"); + } + + private static string SelectGameExecutable() { + var fnPtr = Marshal.AllocHGlobal(32768); + var ofn = new OpenFileName { + file = fnPtr, + size = Marshal.SizeOf(), + owner = Native.GetConsoleWindow(), + flags = Explorer | NoNetworkButton | FileMustExist | NoChangeDir, + title = "选择主程序", + filter = "国服/国际服主程序 (YuanShen/GenshinImpact.exe)\0YuanShen.exe;GenshinImpact.exe\0", + maxFile = 32768 + }; + if(!Native.GetOpenFileName(ofn)) { + var err = Native.CommDlgExtendedError(); + if (err != 0) { + throw new SystemException($"Dialog error: {err}"); + } + Console.WriteLine("操作被取消"); + Environment.Exit(0); + } + var path = Marshal.PtrToStringAuto(fnPtr)!; + Marshal.FreeHGlobal(fnPtr); + return path; + } + + public static void CheckGenshinIsRunning() { + Process.EnterDebugMode(); + foreach (var process in Process.GetProcesses()) { + if (process.ProcessName is "GenshinImpact" or "YuanShen") { + Console.WriteLine("原神正在运行,请关闭后重试"); + Environment.Exit(301); + } + } + Process.LeaveDebugMode(); + } + + public static void InstallExitHook() { + AppDomain.CurrentDomain.ProcessExit += (_, _) => { + Console.WriteLine("按任意键退出"); + Console.ReadKey(); + }; + } + + public static void InstallExceptionHook() { + AppDomain.CurrentDomain.UnhandledException += (_, e) => { + Console.WriteLine(e.ExceptionObject.ToString()); + Console.WriteLine("发生错误,请联系开发者以获取帮助"); + Environment.Exit(-1); + }; + } // ReSharper disable once UnusedMethodReturnValue.Global public static Thread StartAndWaitResult(string exePath, Func onReceive) { @@ -31,7 +101,7 @@ public static class Utils { proc.EnableRaisingEvents = true; proc.Exited += (_, _) => { if (GlobalVars.UnexpectedExit) { - Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}"); + Console.WriteLine("游戏进程异常退出"); Environment.Exit(114514); } }; diff --git a/src/Win32/Native.cs b/src/Win32/Native.cs index 4387b5f..11f14d1 100644 --- a/src/Win32/Native.cs +++ b/src/Win32/Native.cs @@ -41,7 +41,7 @@ public static class Native { [SuppressMessage("Globalization", "CA2101:指定对 P/Invoke 字符串参数进行封送处理")] public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); - [DllImport("kernel32.dll", SetLastError = true, ExactSpelling=true)] + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern IntPtr VirtualAllocEx( IntPtr hProcess, IntPtr lpAddress, @@ -50,7 +50,7 @@ public static class Native { MemoryProtection flProtect ); - [DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)] + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType); [DllImport("kernel32.dll", SetLastError = true)] @@ -71,4 +71,14 @@ public static class Native { uint dwCreationFlags, out IntPtr lpThreadId ); + + [DllImport("kernel32.dll")] + public static extern IntPtr GetConsoleWindow(); + + [DllImport("comdlg32.dll", SetLastError = true)] + public static extern int CommDlgExtendedError(); + + [DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool GetOpenFileName([In, Out] OpenFileName ofn); + } diff --git a/src/Win32/OpenFileFlags.cs b/src/Win32/OpenFileFlags.cs new file mode 100644 index 0000000..5969a98 --- /dev/null +++ b/src/Win32/OpenFileFlags.cs @@ -0,0 +1,9 @@ +namespace YaeAchievement.Win32; + +[Flags] +public enum OpenFileFlags : uint { + Explorer = 0x00080000, + NoChangeDir = 0x00000008, + FileMustExist = 0x00001000, + NoNetworkButton = 0x00020000, +} diff --git a/src/Win32/OpenFileName.cs b/src/Win32/OpenFileName.cs new file mode 100644 index 0000000..d83afdf --- /dev/null +++ b/src/Win32/OpenFileName.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; + +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable FieldCanBeMadeReadOnly.Global + +namespace YaeAchievement.Win32; +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] +public struct OpenFileName { + public int size; + public IntPtr owner; + public IntPtr instance; + public string filter; + public IntPtr customFilter; + public int maxCustFilter; + public int filterIndex; + public IntPtr file; + public int maxFile; + public IntPtr fileTitle; + public int maxFileTitle; + public string initialDir; + public string title; + public OpenFileFlags flags; + public short fileOffset; + public short fileExtension; + public string defExt; + public IntPtr custData; + public IntPtr hook; + public string templateName; + public IntPtr reservedPtr; + public int reservedInt; + public int flagsEx; +}