using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using XFEEDToolBox.Core.Session;
namespace XFEEDToolBox.Services;
public sealed record StartupNoticeControl(int Id,string ClassName,string Text);
/// <summary>Dismisses only the observed informational translation notice of the exact bootstrap client.</summary>
public static class KnownTranslationStartupNotice
{
private const string Notice="EliteDangerous汉化补丁已加载\n\n本补丁由TowaNoah及EliteDangerous中文汉化组制作免费发布\n\n如果你是通过付费渠道获取的本补丁,请举报退款,倒卖必究";
private static string Compact(string text)=>string.Concat(text.Where(c=>!char.IsWhiteSpace(c)));
public static bool Matches(string title,string className,IReadOnlyList<StartupNoticeControl> controls)
=>title=="提示"&&className=="#32770"
&&controls.Count(c=>c.ClassName=="Button")==1
&&controls.Any(c=>c.ClassName=="Button"&&c.Id==2&&c.Text=="确定")
&&controls.Count(c=>c.ClassName=="Static"&&c.Text.Length>0)==1
&&controls.Any(c=>c.ClassName=="Static"&&Compact(c.Text)==Compact(Notice));
public static bool TryDismiss(GameSessionTarget target,CancellationToken token)
{
token.ThrowIfCancellationRequested();
using var process=Process.GetProcessById(target.ProcessId);
if(process.HasExited||process.StartTime.ToUniversalTime().Ticks!=target.StartedUtcTicks
||!string.Equals(process.MainModule?.FileName,target.Executable,StringComparison.OrdinalIgnoreCase))return false;
var dismissed=false;var timedOut=false;
EnumWindows((window,parameter)=>
{
if(token.IsCancellationRequested)return false;
_=GetWindowThreadProcessId(window,out var pid);
if(pid!=target.ProcessId||!IsWindowVisible(window))return true;
var controls=new List<StartupNoticeControl>();nint button=0;
EnumChildWindows(window,(child,childParameter)=>
{
var kind=Text(child,true);var text=Text(child,false);var id=GetDlgCtrlID(child);
controls.Add(new(id,kind,text));if(kind=="Button"&&id==2)button=child;return true;
},0);
if(button==0||!Matches(Text(window,false),Text(window,true),controls))return true;
_=GetWindowThreadProcessId(button,out var buttonPid);
if(buttonPid!=target.ProcessId||process.HasExited)return true;
// WM_COMMAND follows this dialog's own confirmation handler without activating it or synthesizing keyboard input.
timedOut=SendMessageTimeout(window,0x0111,2,button,0x0002,1000,out _)==0;
dismissed=!timedOut;return false;
},0);
token.ThrowIfCancellationRequested();
if(timedOut)throw new IOException("已识别汉化启动提示,但确认操作超时,已保留当前客户端。");
return dismissed;
}
private static string Text(nint window,bool className)
{
var text=new StringBuilder(className?256:4096);
if(className)_=GetClassName(window,text,text.Capacity);else _=GetWindowText(window,text,text.Capacity);
return text.ToString();
}
private delegate bool WindowCallback(nint window,nint parameter);
[DllImport("user32.dll")]private static extern bool EnumWindows(WindowCallback callback,nint parameter);
[DllImport("user32.dll")]private static extern bool EnumChildWindows(nint window,WindowCallback callback,nint parameter);
[DllImport("user32.dll")]private static extern uint GetWindowThreadProcessId(nint window,out uint processId);
[DllImport("user32.dll")]private static extern bool IsWindowVisible(nint window);
[DllImport("user32.dll")]private static extern int GetDlgCtrlID(nint window);
[DllImport("user32.dll",CharSet=CharSet.Unicode)]private static extern int GetWindowText(nint window,StringBuilder text,int capacity);
[DllImport("user32.dll",CharSet=CharSet.Unicode)]private static extern int GetClassName(nint window,StringBuilder text,int capacity);
[DllImport("user32.dll",CharSet=CharSet.Unicode)]private static extern nint SendMessageTimeout(nint window,uint message,nuint wParam,nint lParam,uint flags,uint milliseconds,out nuint result);
}
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using XFEEDToolBox.Core.Session;
namespace XFEEDToolBox.Services;
public sealed record StartupNoticeControl(int Id,string ClassName,string Text);
/// <summary>Dismisses only the observed informational translation notice of the exact bootstrap client.</summary>
public static class KnownTranslationStartupNotice
{
private const string Notice="EliteDangerous汉化补丁已加载\n\n本补丁由TowaNoah及EliteDangerous中文汉化组制作免费发布\n\n如果你是通过付费渠道获取的本补丁,请举报退款,倒卖必究";
private static string Compact(string text)=>string.Concat(text.Where(c=>!char.IsWhiteSpace(c)));
public static bool Matches(string title,string className,IReadOnlyList<StartupNoticeControl> controls)
=>title=="提示"&&className=="#32770"
&&controls.Count(c=>c.ClassName=="Button")==1
&&controls.Any(c=>c.ClassName=="Button"&&c.Id==2&&c.Text=="确定")
&&controls.Count(c=>c.ClassName=="Static"&&c.Text.Length>0)==1
&&controls.Any(c=>c.ClassName=="Static"&&Compact(c.Text)==Compact(Notice));
public static bool TryDismiss(GameSessionTarget target,CancellationToken token)
{
token.ThrowIfCancellationRequested();
using var process=Process.GetProcessById(target.ProcessId);
if(process.HasExited||process.StartTime.ToUniversalTime().Ticks!=target.StartedUtcTicks
||!string.Equals(process.MainModule?.FileName,target.Executable,StringComparison.OrdinalIgnoreCase))return false;
var dismissed=false;var timedOut=false;
EnumWindows((window,parameter)=>
{
if(token.IsCancellationRequested)return false;
_=GetWindowThreadProcessId(window,out var pid);
if(pid!=target.ProcessId||!IsWindowVisible(window))return true;
var controls=new List<StartupNoticeControl>();nint button=0;
EnumChildWindows(window,(child,childParameter)=>
{
var kind=Text(child,true);var text=Text(child,false);var id=GetDlgCtrlID(child);
controls.Add(new(id,kind,text));if(kind=="Button"&&id==2)button=child;return true;
},0);
if(button==0||!Matches(Text(window,false),Text(window,true),controls))return true;
_=GetWindowThreadProcessId(button,out var buttonPid);
if(buttonPid!=target.ProcessId||process.HasExited)return true;
// WM_COMMAND follows this dialog's own confirmation handler without activating it or synthesizing keyboard input.
timedOut=SendMessageTimeout(window,0x0111,2,button,0x0002,1000,out _)==0;
dismissed=!timedOut;return false;
},0);
token.ThrowIfCancellationRequested();
if(timedOut)throw new IOException("已识别汉化启动提示,但确认操作超时,已保留当前客户端。");
return dismissed;
}
private static string Text(nint window,bool className)
{
var text=new StringBuilder(className?256:4096);
if(className)_=GetClassName(window,text,text.Capacity);else _=GetWindowText(window,text,text.Capacity);
return text.ToString();
}
private delegate bool WindowCallback(nint window,nint parameter);
[DllImport("user32.dll")]private static extern bool EnumWindows(WindowCallback callback,nint parameter);
[DllImport("user32.dll")]private static extern bool EnumChildWindows(nint window,WindowCallback callback,nint parameter);
[DllImport("user32.dll")]private static extern uint GetWindowThreadProcessId(nint window,out uint processId);
[DllImport("user32.dll")]private static extern bool IsWindowVisible(nint window);
[DllImport("user32.dll")]private static extern int GetDlgCtrlID(nint window);
[DllImport("user32.dll",CharSet=CharSet.Unicode)]private static extern int GetWindowText(nint window,StringBuilder text,int capacity);
[DllImport("user32.dll",CharSet=CharSet.Unicode)]private static extern int GetClassName(nint window,StringBuilder text,int capacity);
[DllImport("user32.dll",CharSet=CharSet.Unicode)]private static extern nint SendMessageTimeout(nint window,uint message,nuint wParam,nint lParam,uint flags,uint milliseconds,out nuint result);
}