Files
Wand-Enhancer-k1tbyte/WandEnhancer/Utils/ProcessTerminator.cs
T
kitbyte 6716da5c80 feat(patch-engine): locate patches structurally instead of by signature
Anchor each patch on a stable string (API endpoint, IPC channel, method name)
and walk the delimiter structure via JsCursor to the edit site, reading
minified identifiers out of the located region.

Move injected JavaScript into WandEnhancer/Patches/*.js as embedded resources.
Declare patches as PatchEntry rows in EnhancerConfig with CandidateFileNames,
SearchHints and optional CapabilityHints.

Recognise keyword-preceded regex literals in JsCursor so `return/re/.test(x)`
no longer desynchronises the scan.
Require the remote setValue anchor to match exactly once; Wand ships sibling
call sites for other sources.
Require both backup halves in IsPatched so a partial backup no longer blocks
patch and restore at the same time.
Chain inner exceptions when unpack or pack fails.
Rename Common to ProcessTerminator and Utils.Extensions to WeModInstalls.
2026-08-29 16:56:09 +03:00

86 lines
2.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace WandEnhancer.Utils
{
public static class ProcessTerminator
{
private const int KillAttempts = 5;
private const int KillRetryDelayMs = 250;
public static void TryKillProcess(string processName)
{
// The launcher itself runs as Wand.exe; never target our own process.
int selfId = Process.GetCurrentProcess().Id;
for (int attempt = 0; attempt < KillAttempts; attempt++)
{
var processes = Others(Process.GetProcessesByName(processName), selfId);
try
{
if (processes.Length == 0)
{
return;
}
foreach (var process in processes)
{
try
{
process.Kill();
}
catch (Exception e) when (e is InvalidOperationException || e is System.ComponentModel.Win32Exception)
{
// Already exited, or protected: the post-loop check decides the outcome.
}
}
}
finally
{
foreach (var process in processes)
{
process.Dispose();
}
}
Thread.Sleep(KillRetryDelayMs);
}
var survivors = Others(Process.GetProcessesByName(processName), selfId);
try
{
if (survivors.Length > 0)
{
throw new InvalidOperationException($"Failed to close {processName}. Close it manually and try again.");
}
}
finally
{
foreach (var process in survivors)
{
process.Dispose();
}
}
}
private static Process[] Others(Process[] processes, int selfId)
{
var result = new List<Process>(processes.Length);
foreach (var process in processes)
{
if (process.Id == selfId)
{
process.Dispose();
continue;
}
result.Add(process);
}
return result.ToArray();
}
}
}