mirror of
https://github.com/Ylianst/MeshCentralRouter
synced 2025-12-06 00:13:33 +00:00
Added auto-update system.
This commit is contained in:
34
MainForm.cs
34
MainForm.cs
@@ -150,6 +150,9 @@ namespace MeshCentralRouter
|
||||
|
||||
public MainForm(string[] args)
|
||||
{
|
||||
// Set TLS 1.2
|
||||
ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
|
||||
|
||||
this.args = args;
|
||||
InitializeComponent();
|
||||
mainPanel.Controls.Add(panel1);
|
||||
@@ -165,6 +168,8 @@ namespace MeshCentralRouter
|
||||
title = this.Text;
|
||||
|
||||
int argflags = 0;
|
||||
string update = null;
|
||||
string delete = null;
|
||||
foreach (string arg in this.args) {
|
||||
if (arg.ToLower() == "-oldstyle") { deviceListViewMode = false; }
|
||||
if (arg.ToLower() == "-install") { hookRouter(); forceExit = true; return; }
|
||||
@@ -179,12 +184,31 @@ namespace MeshCentralRouter
|
||||
if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-user:") { userNameTextBox.Text = arg.Substring(6); argflags |= 2; }
|
||||
if (arg.Length > 6 && arg.Substring(0, 6).ToLower() == "-pass:") { passwordTextBox.Text = arg.Substring(6); argflags |= 4; }
|
||||
if (arg.Length > 8 && arg.Substring(0, 8).ToLower() == "-search:") { searchTextBox.Text = arg.Substring(8); }
|
||||
if (arg.Length > 8 && arg.Substring(0, 8).ToLower() == "-update:") { update = arg.Substring(8); }
|
||||
if (arg.Length > 8 && arg.Substring(0, 8).ToLower() == "-delete:") { delete = arg.Substring(8); }
|
||||
if (arg.Length > 11 && arg.Substring(0, 11).ToLower() == "mcrouter://") { authLoginUrl = new Uri(arg); }
|
||||
if ((arg.Length > 1) && (arg[0] != '-') && (arg.ToLower().EndsWith(".mcrouter"))) { try { argflags |= loadMappingFile(File.ReadAllText(arg), 1); } catch (Exception) { } }
|
||||
if (arg.ToLower() == "-localfiles") { FileViewer fileViewer = new FileViewer(meshcentral, null); fileViewer.Show(); }
|
||||
}
|
||||
autoLogin = (argflags == 7);
|
||||
|
||||
if (update != null) {
|
||||
// New args
|
||||
ArrayList args2 = new ArrayList();
|
||||
foreach (string a in args) { if (a.StartsWith("-update:") == false) { args2.Add(a); } }
|
||||
|
||||
// Remove ".update.exe" and copy
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
File.Copy(Assembly.GetEntryAssembly().Location, update, true);
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
Process.Start(update, string.Join(" ", args2 + " -delete:" + Assembly.GetEntryAssembly().Location));
|
||||
this.forceExit = true;
|
||||
Application.Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (delete != null) { try { System.Threading.Thread.Sleep(1000); File.Delete(delete); } catch (Exception) { } }
|
||||
|
||||
// Set automatic port map values
|
||||
if (authLoginUrl != null) {
|
||||
string autoNodeId = null;
|
||||
@@ -371,6 +395,7 @@ namespace MeshCentralRouter
|
||||
meshcentral.onLoginTokenChanged += Meshcentral_onLoginTokenChanged;
|
||||
meshcentral.onClipboardData += Meshcentral_onClipboardData;
|
||||
meshcentral.onTwoFactorCookie += Meshcentral_onTwoFactorCookie;
|
||||
meshcentral.onToolUpdate += Meshcentral_onToolUpdate;
|
||||
if (lastBadConnectCert != null)
|
||||
{
|
||||
meshcentral.okCertHash = lastBadConnectCert.GetCertHashString();
|
||||
@@ -442,6 +467,7 @@ namespace MeshCentralRouter
|
||||
meshcentral.onLoginTokenChanged += Meshcentral_onLoginTokenChanged;
|
||||
meshcentral.onClipboardData += Meshcentral_onClipboardData;
|
||||
meshcentral.onTwoFactorCookie += Meshcentral_onTwoFactorCookie;
|
||||
meshcentral.onToolUpdate += Meshcentral_onToolUpdate;
|
||||
meshcentral.okCertHash = lastBadConnectCert.GetCertHashString();
|
||||
|
||||
Uri serverurl = null;
|
||||
@@ -472,6 +498,13 @@ namespace MeshCentralRouter
|
||||
}
|
||||
}
|
||||
|
||||
private void Meshcentral_onToolUpdate(string url, string hash, int size)
|
||||
{
|
||||
if (this.InvokeRequired) { this.Invoke(new MeshCentralServer.toolUpdateHandler(Meshcentral_onToolUpdate), url, hash, size); return; }
|
||||
UpdateForm f = new UpdateForm(url, hash, size, args);
|
||||
if (f.ShowDialog(this) == DialogResult.OK) { }
|
||||
}
|
||||
|
||||
private void Meshcentral_onLoginTokenChanged()
|
||||
{
|
||||
if (this.InvokeRequired) { this.Invoke(new MeshCentralServer.onLoginTokenChangedHandler(Meshcentral_onLoginTokenChanged)); return; }
|
||||
@@ -1020,6 +1053,7 @@ namespace MeshCentralRouter
|
||||
meshcentral.onLoginTokenChanged += Meshcentral_onLoginTokenChanged;
|
||||
meshcentral.onClipboardData += Meshcentral_onClipboardData;
|
||||
meshcentral.onTwoFactorCookie += Meshcentral_onTwoFactorCookie;
|
||||
meshcentral.onToolUpdate += Meshcentral_onToolUpdate;
|
||||
if (sendEmailToken == true)
|
||||
{
|
||||
sendEmailToken = false;
|
||||
|
||||
@@ -227,6 +227,12 @@
|
||||
<Compile Include="SettingsForm.Designer.cs">
|
||||
<DependentUpon>SettingsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UpdateForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="UpdateForm.Designer.cs">
|
||||
<DependentUpon>UpdateForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WebSocketClient.cs" />
|
||||
<Compile Include="Win32Api.cs" />
|
||||
<EmbeddedResource Include="AddPortMapForm.cs.resx">
|
||||
@@ -742,6 +748,9 @@
|
||||
<EmbeddedResource Include="SettingsForm.zh-chs.resx">
|
||||
<DependentUpon>SettingsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="UpdateForm.resx">
|
||||
<DependentUpon>UpdateForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.manifest">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
|
||||
@@ -218,6 +218,7 @@ namespace MeshCentralRouter
|
||||
wc.WriteStringWebSocket("{\"action\":\"nodes\"}");
|
||||
wc.WriteStringWebSocket("{\"action\":\"authcookie\"}");
|
||||
wc.WriteStringWebSocket("{\"action\":\"logincookie\"}");
|
||||
wc.WriteStringWebSocket("{\"action\":\"meshToolInfo\",\"name\":\"MeshCentralRouter\"}");
|
||||
break;
|
||||
}
|
||||
case "authcookie":
|
||||
@@ -582,6 +583,29 @@ namespace MeshCentralRouter
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "meshToolInfo":
|
||||
{
|
||||
if (onToolUpdate == null) return;
|
||||
if (jsonAction.ContainsKey("hash") && jsonAction.ContainsKey("url"))
|
||||
{
|
||||
// MeshCentral Router hash on the server
|
||||
string hash = (string)jsonAction["hash"];
|
||||
|
||||
// Hash our own executable
|
||||
byte[] selfHash;
|
||||
using (var sha384 = SHA384Managed.Create()) { using (var stream = File.OpenRead(System.Reflection.Assembly.GetEntryAssembly().Location)) { selfHash = sha384.ComputeHash(stream); } }
|
||||
string selfExecutableHashHex = BitConverter.ToString(selfHash).Replace("-", string.Empty).ToLower();
|
||||
|
||||
// Get login key
|
||||
string url = jsonAction["url"] + "&auth=" + authCookie;
|
||||
string loginkey = getValueFromQueryString(wsurl.Query, "key");
|
||||
if (loginkey != null) { url += ("&key=" + loginkey); }
|
||||
|
||||
// If the hashes don't match, event the tool update with URL
|
||||
if (selfExecutableHashHex != hash) { onToolUpdate((string)url, (string)jsonAction["hash"], (int)jsonAction["size"]); }
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
@@ -589,6 +613,18 @@ namespace MeshCentralRouter
|
||||
}
|
||||
}
|
||||
|
||||
private static string getValueFromQueryString(string query, string name)
|
||||
{
|
||||
if ((query == null) || (name == null)) return null;
|
||||
int i = query.IndexOf("?" + name + "=");
|
||||
if (i == -1) { i = query.IndexOf("&" + name + "="); }
|
||||
if (i == -1) return null;
|
||||
string r = query.Substring(i + name.Length + 2);
|
||||
i = r.IndexOf("&");
|
||||
if (i >= 0) { r = r.Substring(0, i); }
|
||||
return r;
|
||||
}
|
||||
|
||||
public delegate void onStateChangedHandler(int state);
|
||||
public event onStateChangedHandler onStateChanged;
|
||||
public void changeState(int newState) { if (constate != newState) { constate = newState; if (onStateChanged != null) { onStateChanged(constate); } } }
|
||||
@@ -601,6 +637,8 @@ namespace MeshCentralRouter
|
||||
public event onClipboardDataHandler onClipboardData;
|
||||
public delegate void twoFactorCookieHandler(string cookie);
|
||||
public event twoFactorCookieHandler onTwoFactorCookie;
|
||||
public delegate void toolUpdateHandler(string url, string hash, int size);
|
||||
public event toolUpdateHandler onToolUpdate;
|
||||
|
||||
public class xwebclient : IDisposable
|
||||
{
|
||||
|
||||
146
UpdateForm.Designer.cs
generated
Normal file
146
UpdateForm.Designer.cs
generated
Normal file
@@ -0,0 +1,146 @@
|
||||
namespace MeshCentralRouter
|
||||
{
|
||||
partial class UpdateForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdateForm));
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.mainLabel = new System.Windows.Forms.Label();
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
this.updateProgressBar = new System.Windows.Forms.ProgressBar();
|
||||
this.groupBox1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(294, 155);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 0;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.Location = new System.Drawing.Point(213, 155);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 1;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.groupBox1.Controls.Add(this.updateProgressBar);
|
||||
this.groupBox1.Controls.Add(this.pictureBox1);
|
||||
this.groupBox1.Controls.Add(this.mainLabel);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(357, 137);
|
||||
this.groupBox1.TabIndex = 2;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "MeshCentral Router Update";
|
||||
//
|
||||
// mainLabel
|
||||
//
|
||||
this.mainLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.mainLabel.Font = new System.Drawing.Font("Arial", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.mainLabel.Location = new System.Drawing.Point(131, 19);
|
||||
this.mainLabel.Name = "mainLabel";
|
||||
this.mainLabel.Size = new System.Drawing.Size(220, 115);
|
||||
this.mainLabel.TabIndex = 0;
|
||||
this.mainLabel.Text = "This MeshCentral Server uses a different version of this tool. Click ok to downlo" +
|
||||
"ad and update.";
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.pictureBox1.Image = global::MeshCentralRouter.Properties.Resources.MeshCentral;
|
||||
this.pictureBox1.Location = new System.Drawing.Point(6, 19);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(119, 112);
|
||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.pictureBox1.TabIndex = 1;
|
||||
this.pictureBox1.TabStop = false;
|
||||
//
|
||||
// updateProgressBar
|
||||
//
|
||||
this.updateProgressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.updateProgressBar.Location = new System.Drawing.Point(134, 110);
|
||||
this.updateProgressBar.Name = "updateProgressBar";
|
||||
this.updateProgressBar.Size = new System.Drawing.Size(217, 20);
|
||||
this.updateProgressBar.TabIndex = 2;
|
||||
this.updateProgressBar.Visible = false;
|
||||
//
|
||||
// UpdateForm
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(381, 190);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "UpdateForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Update";
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.Label mainLabel;
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
private System.Windows.Forms.ProgressBar updateProgressBar;
|
||||
}
|
||||
}
|
||||
116
UpdateForm.cs
Normal file
116
UpdateForm.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Security;
|
||||
using System.Windows.Forms;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace MeshCentralRouter
|
||||
{
|
||||
public partial class UpdateForm : Form
|
||||
{
|
||||
private string url = null;
|
||||
private string hash = null;
|
||||
private int size = 0;
|
||||
private string[] args = null;
|
||||
|
||||
public UpdateForm(string url, string hash, int size, string[] args)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.url = url;
|
||||
this.hash = hash;
|
||||
this.size = size;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
private void okButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
DownloadUpdate();
|
||||
}
|
||||
|
||||
private void Client_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e)
|
||||
{
|
||||
updateProgressBar.Value = e.ProgressPercentage;
|
||||
}
|
||||
|
||||
private void DownloadUpdate()
|
||||
{
|
||||
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
|
||||
Uri x = webRequest.RequestUri;
|
||||
webRequest.Method = "GET";
|
||||
webRequest.Timeout = 10000;
|
||||
webRequest.BeginGetResponse(new AsyncCallback(DownloadUpdateRespone), webRequest);
|
||||
webRequest.ServerCertificateValidationCallback += RemoteCertificateValidationCallback;
|
||||
updateProgressBar.Visible = true;
|
||||
}
|
||||
|
||||
public static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public delegate void updateProgressHandler(int ptr, int total);
|
||||
public void updateProgress(int ptr, int total)
|
||||
{
|
||||
if (this.InvokeRequired) { this.Invoke(new updateProgressHandler(updateProgress), ptr, total); return; }
|
||||
updateProgressBar.Visible = true;
|
||||
updateProgressBar.Maximum = total;
|
||||
if (ptr <= total) { updateProgressBar.Value = ptr; } else { updateProgressBar.Value = total; }
|
||||
}
|
||||
|
||||
public delegate void updateMessageHandler(string msg, int buttons);
|
||||
public void updateMessage(string msg, int buttons)
|
||||
{
|
||||
if (this.InvokeRequired) { this.Invoke(new updateMessageHandler(updateMessage), msg, buttons); return; }
|
||||
mainLabel.Text = msg;
|
||||
okButton.Enabled = ((buttons & 1) != 0);
|
||||
cancelButton.Enabled = ((buttons & 2) != 0);
|
||||
updateProgressBar.Visible = ((buttons & 4) != 0);
|
||||
}
|
||||
|
||||
private void DownloadUpdateRespone(IAsyncResult asyncResult)
|
||||
{
|
||||
long received = 0;
|
||||
HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;
|
||||
try
|
||||
{
|
||||
// Hash our own executable
|
||||
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult))
|
||||
{
|
||||
byte[] buffer = new byte[4096];
|
||||
FileStream fileStream = File.OpenWrite(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe");
|
||||
using (Stream input = webResponse.GetResponseStream())
|
||||
{
|
||||
int size = input.Read(buffer, 0, buffer.Length);
|
||||
while (size > 0)
|
||||
{
|
||||
fileStream.Write(buffer, 0, size);
|
||||
received += size;
|
||||
updateProgress((int)received, (int)size);
|
||||
size = input.Read(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
fileStream.Flush();
|
||||
fileStream.Close();
|
||||
|
||||
// Hash the resulting file
|
||||
byte[] downloadHash;
|
||||
using (var sha384 = SHA384Managed.Create()) { using (var stream = File.OpenRead(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe")) { downloadHash = sha384.ComputeHash(stream); } }
|
||||
string downloadHashHex = BitConverter.ToString(downloadHash).Replace("-", string.Empty).ToLower();
|
||||
if (downloadHashHex != hash) {
|
||||
updateMessage("Invalid download.", 2);
|
||||
File.Delete(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe");
|
||||
} else {
|
||||
updateMessage("Updating...", 0);
|
||||
Process.Start(System.Reflection.Assembly.GetEntryAssembly().Location + ".update.exe", "-update:" + System.Reflection.Assembly.GetEntryAssembly().Location + " " + string.Join(" ", args));
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { updateMessage("Error: " + ex.ToString(), 2); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
1815
UpdateForm.resx
Normal file
1815
UpdateForm.resx
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user