diff --git a/Daybreak.Core/Services/ApplicationLauncher/ApplicationLauncher.cs b/Daybreak.Core/Services/ApplicationLauncher/ApplicationLauncher.cs
index de1bbdbb..801946bc 100644
--- a/Daybreak.Core/Services/ApplicationLauncher/ApplicationLauncher.cs
+++ b/Daybreak.Core/Services/ApplicationLauncher/ApplicationLauncher.cs
@@ -536,18 +536,7 @@ internal sealed class ApplicationLauncher(
var scopedLogger = this.logger.CreateScopedLogger();
try
{
- var process = guildWarsApplicationLaunchContext.GuildWarsProcess;
- if (
- process.MainModule?.FileName is not null
- && process.MainModule.FileName.Contains(
- "Gw.exe",
- StringComparison.OrdinalIgnoreCase
- )
- )
- {
- process.Kill(true);
- return;
- }
+ this.guildWarsProcessFinder.KillProcess(guildWarsApplicationLaunchContext);
}
catch (Exception e)
when (e.Message.Contains(
diff --git a/Daybreak.Linux/Services/ApplicationLauncher/GuildWarsProcessFinder.cs b/Daybreak.Linux/Services/ApplicationLauncher/GuildWarsProcessFinder.cs
index 6275f320..cac16c91 100644
--- a/Daybreak.Linux/Services/ApplicationLauncher/GuildWarsProcessFinder.cs
+++ b/Daybreak.Linux/Services/ApplicationLauncher/GuildWarsProcessFinder.cs
@@ -52,6 +52,19 @@ public sealed class GuildWarsProcessFinder(
return this.FindProcesses(configuration).FirstOrDefault();
}
+ ///
+ /// Terminates the Wine-hosted Guild Wars process tree.
+ /// The process was already validated as a Gw.exe Wine process during discovery,
+ /// so we kill it directly. On Linux the process exposed by the context is the
+ /// Wine loader hosting Gw.exe; its therefore
+ /// points at the Wine loader rather than Gw.exe, which is why platform-agnostic
+ /// name checks cannot be used here.
+ ///
+ public void KillProcess(GuildWarsApplicationLaunchContext guildWarsApplicationLaunchContext)
+ {
+ guildWarsApplicationLaunchContext.GuildWarsProcess.Kill(entireProcessTree: true);
+ }
+
public IEnumerable FindProcesses(
params LaunchConfigurationWithCredentials[] configurations
)
diff --git a/Daybreak.Shared/Services/ApplicationLauncher/IGuildWarsProcessFinder.cs b/Daybreak.Shared/Services/ApplicationLauncher/IGuildWarsProcessFinder.cs
index a32b1edd..4cb3fd59 100644
--- a/Daybreak.Shared/Services/ApplicationLauncher/IGuildWarsProcessFinder.cs
+++ b/Daybreak.Shared/Services/ApplicationLauncher/IGuildWarsProcessFinder.cs
@@ -30,4 +30,12 @@ public interface IGuildWarsProcessFinder
IEnumerable FindProcesses(
params LaunchConfigurationWithCredentials[] configurations
);
+
+ ///
+ /// Terminates the Guild Wars process associated with the given launch context.
+ /// Implementations are responsible for handling platform-specific process layouts
+ /// (e.g. Wine-hosted processes on Linux). May throw, allowing the caller to handle
+ /// platform-specific failures such as insufficient privileges.
+ ///
+ void KillProcess(GuildWarsApplicationLaunchContext guildWarsApplicationLaunchContext);
}
diff --git a/Daybreak.Windows/Services/ApplicationLauncher/GuildWarsProcessFinder.cs b/Daybreak.Windows/Services/ApplicationLauncher/GuildWarsProcessFinder.cs
index 8636ceaa..6676099a 100644
--- a/Daybreak.Windows/Services/ApplicationLauncher/GuildWarsProcessFinder.cs
+++ b/Daybreak.Windows/Services/ApplicationLauncher/GuildWarsProcessFinder.cs
@@ -28,6 +28,24 @@ public sealed class GuildWarsProcessFinder : IGuildWarsProcessFinder
return this.FindProcesses(configuration).FirstOrDefault();
}
+ ///
+ /// Terminates the Guild Wars process tree. Guards against killing an unrelated
+ /// process by verifying the main module is Gw.exe. Reading the main module of an
+ /// elevated process throws a , which is propagated so
+ /// the caller can fall back to a direct kill or request elevation.
+ ///
+ public void KillProcess(GuildWarsApplicationLaunchContext guildWarsApplicationLaunchContext)
+ {
+ var process = guildWarsApplicationLaunchContext.GuildWarsProcess;
+ if (
+ process.MainModule?.FileName is not null
+ && process.MainModule.FileName.Contains("Gw.exe", StringComparison.OrdinalIgnoreCase)
+ )
+ {
+ process.Kill(true);
+ }
+ }
+
public IEnumerable FindProcesses(
params LaunchConfigurationWithCredentials[] configurations
)