diff --git a/src/Squirrel/IUpdateManager.cs b/src/Squirrel/IUpdateManager.cs
index 6b38ed49..682f95df 100644
--- a/src/Squirrel/IUpdateManager.cs
+++ b/src/Squirrel/IUpdateManager.cs
@@ -4,6 +4,7 @@ using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Win32;
namespace Squirrel
{
@@ -56,6 +57,15 @@ namespace Squirrel
///
/// Completion
Task FullUninstall();
+
+ ///
+ /// Creates an entry in Programs and Features based on the currently
+ /// applied package
+ ///
+ /// The command to run to uninstall, usually update.exe --uninstall
+ /// The switch for silent uninstall, usually --silent
+ /// The registry key that was created
+ Task CreateUninstallerRegistryEntry(string uninstallCmd, string quietSwitch);
}
public static class EasyModeMixin
diff --git a/src/Squirrel/UpdateManager.cs b/src/Squirrel/UpdateManager.cs
index ceb85b18..e2d37d27 100644
--- a/src/Squirrel/UpdateManager.cs
+++ b/src/Squirrel/UpdateManager.cs
@@ -1,13 +1,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
+using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
+using System.Security.AccessControl;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Win32;
using NuGet;
using Splat;
@@ -84,6 +87,64 @@ namespace Squirrel
await applyReleases.FullUninstall();
}
+ const string uninstallRegSubKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";
+ public async Task CreateUninstallerRegistryEntry(string uninstallCmd, string quietSwitch)
+ {
+ var releases = ReleaseEntry.ParseReleaseFile(Path.Combine(rootAppDirectory, "packages", "RELEASES"));
+ var latest = releases.OrderByDescending(x => x.Version).First();
+
+ // Download the icon and PNG => ICO it. If this doesn't work, who cares
+ var pkgPath = Path.Combine(rootAppDirectory, "packages", latest.Filename);
+ var zp = new ZipPackage(pkgPath);
+
+ var targetPng = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".png");
+ var targetIco = Path.Combine(rootAppDirectory, "app.ico");
+ try {
+ var wc = new WebClient();
+
+ await wc.DownloadFileTaskAsync(zp.IconUrl, targetPng);
+ using (var fs = new FileStream(targetIco, FileMode.Create))
+ using (var bmp = (Bitmap)Image.FromFile(targetPng))
+ using (var ico = Icon.FromHandle(bmp.GetHicon())) {
+ ico.Save(fs);
+ }
+ } catch(Exception ex) {
+ this.Log().InfoException("Couldn't write uninstall icon, don't care", ex);
+ } finally {
+ File.Delete(targetPng);
+ }
+
+ var stringsToWrite = new[] {
+ new { Key = "DisplayIcon", Value = "targetIco" },
+ new { Key = "DisplayName", Value = zp.Description ?? zp.Summary },
+ new { Key = "DisplayVersion", Value = zp.Version.ToString() },
+ new { Key = "InstallDate", Value = DateTime.Now.ToString("yyyymmdd") },
+ new { Key = "InstallLocation", Value = rootAppDirectory },
+ new { Key = "Publisher", Value = zp.Authors.First() },
+ new { Key = "QuietUninstallString", Value = String.Format("{0} {1}", uninstallCmd, quietSwitch) },
+ new { Key = "UninstallString", Value = uninstallCmd },
+ };
+
+ var dwordsToWrite = new[] {
+ new { Key = "EstimatedSize", Value = (int)((new FileInfo(pkgPath)).Length / 1024) },
+ new { Key = "NoModify", Value = 1 },
+ new { Key = "NoRepair", Value = 1 },
+ new { Key = "Language", Value = 0x0409 },
+ };
+
+ var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
+ .CreateSubKey(uninstallRegSubKey + "\\" + applicationName, RegistryKeyPermissionCheck.ReadWriteSubTree);
+
+ foreach (var kvp in stringsToWrite) {
+ key.SetValue(kvp.Key, kvp.Value, RegistryValueKind.String);
+ }
+ foreach (var kvp in dwordsToWrite) {
+ key.SetValue(kvp.Key, kvp.Value, RegistryValueKind.DWord);
+ }
+
+ return key;
+ }
+
public void Dispose()
{
var disp = Interlocked.Exchange(ref updateLock, null);