using System; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Reflection; using System.Text.Json; using System.Threading; using System.Windows; using PCL.Core.Logging; using PCL.Core.Utils; namespace PCL.Core.App; /// /// 基础工具集。 /// public static class Basics { #region 基本信息 /// /// 启动器元数据。 /// public static MetadataModel Metadata { get; } = JsonSerializer.Deserialize( Assembly.GetEntryAssembly()!.GetManifestResourceStream("PCL.metadata.json")!, JsonCompat.SerializerOptions)!; /// /// 版本名称。 /// public static string VersionName => Metadata.Version.BaseName; /// /// 版本内部代号。 /// public static int VersionCode => Metadata.Version.Code; /// /// 版本分支名。 /// public static string VersionBranch => Metadata.Version.BranchName; /// /// 当前日期是否为愚人节。 /// public static bool IsAprilFool => DateTime.Now is { Month: 4, Day: 1 }; #endregion #region 程序路径信息 /// /// 当前进程实例。 /// public static Process CurrentProcess { get; } = Process.GetCurrentProcess(); /// /// 当前进程 ID。 /// public static int CurrentProcessId { get; } = CurrentProcess.Id; /// /// 当前进程可执行文件的绝对路径。 /// public static string ExecutablePath { get; } = Environment.ProcessPath!; /// /// 当前进程可执行文件所在的目录。若有需求,请使用 而不是自行拼接路径。 /// public static string ExecutableDirectory { get; } = GetParentPath(ExecutablePath) ?? CurrentDirectory; /// /// 当前进程可执行文件的名称,含扩展名。 /// public static string ExecutableName { get; } = Path.GetFileName(ExecutablePath); /// /// 当前进程可执行文件的名称,不含扩展名。 /// public static string ExecutableNameWithoutExtension { get; } = Path.GetFileNameWithoutExtension(ExecutablePath); /// /// 当前进程包括第一个参数(文件名)的完整命令行参数。 /// public static string[] FullCommandLineArguments { get; } = Environment.GetCommandLineArgs(); /// /// 当前进程不包括第一个参数(文件名)的命令行参数。 /// public static string[] CommandLineArguments { get; } = FullCommandLineArguments[1..]; /// /// 实时获取的当前目录。若要在可执行文件目录中存放文件等内容,请使用更准确的 而不是这个目录。 /// public static string CurrentDirectory => Environment.CurrentDirectory; #endregion #region 线程操作 /// /// 在新的工作线程运行指定委托。 /// /// 要运行的委托 /// 线程名,默认为 WorkerThread@[ThreadId] /// 线程优先级 /// 新创建的线程实例 public static Thread RunInNewThread(Action action, string? name = null, ThreadPriority priority = ThreadPriority.Normal) { var threadName = new AtomicVariable(name); var thread = new Thread(() => { try { action(); } catch (ThreadInterruptedException) { LogWrapper.Trace("Thread", $"{threadName.Value}: 已中止"); } catch (Exception ex) { LogWrapper.Error(ex, "Thread", $"{threadName.Value}: 抛出异常"); } }) { Priority = priority }; threadName.Value ??= $"Worker#{thread.ManagedThreadId}"; thread.Name = threadName.Value; thread.Start(); return thread; } #endregion #region 路径操作 /// /// 获取某个路径的父路径/目录。 /// /// 路径文本 /// 父路径文本,可能为 null public static string? GetParentPath(string path) => Path.GetDirectoryName(path) ?? Path.GetPathRoot(path); /// /// 获取某个路径的父路径/目录。 /// /// 路径文本 /// 父路径文本,或空白 public static string GetParentPathOrEmpty(string path) => GetParentPath(path) ?? string.Empty; /// /// 获取某个路径的父路径/目录。 /// /// 路径文本 /// 父路径文本,或默认 () public static string GetParentPathOrDefault(string path) => GetParentPath(path) ?? CurrentDirectory; /// /// 以默认方式打开一个路径 (文件或目录) /// /// 路径文本 /// 执行工作目录 public static void OpenPath(string path, string? workingDirectory = null) { var psi = new ProcessStartInfo(path) { WorkingDirectory = workingDirectory ?? CurrentDirectory, UseShellExecute = true, CreateNoWindow = true }; try { Process.Start(psi); } catch (Win32Exception ex) when (ex.NativeErrorCode == 1155 && File.Exists(path)) { Process.Start(new ProcessStartInfo { FileName = "notepad.exe", Arguments = $"\"{path}\"", UseShellExecute = false }); } } #endregion #region 应用程序操作 /// /// 获取程序打包资源的输入流。该资源必须声明为 Resource 类型,否则将会报错,Images /// 和 Resources 目录已默认声明该类型。 /// /// 资源路径,例如 "Resources/java-wrapper.jar" /// 资源输入流,若资源不存在则为 null public static Stream? GetResourceStream(string path) { var resourceInfo = Application.GetResourceStream(new Uri($"pack://application:,,,/{path}", UriKind.Absolute)); return resourceInfo?.Stream; } private const string AssemblyImagePath = "pack://application:,,,/Plain Craft Launcher 2;component/Images/"; public static string GetAppImagePath(string imageName) => AssemblyImagePath + imageName; #endregion }