XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using XFEEDToolBox.Core.Session;

namespace XFEEDToolBox.Services;

public static class OwnedStartupCrashReporter
{
    public static bool Matches(string game,string reporter,string commandLine,DateTimeOffset started,StartupCrashEvidence crash)
    {
        var installation=Directory.GetParent(Path.GetDirectoryName(Path.GetFullPath(game))!)?.Parent?.FullName;
        if(installation is null||!string.Equals(Path.GetFullPath(reporter),Path.Combine(installation,"CrashReporter.exe"),StringComparison.OrdinalIgnoreCase)
            ||started<crash.At.AddSeconds(-5)||started>crash.At.AddMinutes(1))return false;
        foreach(Match match in Regex.Matches(commandLine,"(?:\"(?<path>[^\"]+\\.dmp)\"|(?<path>\\S+\\.dmp))",RegexOptions.IgnoreCase))
            try{if(string.Equals(Path.GetFullPath(match.Groups["path"].Value),Path.GetFullPath(crash.Path),StringComparison.OrdinalIgnoreCase))return true;}
            catch(ArgumentException){}
        return false;
    }
    public static async Task CloseAsync(string game,StartupCrashEvidence crash,CancellationToken token)
    {
        foreach(var reporter in Process.GetProcessesByName("CrashReporter"))
        using(reporter)
        {
            token.ThrowIfCancellationRequested();string? path,line;DateTimeOffset started;
            try{path=reporter.MainModule?.FileName;line=CommandLine(reporter);started=reporter.StartTime.ToUniversalTime();}
            catch(Exception error)when(error is InvalidOperationException or System.ComponentModel.Win32Exception){continue;}
            if(path is null||line is null||!Matches(game,path,line,started,crash))continue;
            if(!reporter.CloseMainWindow())throw new IOException("已确认本次崩溃报告器,但它未接受关闭,未重复启动客户端。");
            await reporter.WaitForExitAsync(token).WaitAsync(TimeSpan.FromSeconds(15),token).ConfigureAwait(false);
        }
    }
    [DllImport("ntdll.dll")]private static extern int NtQueryInformationProcess(nint process,int information,nint buffer,uint length,out uint required);
    private static string? CommandLine(Process process)
    {
        _=NtQueryInformationProcess(process.Handle,60,0,0,out var length);if(length is <16 or >65536)return null;
        var buffer=Marshal.AllocHGlobal((int)length);
        try
        {
            if(NtQueryInformationProcess(process.Handle,60,buffer,length,out _)!=0)return null;
            var bytes=(ushort)Marshal.ReadInt16(buffer);var pointer=Marshal.ReadIntPtr(buffer,8);
            if(bytes%2!=0||pointer<buffer||pointer>buffer+(int)length-bytes)return null;
            return Marshal.PtrToStringUni(pointer,bytes/2);
        }
        finally{Marshal.FreeHGlobal(buffer);}
    }
}