installer: wizard C# Windows d'installation guidee (WSL2, Podman, agent, desinstallation)

This commit is contained in:
EduBox Dev
2026-06-28 20:49:57 +00:00
parent d2c3edea2f
commit 0f07a2d2a3
7 changed files with 1196 additions and 0 deletions
+662
View File
@@ -0,0 +1,662 @@
using System.Diagnostics;
using System.Reflection;
using Microsoft.Win32;
namespace StudioE5.SetupWizard;
public partial class MainForm : Form
{
private readonly InstallerState _state;
private readonly Panel _contentPanel;
private readonly Button _btnBack;
private readonly Button _btnNext;
private readonly Button _btnCancel;
private readonly Label _titleLabel;
private readonly Label _subtitleLabel;
private WizardStep _currentStep = WizardStep.Welcome;
private PrerequisiteResult? _lastCheck;
public MainForm(bool startInUninstallMode = false)
{
_state = InstallerState.Load();
Text = startInUninstallMode ? "Désinstallation studioE5" : "Installateur studioE5 Agent";
Size = new Size(700, 520);
StartPosition = FormStartPosition.CenterScreen;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
_titleLabel = new Label
{
Left = 24,
Top = 18,
Width = 640,
Height = 32,
Font = new Font("Segoe UI", 14, FontStyle.Bold),
Text = "Installateur studioE5 Agent"
};
_subtitleLabel = new Label
{
Left = 24,
Top = 50,
Width = 640,
Height = 24,
Font = new Font("Segoe UI", 9),
ForeColor = Color.Gray
};
_contentPanel = new Panel
{
Left = 24,
Top = 84,
Width = 640,
Height = 320,
BorderStyle = BorderStyle.None
};
var separator = new Panel
{
Left = 0,
Top = 416,
Width = 700,
Height = 1,
BackColor = Color.LightGray,
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom
};
_btnBack = new Button
{
Left = 360,
Top = 440,
Width = 100,
Height = 30,
Text = "< Précédent",
Visible = false
};
_btnBack.Click += (s, e) => GoBack();
_btnNext = new Button
{
Left = 470,
Top = 440,
Width = 100,
Height = 30,
Text = "Suivant >"
};
_btnNext.Click += (s, e) => GoNext();
_btnCancel = new Button
{
Left = 584,
Top = 440,
Width = 80,
Height = 30,
Text = "Annuler"
};
_btnCancel.Click += (s, e) => Application.Exit();
Controls.Add(_titleLabel);
Controls.Add(_subtitleLabel);
Controls.Add(_contentPanel);
Controls.Add(separator);
Controls.Add(_btnBack);
Controls.Add(_btnNext);
Controls.Add(_btnCancel);
if (startInUninstallMode)
{
GoToStep(WizardStep.Uninstall);
return;
}
ResumeAfterReboot();
}
private void ResumeAfterReboot()
{
// If we are resuming after a reboot, skip directly to the relevant step.
if (_state.VirtualEnvironmentInstalled && !_state.PodmanInstalled)
{
GoToStep(WizardStep.InstallPodman);
return;
}
if (_state.PodmanInstalled && !_state.PodmanConfigured)
{
GoToStep(WizardStep.ConfigurePodman);
return;
}
if (_state.PodmanConfigured && !_state.AgentInstalled)
{
GoToStep(WizardStep.InstallAgent);
return;
}
GoToStep(WizardStep.Welcome);
}
private void GoBack()
{
switch (_currentStep)
{
case WizardStep.Prerequisites:
GoToStep(WizardStep.Welcome);
break;
case WizardStep.InstallVirtualEnvironment:
case WizardStep.RestartRequired:
GoToStep(WizardStep.Prerequisites);
break;
case WizardStep.InstallPodman:
GoToStep(WizardStep.Prerequisites);
break;
case WizardStep.ConfigurePodman:
GoToStep(WizardStep.InstallPodman);
break;
case WizardStep.InstallAgent:
GoToStep(WizardStep.ConfigurePodman);
break;
}
}
private void GoNext()
{
switch (_currentStep)
{
case WizardStep.Welcome:
GoToStep(WizardStep.Prerequisites);
break;
case WizardStep.Prerequisites:
if (_lastCheck?.VirtualEnvironmentInstalled == true)
GoToStep(WizardStep.InstallPodman);
else
GoToStep(WizardStep.InstallVirtualEnvironment);
break;
case WizardStep.InstallVirtualEnvironment:
InstallVirtualEnvironment();
break;
case WizardStep.RestartRequired:
Application.Exit();
break;
case WizardStep.InstallPodman:
InstallPodman();
break;
case WizardStep.ConfigurePodman:
ConfigurePodman();
break;
case WizardStep.InstallAgent:
InstallAgent();
break;
case WizardStep.Finished:
Application.Exit();
break;
case WizardStep.Uninstall:
RunUninstall();
break;
}
}
private void GoToStep(WizardStep step)
{
_currentStep = step;
_state.Step = step;
_state.Save();
_contentPanel.Controls.Clear();
switch (step)
{
case WizardStep.Welcome:
ShowWelcome();
break;
case WizardStep.Prerequisites:
ShowPrerequisites();
break;
case WizardStep.InstallVirtualEnvironment:
ShowInstallVirtualEnvironment();
break;
case WizardStep.RestartRequired:
ShowRestartRequired();
break;
case WizardStep.InstallPodman:
ShowInstallPodman();
break;
case WizardStep.ConfigurePodman:
ShowConfigurePodman();
break;
case WizardStep.InstallAgent:
ShowInstallAgent();
break;
case WizardStep.Finished:
ShowFinished();
break;
case WizardStep.Uninstall:
ShowUninstall();
break;
}
}
private void ShowWelcome()
{
_titleLabel.Text = "Bienvenue dans l'installateur studioE5";
_subtitleLabel.Text = "Cet assistant va vous guider pour installer studioE5 Agent sur votre poste.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 200,
Text = "L'installation se déroule en plusieurs étapes :\n\n" +
"1. Vérification des prérequis\n" +
"2. Installation de l'environnement virtuel (si nécessaire)\n" +
"3. Installation de Podman\n" +
"4. Configuration de Podman\n" +
"5. Installation de studioE5 Agent\n\n" +
"Cliquez sur 'Suivant' pour commencer.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = false;
_btnNext.Text = "Suivant >";
_btnNext.Enabled = true;
_btnCancel.Text = "Annuler";
}
private void ShowPrerequisites()
{
_titleLabel.Text = "Vérification des prérequis";
_subtitleLabel.Text = "Assurez-vous que votre poste est prêt avant de continuer.";
_lastCheck = PrerequisiteChecker.Check();
var result = _lastCheck;
var text = $"Système d'exploitation : {(result.WindowsCompatible ? " Compatible" : " Non compatible (Windows 10 2004+ requis)")}\n" +
$"Mémoire vive (RAM) : {(result.RamMB >= 8192 ? "" : result.RamMB >= 4096 ? "" : "")} {result.RamMB} Mo (8 Go recommandés)\n" +
$"Espace disque disponible : {(result.FreeDiskMB >= 10240 ? "" : result.FreeDiskMB >= 5120 ? "" : "")} {result.FreeDiskMB} Mo (10 Go recommandés)\n" +
$"Environnement virtuel : {(result.VirtualEnvironmentInstalled ? " Installé" : " Non installé")}\n" +
$"Podman : {(result.PodmanInstalled ? " Installé" : " Non installé")}\n" +
$"Machine Podman : {(result.PodmanMachineReady ? " Prête" : " Non prête")}\n\n";
if (result.AllReady)
{
text += "Tous les prérequis sont satisfaits. Vous pouvez continuer.";
}
else
{
text += "Ordre d'installation recommandé :\n" +
"1. Installer l'environnement virtuel\n" +
"2. Installer Podman\n" +
"3. Configurer Podman\n" +
"4. Installer studioE5 Agent";
}
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 240,
Text = text,
Font = new Font("Consolas", 10),
ForeColor = Color.Black
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = true;
_btnNext.Text = result.AllReady ? "Suivant >" : (result.VirtualEnvironmentInstalled ? "Installer Podman" : "Installer l'environnement virtuel");
_btnNext.Enabled = true;
}
private void ShowInstallVirtualEnvironment()
{
_titleLabel.Text = "Installation de l'environnement virtuel";
_subtitleLabel.Text = "L'environnement virtuel permet de faire tourner Podman sur Windows.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 120,
Text = "L'environnement virtuel (WSL2) n'est pas installé.\n\n" +
"Cliquez sur 'Installer' pour lancer l'installation.\n" +
"Un redémarrage de l'ordinateur sera nécessaire. L'installateur se relancera automatiquement.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = true;
_btnNext.Text = "Installer";
_btnNext.Enabled = true;
}
private void InstallVirtualEnvironment()
{
_btnNext.Enabled = false;
_btnBack.Enabled = false;
try
{
RunCommand("wsl.exe", "--install --no-distribution", "Installation de l'environnement virtuel en cours...");
_state.VirtualEnvironmentInstalled = true;
_state.Save();
RegisterRunOnce();
GoToStep(WizardStep.RestartRequired);
}
catch (Exception ex)
{
MessageBox.Show($"Erreur lors de l'installation de l'environnement virtuel : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_btnNext.Enabled = true;
_btnBack.Enabled = true;
}
}
private void ShowRestartRequired()
{
_titleLabel.Text = "Redémarrage nécessaire";
_subtitleLabel.Text = "L'environnement virtuel a été installé.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 120,
Text = "Veuillez redémarrer votre ordinateur pour finaliser l'installation de l'environnement virtuel.\n\n" +
"L'installateur se relancera automatiquement après le redémarrage pour continuer l'installation.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = false;
_btnNext.Text = "Redémarrer maintenant";
_btnNext.Enabled = true;
_btnCancel.Text = "Redémarrer plus tard";
}
private void ShowInstallPodman()
{
_titleLabel.Text = "Installation de Podman";
_subtitleLabel.Text = "Podman est le moteur de conteneurs utilisé par studioE5.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 120,
Text = "Podman va être installé sur votre poste.\n\n" +
"Cliquez sur 'Installer' pour lancer l'installation silencieuse.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = true;
_btnNext.Text = "Installer Podman";
_btnNext.Enabled = true;
}
private void InstallPodman()
{
_btnNext.Enabled = false;
_btnBack.Enabled = false;
try
{
var msiPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Resources", "podman-setup.msi");
if (!File.Exists(msiPath))
throw new FileNotFoundException("Le fichier podman-setup.msi est introuvable. Vérifiez qu'il est bien inclus dans le package.");
RunCommand("msiexec.exe", $"/i \"{msiPath}\" /qn /norestart", "Installation de Podman en cours...");
_state.PodmanInstalled = true;
_state.Save();
GoToStep(WizardStep.ConfigurePodman);
}
catch (Exception ex)
{
MessageBox.Show($"Erreur lors de l'installation de Podman : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_btnNext.Enabled = true;
_btnBack.Enabled = true;
}
}
private void ShowConfigurePodman()
{
_titleLabel.Text = "Configuration de Podman";
_subtitleLabel.Text = "Initialisation de la machine Podman.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 120,
Text = "La machine virtuelle Podman va être créée et démarrée.\n\n" +
"Cette opération peut prendre plusieurs minutes la première fois.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = true;
_btnNext.Text = "Configurer Podman";
_btnNext.Enabled = true;
}
private void ConfigurePodman()
{
_btnNext.Enabled = false;
_btnBack.Enabled = false;
try
{
RunCommand("podman.exe", "machine init", "Initialisation de la machine Podman...");
RunCommand("podman.exe", "machine start", "Démarrage de la machine Podman...");
_state.PodmanConfigured = true;
_state.Save();
GoToStep(WizardStep.InstallAgent);
}
catch (Exception ex)
{
MessageBox.Show($"Erreur lors de la configuration de Podman : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_btnNext.Enabled = true;
_btnBack.Enabled = true;
}
}
private void ShowInstallAgent()
{
_titleLabel.Text = "Installation de studioE5 Agent";
_subtitleLabel.Text = "L'environnement est prêt. Il ne reste plus qu'à installer l'agent.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 120,
Text = "Cliquez sur 'Installer studioE5 Agent' pour lancer le package d'installation.\n\n" +
"Une fois l'installation terminée, fermez cet assistant.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = true;
_btnNext.Text = "Installer studioE5 Agent";
_btnNext.Enabled = true;
}
private void InstallAgent()
{
try
{
var setupPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Resources", "studioE5-agent-setup.exe");
if (!File.Exists(setupPath))
throw new FileNotFoundException("Le fichier studioE5-agent-setup.exe est introuvable. Vérifiez qu'il est bien inclus dans le package.");
var psi = new ProcessStartInfo(setupPath)
{
UseShellExecute = true,
Verb = "runas"
};
Process.Start(psi);
_state.AgentInstalled = true;
_state.Save();
GoToStep(WizardStep.Finished);
}
catch (Exception ex)
{
MessageBox.Show($"Erreur lors du lancement de l'installation de l'agent : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ShowFinished()
{
_titleLabel.Text = "Installation terminée";
_subtitleLabel.Text = "studioE5 Agent est prêt à être utilisé.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 120,
Text = "L'installation est terminée.\n\n" +
"Vous pouvez lancer studioE5 Agent depuis le menu Démarrer ou le bureau.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = false;
_btnNext.Text = "Terminer";
_btnCancel.Text = "Fermer";
}
private void ShowUninstall()
{
_titleLabel.Text = "Désinstallation de studioE5";
_subtitleLabel.Text = "Suppression complète de studioE5 Agent et des composants associés.";
var label = new Label
{
Left = 0,
Top = 20,
Width = _contentPanel.Width,
Height = 200,
Text = "Cette opération va :\n\n" +
"- Arrêter studioE5 Agent\n" +
"- Désinstaller studioE5 Agent\n" +
"- Supprimer les données élèves\n" +
"- Désinstaller Podman\n" +
"- Proposer de désactiver l'environnement virtuel\n\n" +
"Cliquez sur 'Désinstaller' pour commencer.",
Font = new Font("Segoe UI", 10)
};
_contentPanel.Controls.Add(label);
_btnBack.Visible = false;
_btnNext.Text = "Désinstaller";
_btnCancel.Text = "Annuler";
}
private void RunUninstall()
{
_btnNext.Enabled = false;
try
{
// 1. Kill agent
RunCommand("taskkill.exe", "/f /im studioE5-agent.exe", "Arrêt de studioE5 Agent...");
// 2. Uninstall agent via Inno Setup uninstaller
var agentUninstaller = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "studioE5-agent", "unins000.exe");
if (File.Exists(agentUninstaller))
RunCommand(agentUninstaller, "/SILENT", "Désinstallation de studioE5 Agent...");
// 3. Delete student data
var dataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "studioE5-agent");
if (Directory.Exists(dataDir))
{
Directory.Delete(dataDir, true);
}
// 4. Uninstall Podman
var podmanMsiPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Resources", "podman-setup.msi");
if (File.Exists(podmanMsiPath))
{
RunCommand("msiexec.exe", $"/x \"{podmanMsiPath}\" /qn /norestart", "Désinstallation de Podman...");
}
else
{
MessageBox.Show("Le MSI de Podman n'a pas été trouvé dans le package. Veuillez désinstaller Podman manuellement via Ajouter/Supprimer des programmes.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
// 5. Optionally disable WSL2
var result = MessageBox.Show("Voulez-vous désactiver l'environnement virtuel (WSL2) ?", "Environnement virtuel", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
RunCommand("wsl.exe", "--uninstall", "Désactivation de l'environnement virtuel...");
}
InstallerState.Delete();
MessageBox.Show("Désinstallation terminée.", "Terminé", MessageBoxButtons.OK, MessageBoxIcon.Information);
Application.Exit();
}
catch (Exception ex)
{
MessageBox.Show($"Erreur lors de la désinstallation : {ex.Message}", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_btnNext.Enabled = true;
}
}
private void RunCommand(string fileName, string arguments, string description)
{
var psi = new ProcessStartInfo(fileName, arguments)
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using var process = Process.Start(psi);
if (process == null)
throw new InvalidOperationException($"Impossible de démarrer {fileName}");
process.WaitForExit();
if (process.ExitCode != 0)
{
var error = process.StandardError.ReadToEnd();
throw new InvalidOperationException($"{description} a échoué (code {process.ExitCode}) : {error}");
}
}
private void RegisterRunOnce()
{
var executablePath = Application.ExecutablePath;
var key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", true);
key?.SetValue("StudioE5SetupWizard", $"\"{executablePath}\"");
}
}