Files
wiicompiled/Launcher/WiiCompiled.Setup.Windows/UninstallService.cs
T
theofficialgman c0ed2bfbeb refactor WiiCompiled.Setup into WiiCompiled.Setup.Windows and add WiiCompiled.Setup.Common
the idea behind this is C# code that is OS agnostic can go in WiiCompiled.Setup.Common to be shared by any OS specific code (eg: WiiCompiled.Setup.Windows and WiiCompiled.Setup.Linux).
2026-08-29 12:06:58 -04:00

114 lines
4.5 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
using WiiCompiled.Setup.Common;
namespace WiiCompiled.Setup.Windows;
internal static class UninstallService
{
public static void StartWorker(string installDirectory, bool quiet = false)
{
var source = Environment.ProcessPath ?? throw new InvalidOperationException("Cannot locate the uninstaller.");
var temporary = Path.Combine(Path.GetTempPath(), $"WiiCompiled-Uninstall-{Guid.NewGuid():N}.exe");
File.Copy(source, temporary, overwrite: true);
var info = new ProcessStartInfo
{
FileName = temporary,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
info.ArgumentList.Add("--uninstall-worker");
info.ArgumentList.Add("--install-dir");
info.ArgumentList.Add(Path.GetFullPath(installDirectory));
if (quiet) info.ArgumentList.Add("--quiet");
_ = Process.Start(info) ?? throw new InvalidOperationException("Could not start the uninstall worker.");
}
public static int RunWorker(string installDirectory, bool quiet)
{
installDirectory = Path.GetFullPath(installDirectory);
Thread.Sleep(750);
TryCleanup("remove shortcuts", quiet, ShellIntegration.RemoveShortcuts);
// A portable installation never registered an uninstall entry, and the single machine-wide
// key may belong to a normal installation on the same account. Removing it here would
// uninstall that one from Windows' point of view.
bool? isPortable = null;
TryCleanup("determine whether the installation is portable", quiet,
() => isPortable = PortableRoot.TryFind(installDirectory) is not null);
if (isPortable == false)
TryCleanup("remove the Add/Remove Programs entry", quiet,
ShellIntegration.UnregisterUninstaller);
var installation = new Installation(installDirectory);
string? configPath = null;
TryCleanup("locate the runtime configuration", quiet,
() => configPath = RuntimeConfiguration.ResolveConfigPath(installDirectory));
InstallState? state = null;
TryCleanup("read the installation state", quiet,
() => state = installation.ReadInstallState());
if (configPath is not null)
{
TryCleanup("remove the installed game path from the runtime configuration", quiet,
() => RuntimeConfiguration.RemoveDvdRootIfOwned(configPath,
Path.Combine(installDirectory, "GameAssets", "DATA")));
}
// Remove only this install's Retro Rewind setting; leave user-owned paths untouched.
if (configPath is not null && !string.IsNullOrEmpty(state?.RetroRewindRoot))
TryCleanup("remove the Retro Rewind path from the runtime configuration", quiet,
() => RuntimeConfiguration.RemoveRetroRewindRootIfOwned(configPath, state.RetroRewindRoot));
Exception? lastError = null;
for (var attempt = 0; attempt < 20; attempt++)
{
try
{
if (Directory.Exists(installDirectory)) Directory.Delete(installDirectory, recursive: true);
lastError = null;
break;
}
catch (Exception ex)
{
lastError = ex;
Thread.Sleep(250);
}
}
var current = Environment.ProcessPath;
if (current is not null) MoveFileEx(current, null, MoveFileFlags.DelayUntilReboot);
if (lastError is not null)
{
if (!quiet)
Console.Error.WriteLine("Uninstall could not remove every file. " + lastError.Message);
return 1;
}
if (!quiet)
Console.Out.WriteLine("WiiCompiled was removed from this computer.");
return 0;
}
private static void TryCleanup(string description, bool quiet, Action cleanup)
{
try
{
cleanup();
}
catch (Exception ex)
{
if (!quiet)
Console.Error.WriteLine($"Uninstall could not {description}; continuing. {ex.Message}");
}
}
[Flags]
private enum MoveFileFlags : uint { DelayUntilReboot = 0x4 }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool MoveFileEx(string existingFileName, string? newFileName, MoveFileFlags flags);
}