Initialversion

This commit is contained in:
2026-08-09 13:27:53 +02:00
commit eec4f52b5a
25 changed files with 2123 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
using System.Reflection;
namespace Plandent.MstscScriptHook.Configurator;
internal static class PluginInstaller
{
private const string ResourceName = "PlandentMstscScriptHook.Native.PlandentMstscScriptHook.dll";
public const string DllFileName = "PlandentMstscScriptHook.dll";
public static string InstallDirectory => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Plandent",
"MstscScriptHook");
public static string InstalledDllPath => Path.Combine(InstallDirectory, DllFileName);
public static void Install()
{
Directory.CreateDirectory(InstallDirectory);
ExtractPluginBinary(InstalledDllPath);
RegistryConfig.RegisterPlugin(InstalledDllPath);
}
public static UninstallResult Uninstall()
{
RegistryConfig.UnregisterPlugin();
if (!File.Exists(InstalledDllPath))
{
return new UninstallResult(true, "Plugin-Registrierung entfernt.");
}
try
{
File.Delete(InstalledDllPath);
TryDeleteEmptyInstallDirectory();
return new UninstallResult(true, "Plugin-Registrierung und DLL wurden entfernt.");
}
catch (IOException)
{
return new UninstallResult(
false,
"Die Registrierung wurde entfernt. Die DLL wird noch von mstsc.exe verwendet. " +
"Alle Remote-Desktop-Clients schließen und die Datei anschließend löschen bzw. erneut auf „Plugin entfernen“ klicken.");
}
catch (UnauthorizedAccessException ex)
{
return new UninstallResult(false, "Registrierung entfernt, DLL konnte aber nicht gelöscht werden: " + ex.Message);
}
}
public static bool IsInstalled(out string status)
{
string? registered = RegistryConfig.GetRegisteredPluginPath();
if (string.IsNullOrWhiteSpace(registered))
{
status = "Plugin ist nicht registriert.";
return false;
}
string expanded = Environment.ExpandEnvironmentVariables(registered);
if (!File.Exists(expanded))
{
status = $"Plugin ist registriert, DLL fehlt jedoch: {expanded}";
return false;
}
status = $"Plugin ist registriert: {expanded}";
return true;
}
private static void ExtractPluginBinary(string destination)
{
Assembly assembly = Assembly.GetExecutingAssembly();
using Stream? resource = assembly.GetManifestResourceStream(ResourceName);
if (resource is not null)
{
using FileStream output = new(destination, FileMode.Create, FileAccess.Write, FileShare.None);
resource.CopyTo(output);
return;
}
// Praktischer Fallback für Debugging/Entwicklung: DLL direkt neben der EXE akzeptieren.
string adjacent = Path.Combine(AppContext.BaseDirectory, DllFileName);
if (File.Exists(adjacent))
{
File.Copy(adjacent, destination, overwrite: true);
return;
}
throw new FileNotFoundException(
"Die native Plugin-DLL ist weder als Resource eingebettet noch neben der Konfigurations-EXE vorhanden. " +
"Bitte zuerst build-release.ps1 ausführen.",
DllFileName);
}
private static void TryDeleteEmptyInstallDirectory()
{
try
{
if (Directory.Exists(InstallDirectory) && !Directory.EnumerateFileSystemEntries(InstallDirectory).Any())
{
Directory.Delete(InstallDirectory);
}
}
catch
{
// Unkritisch: ein leeres Verzeichnis darf bestehen bleiben.
}
}
}
internal sealed record UninstallResult(bool FullyRemoved, string Message);