diff --git a/ToDo.txt b/ToDo.txt index e26fd2b..3e8b009 100644 --- a/ToDo.txt +++ b/ToDo.txt @@ -3,7 +3,6 @@ More apps: Laptop Sim (when done) Split up main File (MainForm.cs) to (more or less) independent modules Allow Repos to contain "Links" to seperate Repos/App files (Repo with only one app & without a repo tag) Automatically push Meta.xml changes after building -Allow Zips for updates -Allow 3rd party update source in main.xml +Show number of available updates NOTE: All command prompts will be removed soon (tm) Update your scripts to reflect this change (there may be some things provided for dialogs) \ No newline at end of file diff --git a/UpTool2/MainForm.Designer.cs b/UpTool2/MainForm.Designer.cs index 799f879..a8fa498 100644 --- a/UpTool2/MainForm.Designer.cs +++ b/UpTool2/MainForm.Designer.cs @@ -46,6 +46,7 @@ this.controls_reload = new System.Windows.Forms.Button(); this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.searchPackageDialog = new System.Windows.Forms.OpenFileDialog(); + this.controls_local = new System.Windows.Forms.Button(); this.infoPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); this.splitContainer.Panel1.SuspendLayout(); @@ -169,6 +170,7 @@ this.optionsPanel.Controls.Add(this.searchBox); this.optionsPanel.Controls.Add(this.controls_settings); this.optionsPanel.Controls.Add(this.controls_reload); + this.optionsPanel.Controls.Add(this.controls_local); this.optionsPanel.Dock = System.Windows.Forms.DockStyle.Top; this.optionsPanel.Location = new System.Drawing.Point(0, 0); this.optionsPanel.Name = "optionsPanel"; @@ -204,7 +206,7 @@ | System.Windows.Forms.AnchorStyles.Right))); this.searchBox.Location = new System.Drawing.Point(3, 33); this.searchBox.Name = "searchBox"; - this.searchBox.Size = new System.Drawing.Size(262, 20); + this.searchBox.Size = new System.Drawing.Size(233, 20); this.searchBox.TabIndex = 2; this.searchBox.TextChanged += new System.EventHandler(this.updateSidebarV); // @@ -239,6 +241,17 @@ // this.searchPackageDialog.Filter = "Packages (*.zip)|*.zip"; // + // controls_local + // + this.controls_local.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.controls_local.Location = new System.Drawing.Point(242, 31); + this.controls_local.Name = "controls_local"; + this.controls_local.Size = new System.Drawing.Size(23, 23); + this.controls_local.TabIndex = 6; + this.controls_local.Text = "⇓"; + this.controls_local.UseVisualStyleBackColor = true; + this.controls_local.Click += new System.EventHandler(this.controls_local_Click); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -281,6 +294,7 @@ private System.Windows.Forms.Button action_run; private System.Windows.Forms.Button controls_upload; private System.Windows.Forms.OpenFileDialog searchPackageDialog; + private System.Windows.Forms.Button controls_local; } } diff --git a/UpTool2/MainForm.cs b/UpTool2/MainForm.cs index 1b075b2..8e165c1 100644 --- a/UpTool2/MainForm.cs +++ b/UpTool2/MainForm.cs @@ -14,6 +14,7 @@ using Microsoft.VisualBasic; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Threading; +using System.Runtime.InteropServices; namespace UpTool2 { @@ -162,6 +163,9 @@ namespace UpTool2 toolTip.SetToolTip(controls_settings, "Settings"); toolTip.SetToolTip(controls_reload, "Refresh repositories"); toolTip.SetToolTip(controls_upload, "Install package from disk"); + toolTip.SetToolTip(controls_local, "Install UpTool2 locally"); + controls_local.Visible = Application.ExecutablePath != dir + @"\UpTool2.exe"; + searchBox.Size = (Application.ExecutablePath != dir + @"\UpTool2.exe") ? new Size(233, 20) : new Size(262, 20); toolTip.SetToolTip(filterBox, "Filter"); toolTip.SetToolTip(action_install, "Install"); toolTip.SetToolTip(action_remove, "Remove"); @@ -283,10 +287,8 @@ namespace UpTool2 tmp_apps_list.Last().Add(new XElement("MainFile", app.Element("MainFile").Value)); if (app.Element("Icon") != null) { -#if !DEBUG try { -#endif //Scale Image and save as Base64 Image src = Image.FromStream(client.OpenRead(app.Element("Icon").Value)); Bitmap dest = new Bitmap(70, 70); @@ -309,10 +311,8 @@ namespace UpTool2 dest.Save(ms, ImageFormat.Png); tmp_apps_list.Last().Add(new XElement("Icon", Convert.ToBase64String(ms.ToArray()))); } -#if !DEBUG } catch { } -#endif } if (tmp_apps_list.Where(a => a.Element("ID").Value == app.Element("ID").Value).Count() > 1) tmp_apps_list.Where(a => a.Element("ID").Value == app.Element("ID").Value).Reverse().Skip(1).ToList().ForEach(a => tmp_apps_list.Remove(a)); @@ -335,8 +335,8 @@ namespace UpTool2 tmp_apps_list.ForEach(app => repos.Add(app)); meta.Save(xml); } -#endregion -#region Run/Update/Reload/Settings (Small links to other stuff) + #endregion + #region Run/Update/Reload/Settings (Small links to other stuff) private void Action_run_Click(object sender, EventArgs e) { Console.WriteLine(new string('-', 10)); @@ -345,7 +345,8 @@ namespace UpTool2 Console.WriteLine(((App)action_run.Tag).mainFile); Console.WriteLine(getDataPath((App)action_run.Tag)); _ = Process.Start( - new ProcessStartInfo { + new ProcessStartInfo + { FileName = getDataPath((App)action_run.Tag) + "\\" + ((App)action_run.Tag).mainFile, WorkingDirectory = getDataPath((App)action_run.Tag) @@ -374,8 +375,8 @@ namespace UpTool2 } private void Controls_settings_Click(object sender, EventArgs e) => new SettingsForms().ShowDialog(); -#endregion -#region GUI (stuff only present for GUI) + #endregion + #region GUI (stuff only present for GUI) void clearSelection() { action_install.Enabled = false; @@ -401,14 +402,14 @@ namespace UpTool2 else { #endif - Enum.TryParse(filterBox.SelectedValue.ToString(), out Status status); - for (int i = 0; i < sidebarPanel.Controls.Count; i++) - { - Panel sidebarIcon = (Panel)sidebarPanel.Controls[i]; - App app = (App)sidebarIcon.Tag; - sidebarIcon.Visible = app.name.Contains(searchBox.Text) && ((int)app.status & (int)(Program.online ? status : Status.Installed)) != 0; - } - clearSelection(); + Enum.TryParse(filterBox.SelectedValue.ToString(), out Status status); + for (int i = 0; i < sidebarPanel.Controls.Count; i++) + { + Panel sidebarIcon = (Panel)sidebarPanel.Controls[i]; + App app = (App)sidebarIcon.Tag; + sidebarIcon.Visible = app.name.Contains(searchBox.Text) && ((int)app.status & (int)(Program.online ? status : Status.Installed)) != 0; + } + clearSelection(); #if DEBUG } #endif @@ -435,8 +436,64 @@ namespace UpTool2 Program.splash.Hide(); BringToFront(); } -#endregion -#region Definitions + + private void controls_local_Click(object sender, EventArgs e) + { + File.Copy(dir + @"\update.exe", dir + @"\UpTool2.exe", true); + Shortcut.Create(Path.GetDirectoryName(Application.ExecutablePath) + "\\UpTool2.lnk", dir + @"\UpTool2.exe", null, null, null, null, null); + Shortcut.Create(Environment.GetFolderPath(Environment.SpecialFolder.Programs) + "\\UpTool2.lnk", dir + @"\UpTool2.exe", null, null, null, null, null); + Close(); + } + + public class Shortcut + { + + private static Type m_type = Type.GetTypeFromProgID("WScript.Shell"); + private static object m_shell = Activator.CreateInstance(m_type); + + [ComImport, TypeLibType((short)0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")] + private interface IWshShortcut + { + [DispId(0)] + string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; } + [DispId(0x3e8)] + string Arguments { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] set; } + [DispId(0x3e9)] + string Description { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e9)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e9)] set; } + [DispId(0x3ea)] + string Hotkey { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ea)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ea)] set; } + [DispId(0x3eb)] + string IconLocation { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3eb)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3eb)] set; } + [DispId(0x3ec)] + string RelativePath { [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ec)] set; } + [DispId(0x3ed)] + string TargetPath { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ed)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ed)] set; } + [DispId(0x3ee)] + int WindowStyle { [DispId(0x3ee)] get; [param: In] [DispId(0x3ee)] set; } + [DispId(0x3ef)] + string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] set; } + [TypeLibFunc((short)0x40), DispId(0x7d0)] + void Load([In, MarshalAs(UnmanagedType.BStr)] string PathLink); + [DispId(0x7d1)] + void Save(); + } + + public static void Create(string fileName, string targetPath, string arguments, string workingDirectory, string description, string hotkey, string iconPath) + { + IWshShortcut shortcut = (IWshShortcut)m_type.InvokeMember("CreateShortcut", System.Reflection.BindingFlags.InvokeMethod, null, m_shell, new object[] { fileName }); + shortcut.Description = description; + shortcut.TargetPath = targetPath; + shortcut.WorkingDirectory = workingDirectory; + shortcut.Arguments = arguments; + if (!string.IsNullOrEmpty(hotkey)) + shortcut.Hotkey = hotkey; + if (!string.IsNullOrEmpty(iconPath)) + shortcut.IconLocation = iconPath; + shortcut.Save(); + } + } + #endregion + #region Definitions private struct App : IEquatable { public string name; @@ -504,6 +561,6 @@ namespace UpTool2 string getAppPath(Guid app) => appsPath + @"\" + app.ToString(); string getDataPath(Guid app) => getAppPath(app) + @"\app"; bool relE = true; -#endregion + #endregion } } diff --git a/UpTool2/Program.cs b/UpTool2/Program.cs index 62e94ac..4e01cd8 100644 --- a/UpTool2/Program.cs +++ b/UpTool2/Program.cs @@ -14,6 +14,7 @@ using System.Drawing; using System.Linq; using System.Collections.Generic; using System.Xml; +using System.IO.Compression; namespace UpTool2 { @@ -26,14 +27,13 @@ namespace UpTool2 { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - showSplash(); + ShowSplash(); string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString(); string mutexId = string.Format("Global\\{{{0}}}", appGuid); - bool createdNew; var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow); var securitySettings = new MutexSecurity(); securitySettings.AddAccessRule(allowEveryoneRule); - using (var mutex = new Mutex(false, mutexId, out createdNew, securitySettings)) + using (var mutex = new Mutex(false, mutexId, out bool createdNew, securitySettings)) { var hasHandle = false; #if !DEBUG @@ -57,10 +57,10 @@ namespace UpTool2 if (!Directory.Exists(dir + @"\Apps")) Directory.CreateDirectory(dir + @"\Apps"); string xml = dir + @"\info.xml"; - fixXML(xml); - string metaXml = "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Meta.xml"; - online = Ping(metaXml); - if (!online || updateCheck(dir, xml, metaXml)) + FixXML(xml); + string metaXML = XDocument.Load(xml).Element("meta").Element("UpdateSource").Value; + online = Ping(metaXML); + if (!online || UpdateCheck(dir, xml, metaXML)) Application.Run(new MainForm()); #if !DEBUG } @@ -77,7 +77,7 @@ namespace UpTool2 } } - static void showSplash() + static void ShowSplash() { splash = new Form { @@ -107,27 +107,30 @@ namespace UpTool2 splash.BringToFront(); } - static void fixXML(string xml) + static void FixXML(string xml) { try { if ((!File.Exists(xml)) || XDocument.Load(xml).Element("meta") == null) - new XElement("meta", new XElement("Version", 0), new XElement("Repos", new XElement("Repo", new XElement("Name", "UpTool2 official Repo"), new XElement("Link", "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Repo.xml"))), new XElement("LocalRepo")).Save(xml); + new XElement("meta", new XElement("Version", 0), new XElement("UpdateSource", "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Meta.xml"), new XElement("Repos", new XElement("Repo", new XElement("Name", "UpTool2 official Repo"), new XElement("Link", "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Repo.xml"))), new XElement("LocalRepo")).Save(xml); else { XDocument x = XDocument.Load(xml); XElement meta = x.Element("meta"); - if (XDocument.Load(xml).Element("meta").Element("Repos") == null || XDocument.Load(xml).Element("meta").Element("Repos").Elements("Repo").Count() == 0) - { + if (XDocument.Load(xml).Element("meta").Element("Version") == null) + meta.Add(new XElement("Version", 0)); + if (XDocument.Load(xml).Element("meta").Element("UpdateSource") == null) + meta.Add(new XElement("UpdateSource", "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Meta.xml")); + if (XDocument.Load(xml).Element("meta").Element("Repos") == null) meta.Add(new XElement("Repos", new XElement("Repo", new XElement("Name", "UpTool2 official Repo"), new XElement("Link", "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Repo.xml")))); - meta.Add(new XElement("LocalRepo")); - } + else if (XDocument.Load(xml).Element("meta").Element("Repos").Elements("Repo").Count() == 0) + meta.Element("Repos").Add(new XElement("Repo", new XElement("Name", "UpTool2 official Repo"), new XElement("Link", "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Repo.xml"))); else - { - XElement repos = meta.Element("Repos"); - IEnumerable reposa = repos.Elements("Repo"); - reposa.Select(s => s.Element("Link")).Where(s => s.Value == "https://github.com/CreepyCrafter24/UpTool2/releases/download/Repo/Repo.xml").ToList().ForEach(s => s.Value = "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Repo.xml"); - } + meta.Element("Repos").Elements("Repo").Select(s => s.Element("Link")) + .Where(s => s.Value == "https://github.com/CreepyCrafter24/UpTool2/releases/download/Repo/Repo.xml") + .ToList().ForEach(s => s.Value = "https://raw.githubusercontent.com/CreepyCrafter24/UpTool2/master/Repo.xml"); + if (XDocument.Load(xml).Element("meta").Element("LocalRepo") == null) + meta.Add(new XElement("LocalRepo")); x.Save(xml); } } @@ -137,20 +140,38 @@ namespace UpTool2 } } - static bool updateCheck(string dir, string xml, string metaXml) + static bool UpdateCheck(string dir, string xml, string metaXML) { - XElement meta = XDocument.Load(metaXml).Element("meta"); + XElement meta = XDocument.Load(metaXML).Element("meta"); int version = int.Parse(meta.Element("Version").Value); if (int.Parse(XDocument.Load(xml).Element("meta").Element("Version").Value) < version) { - if (new DownloadDialog(meta.Element("File").Value, dir + @"\update.exe").ShowDialog() != DialogResult.OK) - throw new Exception("Failed to update"); + using (DownloadDialog dlg = new DownloadDialog(meta.Element("File").Value, dir + @"\update.tmp")) + { + if (dlg.ShowDialog() != DialogResult.OK) + throw new Exception("Failed to update"); + } using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) { - string pkghash = BitConverter.ToString(sha256.ComputeHash(File.ReadAllBytes(dir + @"\update.exe"))).Replace("-", string.Empty).ToUpper(); + string pkghash = BitConverter.ToString(sha256.ComputeHash(File.ReadAllBytes(dir + @"\update.tmp"))).Replace("-", string.Empty).ToUpper(); if (pkghash != meta.Element("Hash").Value.ToUpper()) throw new Exception("The hash is not equal to the one stored in the repo:\r\nPackage: " + pkghash + "\r\nOnline: " + meta.Element("Hash").Value.ToUpper()); } + try + { + //Try extracting. This is done to support automatically built updates + if (Directory.Exists(dir + @"\update")) + Directory.Delete(dir + @"\update", true); + ZipFile.ExtractToDirectory(dir + @"\update.tmp", dir + @"\update"); + File.Delete(dir + @"\update.tmp"); + File.Copy(dir + @"\update", dir + @"\update.exe", true); + } + catch (InvalidDataException) + { + //If it can not be extracted as a .zip we try reading to see if it is a binary by trying to read it's name + AssemblyName.GetAssemblyName(dir + @"\update.tmp"); + File.Move(dir + @"\update.tmp", dir + @"\update.exe"); + } new XElement("meta", new XElement("Version", version)).Save(xml); splash.Hide(); Process.Start(new ProcessStartInfo { FileName = "cmd.exe", Arguments = "/C timeout /t 2 & copy /b/v/y \"" + dir + @"\update.exe" + "\" \"" + Application.ExecutablePath + "\" & \"" + Application.ExecutablePath + "\"", CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden }); diff --git a/UpTool2/UpTool2.csproj b/UpTool2/UpTool2.csproj index 3c1b8d7..85843e1 100644 --- a/UpTool2/UpTool2.csproj +++ b/UpTool2/UpTool2.csproj @@ -40,6 +40,7 @@ +