Я работаю над системой самостоятельного обновления для моего приложения (MyApp). Идея в том, что у меня есть сервис Windows (MyUpdater) с таймером, который в интервале будет запускать проверку версии. Если есть более новая версия MyApp , она загрузит новый установщик MyAppSetup.exe (в настоящее время на основе настройки Inno). Новый установщик должен работать молча. Новая установка также может обновить службу MyUpdater . Большинство все, кажется, работает, но когда новый MyAppSetup.exe запускается, он, кажется, начинается, а затем просто придерживается и никогда не завершается. Ничто не регистрируется у установщика, хотя он установлен, поэтому я не думаю, что установщик когда -либо начинает работать. Зритель событий ничего не показывает, если я не убью процесс, в котором он возвращается.MyUpdater.csproj:
MyUpdater
net48
WinExe
Component
Component
< /code>
MyUpdater/app.config:
< /code>
MyUpdater/Constants.cs:
public class Constants
{
public const string WindowsServiceName = "MyAutoUpdate";
internal const string ProcessName = "MyApp";
internal const string VersionCheckerAppID = "MyAppID";
internal const string AppSettingsVersionCheckerBaseUrlKey = "VersionCheckerBaseUrl";
internal const string AppSettingsIntervalKey = "UpdateInterval";
internal static readonly TimeSpan WebClientTimeout = TimeSpan.FromHours(1);
internal static readonly TimeSpan DefaultUpdateInterval = TimeSpan.FromHours(3);
internal static readonly TimeSpan InstallerTimeout = TimeSpan.FromMinutes(3);
internal static string InstallerLogDirectory => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), WindowsServiceName, "Logs");
}
< /code>
MyUpdater/MyAutoUpdater.cs:
public class MyAutoUpdater : ServiceBase
{
private readonly string _versionCheckerUrl;
private readonly TimeSpan _updateInterval;
private readonly Version _currentVersion;
private readonly Timer _timer;
private string _tempFilePath;
public MyAutoUpdater()
{
ServiceName = Constants.WindowsServiceName;
AutoLog = true;
CanShutdown = true;
CanStop = true;
ExitCode = 0;
_currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version;
_versionCheckerUrl = ConfigurationManager.AppSettings[Constants.AppSettingsVersionCheckerBaseUrlKey];
if (string.IsNullOrEmpty(_versionCheckerUrl))
{
throw new ConfigurationErrorsException("No version checker URL was found in the config file.");
}
string intervalSettingString = ConfigurationManager.AppSettings[Constants.AppSettingsIntervalKey];
if (!string.IsNullOrEmpty(intervalSettingString))
{
if (!TimeSpan.TryParse(intervalSettingString, out _updateInterval))
{
_updateInterval = Constants.DefaultUpdateInterval;
}
}
else
{
_updateInterval = Constants.DefaultUpdateInterval;
}
_timer = new Timer
{
AutoReset = true,
Interval = _updateInterval.TotalMilliseconds
};
_timer.Elapsed += Timer_Elapsed;
}
public static void Main(string[] _)
{
Run(new MyAutoUpdater());
}
protected override void OnStart(string[] _)
{
_timer.Start();
}
protected override void OnStop()
{
ShutDown();
}
protected override void OnShutdown()
{
ShutDown();
}
private void ShutDown()
{
_timer.Stop();
_timer.Dispose();
}
private async void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
StringBuilder logBuilder = new StringBuilder();
logBuilder.AppendLine("Beginning update check.");
try
{
// Check internet connectivity
if (IsInternetAvailable())
{
logBuilder.AppendLine("Internet connection is available.");
VersionCheckerClient versionChecker = new VersionCheckerClient(new HttpClient { BaseAddress = new Uri(_versionCheckerUrl) });
logBuilder.AppendLine("Sending request to version checker.");
ApiResponse response = await versionChecker.CheckForUpdateAsync(Constants.VersionCheckerAppID, _currentVersion);
if (response.Successful)
{
logBuilder.AppendLine($"Version check successful. Latest version: {response.Model.Latest.Version}, Current version: {_currentVersion}, installer: {response.Model.LatestInstallerUrl}.");
if (response.Model.Latest.Version > _currentVersion && !string.IsNullOrEmpty(response.Model.LatestInstallerUrl))
{
string downloadUrl = response.Model.LatestInstallerUrl;
logBuilder.AppendLine($"Update available. Download URL: {downloadUrl}.");
// Extract the filename from the download URL
string fileName = Path.GetFileName(new Uri(downloadUrl).LocalPath);
string tempFilePath = Path.Combine(GetWritableTempPath(), fileName);
logBuilder.AppendLine($"Downloading update installer to: {tempFilePath}.");
// Download the update installer
using (HttpClient client = new HttpClient { Timeout = Constants.WebClientTimeout })
{
using HttpResponseMessage downloadResponse = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
downloadResponse.EnsureSuccessStatusCode();
using FileStream fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None);
await downloadResponse.Content.CopyToAsync(fileStream);
}
_tempFilePath = tempFilePath;
logBuilder.AppendLine($"Update installer downloaded to: {_tempFilePath}.");
}
else
{
logBuilder.AppendLine("No update available.");
}
}
else
{
logBuilder.AppendLine($"Version check failed: {response.Message}");
}
}
else
{
logBuilder.AppendLine("No internet connection. Cannot check for updates.");
}
if (!string.IsNullOrEmpty(_tempFilePath))
{
if (!AppIsRunning())
{
// INSTALL!
logBuilder.AppendLine($"Application is not running. Installing update from: {_tempFilePath}.");
StartSilentInstall(_tempFilePath, logBuilder);
// This program won't exist anymore once the downloaded update begins uninstalling the old version and installing the new version.
// So we can't wait for the installer process to finish in order to delete it from the "NT Service\System" TEMP folder.
_tempFilePath = null; // Reset the temp file path
}
else
{
logBuilder.AppendLine("Application is running. Update will be applied later.");
}
}
}
catch (Exception ex)
{
logBuilder.AppendLine($"Failed to update. Exception: {ex.Message}");
_tempFilePath = null; // Reset the temp file path
}
finally
{
logBuilder.AppendLine("Ending update check.");
EventLog.WriteEntry(logBuilder.ToString(), EventLogEntryType.Information);
}
static bool IsInternetAvailable()
{
try
{
using TcpClient client = new TcpClient();
IAsyncResult result = client.BeginConnect("8.8.8.8", 53, null, null);
bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3));
if (!success)
{
return false; // Timed out
}
client.EndConnect(result);
return true;
}
catch
{
return false;
}
}
static string GetWritableTempPath()
{
string tempDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutoUpdaterTemp");
if (!Directory.Exists(tempDirectory))
{
Directory.CreateDirectory(tempDirectory);
}
return tempDirectory;
}
static bool AppIsRunning()
{
Process[] appProcess = Process.GetProcessesByName(Constants.ProcessName);
return appProcess.Any();
}
static void StartSilentInstall(string setupPath, StringBuilder log)
{
string logDir = Constants.InstallerLogDirectory;
Directory.CreateDirectory(logDir);
string logPath = Path.Combine(logDir, $"install_{DateTime.Now:yyyyMMdd_HHmmss}.log");
Directory.CreateDirectory(Path.GetDirectoryName(logPath));
string args = $"/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOG=\"{logPath}\"";
string handoffExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MyUpdaterInstaller.exe");
using Process p = new Process();
p.StartInfo.FileName = handoffExe;
p.StartInfo.Arguments = $"--handoff \"{setupPath}\" {args}";
p.StartInfo.UseShellExecute = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Verb = "runas"; // Run as administrator
p.Start();
/*if (!p.WaitForExit((int) Constants.InstallerTimeout.TotalMilliseconds))
{
try
{
p.Kill();
}
catch
{
}
log?.AppendLine($"Installer timed out after {Constants.InstallerTimeout.TotalMilliseconds} and was killed.");
throw new System.ServiceProcess.TimeoutException("Installer did not finish within allotted time.");
}
log?.AppendLine($"Installer exited with code {p.ExitCode}. Log: {logPath}");*/
//return p.ExitCode;
}
}
}
< /code>
MyUpdater/WindowsServiceInstaller.cs:
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
public WindowsServiceInstaller()
{
ServiceProcessInstaller process = new ServiceProcessInstaller
{
Account = ServiceAccount.LocalSystem
};
ServiceInstaller service = new ServiceInstaller
{
ServiceName = Constants.WindowsServiceName,
DisplayName = "MyApp Updater",
Description = "Ensures that MyApp stays up to date.",
StartType = ServiceStartMode.Automatic
};
Installers.Add(process);
Installers.Add(service);
}
}
< /code>
MyUpdaterInstaller.csproj:
MyUpdaterInstaller
net48
Exe
< /code>
MyUpdaterInstaller/Program.cs:
internal class Program
{
private const string InstallArg = "--install";
private const string UninstallArg = "--uninstall";
private const string HandoffArg = "--handoff";
private const string ServiceExeName = "MyUpdater.exe";
private static string _serviceFullPath;
///
/// This program seems to solve the uninstaller's ability to actual remove the service when installing an update in the background.
/// Originally, the service could be executed to install/uninstall itself.
///
private static void Main(string[] args)
{
if (!EventLog.SourceExists(Constants.WindowsServiceName))
{
EventLog.CreateEventSource(Constants.WindowsServiceName, "Application");
}
_serviceFullPath = Path.Combine(AppContext.BaseDirectory, ServiceExeName);
if (!File.Exists(_serviceFullPath))
{
EventLog.WriteEntry(Constants.WindowsServiceName, $"The service exe is missing: {_serviceFullPath}", EventLogEntryType.Error);
return;
}
try
{
string argument = args.FirstOrDefault()?.Trim()?.ToLowerInvariant();
switch (argument)
{
case InstallArg:
EventLog.WriteEntry(Constants.WindowsServiceName, "Starting installation process.", EventLogEntryType.Information);
InstallAndStart();
EventLog.WriteEntry(Constants.WindowsServiceName, "Installation completed successfully.", EventLogEntryType.Information);
break;
case UninstallArg:
EventLog.WriteEntry(Constants.WindowsServiceName, "Starting uninstallation process.", EventLogEntryType.Information);
StopAndUninstall();
EventLog.WriteEntry(Constants.WindowsServiceName, "Uninstallation completed successfully.", EventLogEntryType.Information);
break;
case HandoffArg:
EventLog.WriteEntry(Constants.WindowsServiceName, "Starting handoff process.", EventLogEntryType.Information);
Handoff(args);
EventLog.WriteEntry(Constants.WindowsServiceName, "Handoff completed successfully.", EventLogEntryType.Information);
break;
default:
EventLog.WriteEntry(Constants.WindowsServiceName, $"Invalid argument: {argument}. Use {InstallArg}, {UninstallArg} or {HandoffArg}.", EventLogEntryType.Error);
break;
}
}
catch (Exception ex)
{
EventLog.WriteEntry(Constants.WindowsServiceName, $"An error occurred: {ex.Message}", EventLogEntryType.Error);
throw;
}
}
private static void InstallAndStart()
{
ManagedInstallerClass.InstallHelper(new[] { _serviceFullPath });
using (ServiceController sc = new ServiceController(Constants.WindowsServiceName))
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
EventLog.WriteEntry(Constants.WindowsServiceName, "Service installed and started successfully.", EventLogEntryType.Information);
RunHidden("sc.exe", $@"failure {Constants.WindowsServiceName} reset= 86400 actions= restart/60000/restart/60000/none/0");
RunHidden("sc.exe", $@"failureflag {Constants.WindowsServiceName} 1");
RunHidden("sc.exe", $@"config {Constants.WindowsServiceName} start= delayed-auto");
static void RunHidden(string file, string args)
{
using Process p = new Process();
p.StartInfo.FileName = file;
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.Start();
p.WaitForExit();
}
}
private static void StopAndUninstall()
{
if (IsInstalled())
{
using (ServiceController sc = new ServiceController(Constants.WindowsServiceName))
{
if (sc.Status == ServiceControllerStatus.Running)
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
}
ManagedInstallerClass.InstallHelper(new[] { "/u", _serviceFullPath });
EventLog.WriteEntry(Constants.WindowsServiceName, "Service stopped and uninstalled successfully.", EventLogEntryType.Information);
}
static bool IsInstalled()
{
try
{
using ServiceController sc = new ServiceController(Constants.WindowsServiceName);
ServiceControllerStatus status = sc.Status;
return true;
}
catch
{
return false;
}
}
}
private static void Handoff(string[] args)
{
// stop the service if it's running so the installer isn't blocked
using (ServiceController sc = new ServiceController(Constants.WindowsServiceName))
{
if (sc.Status == ServiceControllerStatus.Running)
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
}
string installerPath = args.Length > 1 ? args[1] : null;
string installerArgs = args.Length > 2 ? string.Join(" ", args.Skip(2)) : string.Empty;
if (string.IsNullOrWhiteSpace(installerPath) || !File.Exists(installerPath))
{
EventLog.WriteEntry(Constants.WindowsServiceName, $"Handoff requires a valid installer path. Provided: '{installerPath}'", EventLogEntryType.Error);
Environment.ExitCode = 2;
}
EventLog.WriteEntry(Constants.WindowsServiceName, $"Handoff [{installerPath} {installerArgs}]", EventLogEntryType.Information);
using Process p = new Process();
p.StartInfo.FileName = installerPath;
p.StartInfo.Arguments = installerArgs;
p.StartInfo.UseShellExecute = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Verb = "runas"; // Run as administrator
p.Start();
//p.WaitForExit();
//EventLog.WriteEntry(Constants.WindowsServiceName, $"Handoff installer exited with code {p.ExitCode}.", EventLogEntryType.Information);
// the installer should restart the service when it's done
}
}
Подробнее здесь: https://stackoverflow.com/questions/797 ... -sharp-app
Возникают проблемы с созданием приложения для самостоятельного обновления C# ⇐ C#
Место общения программистов C#
1756441489
Anonymous
Я работаю над системой самостоятельного обновления для моего приложения (MyApp). Идея в том, что у меня есть сервис Windows (MyUpdater) с таймером, который в интервале будет запускать проверку версии. Если есть более новая версия MyApp , она загрузит новый установщик MyAppSetup.exe (в настоящее время на основе настройки Inno). Новый установщик должен работать молча. Новая установка также может обновить службу MyUpdater . Большинство все, кажется, работает, но когда новый MyAppSetup.exe запускается, он, кажется, начинается, а затем просто придерживается и никогда не завершается. Ничто не регистрируется у установщика, хотя он установлен, поэтому я не думаю, что установщик когда -либо начинает работать. Зритель событий ничего не показывает, если я не убью процесс, в котором он возвращается.MyUpdater.csproj:
MyUpdater
net48
WinExe
Component
Component
< /code>
MyUpdater/app.config:
< /code>
MyUpdater/Constants.cs:
public class Constants
{
public const string WindowsServiceName = "MyAutoUpdate";
internal const string ProcessName = "MyApp";
internal const string VersionCheckerAppID = "MyAppID";
internal const string AppSettingsVersionCheckerBaseUrlKey = "VersionCheckerBaseUrl";
internal const string AppSettingsIntervalKey = "UpdateInterval";
internal static readonly TimeSpan WebClientTimeout = TimeSpan.FromHours(1);
internal static readonly TimeSpan DefaultUpdateInterval = TimeSpan.FromHours(3);
internal static readonly TimeSpan InstallerTimeout = TimeSpan.FromMinutes(3);
internal static string InstallerLogDirectory => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), WindowsServiceName, "Logs");
}
< /code>
MyUpdater/MyAutoUpdater.cs:
public class MyAutoUpdater : ServiceBase
{
private readonly string _versionCheckerUrl;
private readonly TimeSpan _updateInterval;
private readonly Version _currentVersion;
private readonly Timer _timer;
private string _tempFilePath;
public MyAutoUpdater()
{
ServiceName = Constants.WindowsServiceName;
AutoLog = true;
CanShutdown = true;
CanStop = true;
ExitCode = 0;
_currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version;
_versionCheckerUrl = ConfigurationManager.AppSettings[Constants.AppSettingsVersionCheckerBaseUrlKey];
if (string.IsNullOrEmpty(_versionCheckerUrl))
{
throw new ConfigurationErrorsException("No version checker URL was found in the config file.");
}
string intervalSettingString = ConfigurationManager.AppSettings[Constants.AppSettingsIntervalKey];
if (!string.IsNullOrEmpty(intervalSettingString))
{
if (!TimeSpan.TryParse(intervalSettingString, out _updateInterval))
{
_updateInterval = Constants.DefaultUpdateInterval;
}
}
else
{
_updateInterval = Constants.DefaultUpdateInterval;
}
_timer = new Timer
{
AutoReset = true,
Interval = _updateInterval.TotalMilliseconds
};
_timer.Elapsed += Timer_Elapsed;
}
public static void Main(string[] _)
{
Run(new MyAutoUpdater());
}
protected override void OnStart(string[] _)
{
_timer.Start();
}
protected override void OnStop()
{
ShutDown();
}
protected override void OnShutdown()
{
ShutDown();
}
private void ShutDown()
{
_timer.Stop();
_timer.Dispose();
}
private async void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
StringBuilder logBuilder = new StringBuilder();
logBuilder.AppendLine("Beginning update check.");
try
{
// Check internet connectivity
if (IsInternetAvailable())
{
logBuilder.AppendLine("Internet connection is available.");
VersionCheckerClient versionChecker = new VersionCheckerClient(new HttpClient { BaseAddress = new Uri(_versionCheckerUrl) });
logBuilder.AppendLine("Sending request to version checker.");
ApiResponse response = await versionChecker.CheckForUpdateAsync(Constants.VersionCheckerAppID, _currentVersion);
if (response.Successful)
{
logBuilder.AppendLine($"Version check successful. Latest version: {response.Model.Latest.Version}, Current version: {_currentVersion}, installer: {response.Model.LatestInstallerUrl}.");
if (response.Model.Latest.Version > _currentVersion && !string.IsNullOrEmpty(response.Model.LatestInstallerUrl))
{
string downloadUrl = response.Model.LatestInstallerUrl;
logBuilder.AppendLine($"Update available. Download URL: {downloadUrl}.");
// Extract the filename from the download URL
string fileName = Path.GetFileName(new Uri(downloadUrl).LocalPath);
string tempFilePath = Path.Combine(GetWritableTempPath(), fileName);
logBuilder.AppendLine($"Downloading update installer to: {tempFilePath}.");
// Download the update installer
using (HttpClient client = new HttpClient { Timeout = Constants.WebClientTimeout })
{
using HttpResponseMessage downloadResponse = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
downloadResponse.EnsureSuccessStatusCode();
using FileStream fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None);
await downloadResponse.Content.CopyToAsync(fileStream);
}
_tempFilePath = tempFilePath;
logBuilder.AppendLine($"Update installer downloaded to: {_tempFilePath}.");
}
else
{
logBuilder.AppendLine("No update available.");
}
}
else
{
logBuilder.AppendLine($"Version check failed: {response.Message}");
}
}
else
{
logBuilder.AppendLine("No internet connection. Cannot check for updates.");
}
if (!string.IsNullOrEmpty(_tempFilePath))
{
if (!AppIsRunning())
{
// INSTALL!
logBuilder.AppendLine($"Application is not running. Installing update from: {_tempFilePath}.");
StartSilentInstall(_tempFilePath, logBuilder);
// This program won't exist anymore once the downloaded update begins uninstalling the old version and installing the new version.
// So we can't wait for the installer process to finish in order to delete it from the "NT Service\System" TEMP folder.
_tempFilePath = null; // Reset the temp file path
}
else
{
logBuilder.AppendLine("Application is running. Update will be applied later.");
}
}
}
catch (Exception ex)
{
logBuilder.AppendLine($"Failed to update. Exception: {ex.Message}");
_tempFilePath = null; // Reset the temp file path
}
finally
{
logBuilder.AppendLine("Ending update check.");
EventLog.WriteEntry(logBuilder.ToString(), EventLogEntryType.Information);
}
static bool IsInternetAvailable()
{
try
{
using TcpClient client = new TcpClient();
IAsyncResult result = client.BeginConnect("8.8.8.8", 53, null, null);
bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3));
if (!success)
{
return false; // Timed out
}
client.EndConnect(result);
return true;
}
catch
{
return false;
}
}
static string GetWritableTempPath()
{
string tempDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutoUpdaterTemp");
if (!Directory.Exists(tempDirectory))
{
Directory.CreateDirectory(tempDirectory);
}
return tempDirectory;
}
static bool AppIsRunning()
{
Process[] appProcess = Process.GetProcessesByName(Constants.ProcessName);
return appProcess.Any();
}
static void StartSilentInstall(string setupPath, StringBuilder log)
{
string logDir = Constants.InstallerLogDirectory;
Directory.CreateDirectory(logDir);
string logPath = Path.Combine(logDir, $"install_{DateTime.Now:yyyyMMdd_HHmmss}.log");
Directory.CreateDirectory(Path.GetDirectoryName(logPath));
string args = $"/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOG=\"{logPath}\"";
string handoffExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MyUpdaterInstaller.exe");
using Process p = new Process();
p.StartInfo.FileName = handoffExe;
p.StartInfo.Arguments = $"--handoff \"{setupPath}\" {args}";
p.StartInfo.UseShellExecute = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Verb = "runas"; // Run as administrator
p.Start();
/*if (!p.WaitForExit((int) Constants.InstallerTimeout.TotalMilliseconds))
{
try
{
p.Kill();
}
catch
{
}
log?.AppendLine($"Installer timed out after {Constants.InstallerTimeout.TotalMilliseconds} and was killed.");
throw new System.ServiceProcess.TimeoutException("Installer did not finish within allotted time.");
}
log?.AppendLine($"Installer exited with code {p.ExitCode}. Log: {logPath}");*/
//return p.ExitCode;
}
}
}
< /code>
MyUpdater/WindowsServiceInstaller.cs:
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
public WindowsServiceInstaller()
{
ServiceProcessInstaller process = new ServiceProcessInstaller
{
Account = ServiceAccount.LocalSystem
};
ServiceInstaller service = new ServiceInstaller
{
ServiceName = Constants.WindowsServiceName,
DisplayName = "MyApp Updater",
Description = "Ensures that MyApp stays up to date.",
StartType = ServiceStartMode.Automatic
};
Installers.Add(process);
Installers.Add(service);
}
}
< /code>
MyUpdaterInstaller.csproj:
MyUpdaterInstaller
net48
Exe
< /code>
MyUpdaterInstaller/Program.cs:
internal class Program
{
private const string InstallArg = "--install";
private const string UninstallArg = "--uninstall";
private const string HandoffArg = "--handoff";
private const string ServiceExeName = "MyUpdater.exe";
private static string _serviceFullPath;
///
/// This program seems to solve the uninstaller's ability to actual remove the service when installing an update in the background.
/// Originally, the service could be executed to install/uninstall itself.
///
private static void Main(string[] args)
{
if (!EventLog.SourceExists(Constants.WindowsServiceName))
{
EventLog.CreateEventSource(Constants.WindowsServiceName, "Application");
}
_serviceFullPath = Path.Combine(AppContext.BaseDirectory, ServiceExeName);
if (!File.Exists(_serviceFullPath))
{
EventLog.WriteEntry(Constants.WindowsServiceName, $"The service exe is missing: {_serviceFullPath}", EventLogEntryType.Error);
return;
}
try
{
string argument = args.FirstOrDefault()?.Trim()?.ToLowerInvariant();
switch (argument)
{
case InstallArg:
EventLog.WriteEntry(Constants.WindowsServiceName, "Starting installation process.", EventLogEntryType.Information);
InstallAndStart();
EventLog.WriteEntry(Constants.WindowsServiceName, "Installation completed successfully.", EventLogEntryType.Information);
break;
case UninstallArg:
EventLog.WriteEntry(Constants.WindowsServiceName, "Starting uninstallation process.", EventLogEntryType.Information);
StopAndUninstall();
EventLog.WriteEntry(Constants.WindowsServiceName, "Uninstallation completed successfully.", EventLogEntryType.Information);
break;
case HandoffArg:
EventLog.WriteEntry(Constants.WindowsServiceName, "Starting handoff process.", EventLogEntryType.Information);
Handoff(args);
EventLog.WriteEntry(Constants.WindowsServiceName, "Handoff completed successfully.", EventLogEntryType.Information);
break;
default:
EventLog.WriteEntry(Constants.WindowsServiceName, $"Invalid argument: {argument}. Use {InstallArg}, {UninstallArg} or {HandoffArg}.", EventLogEntryType.Error);
break;
}
}
catch (Exception ex)
{
EventLog.WriteEntry(Constants.WindowsServiceName, $"An error occurred: {ex.Message}", EventLogEntryType.Error);
throw;
}
}
private static void InstallAndStart()
{
ManagedInstallerClass.InstallHelper(new[] { _serviceFullPath });
using (ServiceController sc = new ServiceController(Constants.WindowsServiceName))
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
EventLog.WriteEntry(Constants.WindowsServiceName, "Service installed and started successfully.", EventLogEntryType.Information);
RunHidden("sc.exe", $@"failure {Constants.WindowsServiceName} reset= 86400 actions= restart/60000/restart/60000/none/0");
RunHidden("sc.exe", $@"failureflag {Constants.WindowsServiceName} 1");
RunHidden("sc.exe", $@"config {Constants.WindowsServiceName} start= delayed-auto");
static void RunHidden(string file, string args)
{
using Process p = new Process();
p.StartInfo.FileName = file;
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.Start();
p.WaitForExit();
}
}
private static void StopAndUninstall()
{
if (IsInstalled())
{
using (ServiceController sc = new ServiceController(Constants.WindowsServiceName))
{
if (sc.Status == ServiceControllerStatus.Running)
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
}
ManagedInstallerClass.InstallHelper(new[] { "/u", _serviceFullPath });
EventLog.WriteEntry(Constants.WindowsServiceName, "Service stopped and uninstalled successfully.", EventLogEntryType.Information);
}
static bool IsInstalled()
{
try
{
using ServiceController sc = new ServiceController(Constants.WindowsServiceName);
ServiceControllerStatus status = sc.Status;
return true;
}
catch
{
return false;
}
}
}
private static void Handoff(string[] args)
{
// stop the service if it's running so the installer isn't blocked
using (ServiceController sc = new ServiceController(Constants.WindowsServiceName))
{
if (sc.Status == ServiceControllerStatus.Running)
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
}
string installerPath = args.Length > 1 ? args[1] : null;
string installerArgs = args.Length > 2 ? string.Join(" ", args.Skip(2)) : string.Empty;
if (string.IsNullOrWhiteSpace(installerPath) || !File.Exists(installerPath))
{
EventLog.WriteEntry(Constants.WindowsServiceName, $"Handoff requires a valid installer path. Provided: '{installerPath}'", EventLogEntryType.Error);
Environment.ExitCode = 2;
}
EventLog.WriteEntry(Constants.WindowsServiceName, $"Handoff [{installerPath} {installerArgs}]", EventLogEntryType.Information);
using Process p = new Process();
p.StartInfo.FileName = installerPath;
p.StartInfo.Arguments = installerArgs;
p.StartInfo.UseShellExecute = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Verb = "runas"; // Run as administrator
p.Start();
//p.WaitForExit();
//EventLog.WriteEntry(Constants.WindowsServiceName, $"Handoff installer exited with code {p.ExitCode}.", EventLogEntryType.Information);
// the installer should restart the service when it's done
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79749247/having-trouble-creating-self-updating-c-sharp-app[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия