Files
PANDA/Installer.cs

372 lines
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32;
[assembly: AssemblyTitle("PANDA Setup")]
[assembly: AssemblyDescription("Installer für PANDA")]
[assembly: AssemblyProduct("PANDA")]
[assembly: AssemblyCompany("PANDA")]
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]
namespace PandaSetup
{
internal static class Program
{
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length == 1 && string.Equals(args[0], "--verify", StringComparison.OrdinalIgnoreCase))
{
try
{
ResourcePayload.Read("PANDA.Application.exe");
ResourcePayload.Read("PANDA.Uninstaller.exe");
Environment.ExitCode = 0;
}
catch
{
Environment.ExitCode = 2;
}
return;
}
if (args.Length == 2 && string.Equals(args[0], "--screenshot", StringComparison.OrdinalIgnoreCase))
{
using (var form = new SetupForm())
{
form.Show();
Application.DoEvents();
using (var bitmap = new Bitmap(form.Width, form.Height))
{
form.DrawToBitmap(bitmap, new Rectangle(Point.Empty, form.Size));
bitmap.Save(args[1], System.Drawing.Imaging.ImageFormat.Png);
}
form.Close();
}
return;
}
Application.Run(new SetupForm());
}
}
internal static class ResourcePayload
{
public static byte[] Read(string name)
{
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
if (stream == null)
throw new InvalidDataException("Installationsdatei fehlt: " + name);
var bytes = new byte[stream.Length];
int offset = 0;
while (offset < bytes.Length)
{
int read = stream.Read(bytes, offset, bytes.Length - offset);
if (read == 0) break;
offset += read;
}
if (offset != bytes.Length || bytes.Length < 1024)
throw new InvalidDataException("Installationsdatei ist unvollständig: " + name);
return bytes;
}
}
}
internal sealed class SetupForm : Form
{
private readonly Color Navy = Color.FromArgb(24, 38, 58);
private readonly Color Blue = Color.FromArgb(41, 112, 255);
private readonly Color Background = Color.FromArgb(244, 247, 251);
private readonly Color Muted = Color.FromArgb(94, 108, 128);
private readonly TextBox installPath = new TextBox();
private readonly CheckBox desktopShortcut = new CheckBox();
private readonly CheckBox startMenuShortcut = new CheckBox();
private readonly CheckBox launchAfterInstall = new CheckBox();
private readonly Button installButton = new Button();
private readonly Label statusLabel = new Label();
public SetupForm()
{
Text = "PANDA Setup";
StartPosition = FormStartPosition.CenterScreen;
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ClientSize = new Size(720, 520);
BackColor = Background;
Font = new Font("Segoe UI", 9F);
Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath) ?? SystemIcons.Application;
BuildLayout();
}
private void BuildLayout()
{
var root = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 1,
RowCount = 4,
Padding = new Padding(30, 24, 30, 22),
BackColor = Background
};
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 100));
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 120));
root.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 74));
Controls.Add(root);
var heading = new Panel { Dock = DockStyle.Fill };
heading.Controls.Add(new Label
{
Text = "PANDA installieren",
Font = new Font("Segoe UI Semibold", 22F),
ForeColor = Navy,
AutoSize = true,
Location = new Point(0, 0)
});
heading.Controls.Add(new Label
{
Text = "Pseudonymisierung alphanumerischer Nutzdaten durch Alphabetverschiebung",
ForeColor = Muted,
AutoSize = true,
Location = new Point(2, 48)
});
heading.Controls.Add(new Label
{
Text = "Version 1.4.0 • Installation für den aktuellen Windows-Benutzer",
ForeColor = Blue,
AutoSize = true,
Location = new Point(2, 73)
});
root.Controls.Add(heading, 0, 0);
var location = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 3,
BackColor = Color.White,
Padding = new Padding(18, 14, 18, 12),
Margin = new Padding(0, 0, 0, 14)
};
location.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
location.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 110));
location.RowStyles.Add(new RowStyle(SizeType.Absolute, 26));
location.RowStyles.Add(new RowStyle(SizeType.Absolute, 34));
location.RowStyles.Add(new RowStyle(SizeType.Absolute, 26));
var locationTitle = new Label
{
Text = "INSTALLATIONSORDNER",
Font = new Font("Segoe UI Semibold", 9F),
ForeColor = Navy,
AutoSize = true,
Anchor = AnchorStyles.Left
};
location.Controls.Add(locationTitle, 0, 0);
location.SetColumnSpan(locationTitle, 2);
installPath.Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "PANDA");
installPath.Dock = DockStyle.Fill;
installPath.ForeColor = Navy;
location.Controls.Add(installPath, 0, 1);
var browse = new Button
{
Text = "Durchsuchen …",
Anchor = AnchorStyles.None,
Size = new Size(102, 28),
FlatStyle = FlatStyle.Flat,
BackColor = Color.White,
ForeColor = Navy,
Margin = new Padding(8, 0, 0, 0)
};
browse.FlatAppearance.BorderColor = Color.FromArgb(206, 216, 230);
browse.Click += delegate { BrowseForFolder(); };
location.Controls.Add(browse, 1, 1);
var note = new Label
{
Text = "Keine Administratorrechte erforderlich.",
ForeColor = Muted,
AutoSize = true,
Anchor = AnchorStyles.Left
};
location.Controls.Add(note, 0, 2);
location.SetColumnSpan(note, 2);
root.Controls.Add(location, 0, 1);
var options = new Panel { Dock = DockStyle.Fill, BackColor = Color.White, Padding = new Padding(18, 14, 18, 12) };
options.Controls.Add(new Label
{
Text = "OPTIONEN",
Font = new Font("Segoe UI Semibold", 9F),
ForeColor = Navy,
AutoSize = true,
Location = new Point(18, 16)
});
desktopShortcut.Text = "Desktop-Verknüpfung erstellen";
desktopShortcut.Checked = true;
desktopShortcut.AutoSize = true;
desktopShortcut.ForeColor = Navy;
desktopShortcut.Location = new Point(20, 52);
startMenuShortcut.Text = "Eintrag im Startmenü erstellen";
startMenuShortcut.Checked = true;
startMenuShortcut.AutoSize = true;
startMenuShortcut.ForeColor = Navy;
startMenuShortcut.Location = new Point(20, 82);
launchAfterInstall.Text = "PANDA nach der Installation starten";
launchAfterInstall.Checked = true;
launchAfterInstall.AutoSize = true;
launchAfterInstall.ForeColor = Navy;
launchAfterInstall.Location = new Point(20, 112);
options.Controls.Add(desktopShortcut);
options.Controls.Add(startMenuShortcut);
options.Controls.Add(launchAfterInstall);
root.Controls.Add(options, 0, 2);
var footer = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 1, Padding = new Padding(0, 18, 0, 0) };
footer.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
footer.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 190));
footer.RowStyles.Add(new RowStyle(SizeType.Absolute, 38));
statusLabel.Text = "Bereit zur Installation.";
statusLabel.ForeColor = Muted;
statusLabel.Dock = DockStyle.Fill;
statusLabel.TextAlign = ContentAlignment.MiddleLeft;
footer.Controls.Add(statusLabel, 0, 0);
installButton.Text = "Jetzt installieren";
installButton.Dock = DockStyle.Fill;
installButton.Margin = new Padding(0);
installButton.FlatStyle = FlatStyle.Flat;
installButton.FlatAppearance.BorderSize = 0;
installButton.BackColor = Blue;
installButton.ForeColor = Color.White;
installButton.Cursor = Cursors.Hand;
installButton.Click += delegate { Install(); };
footer.Controls.Add(installButton, 1, 0);
root.Controls.Add(footer, 0, 3);
AcceptButton = installButton;
}
private void BrowseForFolder()
{
using (var dialog = new FolderBrowserDialog())
{
dialog.Description = "Installationsordner für PANDA auswählen";
dialog.SelectedPath = installPath.Text;
if (dialog.ShowDialog(this) == DialogResult.OK)
installPath.Text = Path.Combine(dialog.SelectedPath, "PANDA");
}
}
private void Install()
{
string target;
try
{
target = Path.GetFullPath(installPath.Text.Trim());
if (string.Equals(target, Path.GetPathRoot(target), StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException("Bitte wähle keinen Laufwerks-Stammordner aus.");
installButton.Enabled = false;
statusLabel.Text = "PANDA wird installiert …";
Cursor = Cursors.WaitCursor;
Application.DoEvents();
Directory.CreateDirectory(target);
string applicationPath = Path.Combine(target, "PANDA.exe");
string uninstallerPath = Path.Combine(target, "PANDA-Uninstall.exe");
File.WriteAllBytes(applicationPath, ResourcePayload.Read("PANDA.Application.exe"));
File.WriteAllBytes(uninstallerPath, ResourcePayload.Read("PANDA.Uninstaller.exe"));
string desktopLink = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "PANDA.lnk");
if (desktopShortcut.Checked)
Shortcut.Create(desktopLink, applicationPath, target, "PANDA starten");
else if (File.Exists(desktopLink))
File.Delete(desktopLink);
string startMenuFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), "PANDA");
if (startMenuShortcut.Checked)
{
Directory.CreateDirectory(startMenuFolder);
Shortcut.Create(Path.Combine(startMenuFolder, "PANDA.lnk"), applicationPath, target, "PANDA starten");
Shortcut.Create(Path.Combine(startMenuFolder, "PANDA deinstallieren.lnk"), uninstallerPath, target, "PANDA deinstallieren");
}
else if (Directory.Exists(startMenuFolder))
{
string oldApplicationLink = Path.Combine(startMenuFolder, "PANDA.lnk");
string oldUninstallLink = Path.Combine(startMenuFolder, "PANDA deinstallieren.lnk");
if (File.Exists(oldApplicationLink)) File.Delete(oldApplicationLink);
if (File.Exists(oldUninstallLink)) File.Delete(oldUninstallLink);
if (Directory.GetFileSystemEntries(startMenuFolder).Length == 0) Directory.Delete(startMenuFolder, false);
}
RegisterUninstaller(target, applicationPath, uninstallerPath);
statusLabel.Text = "Installation erfolgreich abgeschlossen.";
Cursor = Cursors.Default;
MessageBox.Show(this, "PANDA wurde erfolgreich installiert.\r\n\r\nDie Deinstallation ist über Windows Installierte Apps oder das Startmenü möglich.", "PANDA installiert", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (launchAfterInstall.Checked)
Process.Start(applicationPath);
Close();
}
catch (Exception exception)
{
Cursor = Cursors.Default;
installButton.Enabled = true;
statusLabel.Text = "Installation fehlgeschlagen.";
MessageBox.Show(this, "PANDA konnte nicht installiert werden.\r\n\r\n" + exception.Message + "\r\n\r\nFalls PANDA bereits läuft, schließe das Programm und versuche es erneut.", "Installationsfehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static void RegisterUninstaller(string target, string applicationPath, string uninstallerPath)
{
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\PANDA"))
{
key.SetValue("DisplayName", "PANDA");
key.SetValue("DisplayVersion", "1.4.0");
key.SetValue("DisplayIcon", applicationPath);
key.SetValue("Publisher", "PANDA");
key.SetValue("InstallLocation", target);
key.SetValue("UninstallString", "\"" + uninstallerPath + "\"");
key.SetValue("QuietUninstallString", "\"" + uninstallerPath + "\" --silent");
key.SetValue("NoModify", 1, RegistryValueKind.DWord);
key.SetValue("NoRepair", 1, RegistryValueKind.DWord);
key.SetValue("EstimatedSize", 100, RegistryValueKind.DWord);
}
}
}
internal static class Shortcut
{
public static void Create(string shortcutPath, string targetPath, string workingDirectory, string description)
{
Type shellType = Type.GetTypeFromProgID("WScript.Shell");
if (shellType == null)
throw new InvalidOperationException("Windows-Verknüpfungen werden auf diesem System nicht unterstützt.");
object shell = Activator.CreateInstance(shellType);
object shortcut = null;
try
{
shortcut = shellType.InvokeMember("CreateShortcut", BindingFlags.InvokeMethod, null, shell, new object[] { shortcutPath });
Type shortcutType = shortcut.GetType();
shortcutType.InvokeMember("TargetPath", BindingFlags.SetProperty, null, shortcut, new object[] { targetPath });
shortcutType.InvokeMember("WorkingDirectory", BindingFlags.SetProperty, null, shortcut, new object[] { workingDirectory });
shortcutType.InvokeMember("Description", BindingFlags.SetProperty, null, shortcut, new object[] { description });
shortcutType.InvokeMember("IconLocation", BindingFlags.SetProperty, null, shortcut, new object[] { targetPath + ",0" });
shortcutType.InvokeMember("Save", BindingFlags.InvokeMethod, null, shortcut, null);
}
finally
{
if (shortcut != null && Marshal.IsComObject(shortcut)) Marshal.FinalReleaseComObject(shortcut);
if (shell != null && Marshal.IsComObject(shell)) Marshal.FinalReleaseComObject(shell);
}
}
}
}