diff --git a/src/lib-csharp/Locators/DefaultProcessImpl.cs b/src/lib-csharp/Locators/DefaultProcessImpl.cs new file mode 100644 index 00000000..991174e1 --- /dev/null +++ b/src/lib-csharp/Locators/DefaultProcessImpl.cs @@ -0,0 +1,69 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using Velopack.Logging; +using Velopack.Util; + +namespace Velopack.Locators +{ + public class DefaultProcessImpl : IProcessImpl + { + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AllowSetForegroundWindow(int dwProcessId); + + private Process? _currentProcess; + private readonly IVelopackLogger _logger; + + public DefaultProcessImpl(IVelopackLogger logger) + { + _logger = logger; + } + + public string GetCurrentProcessPath() + { + _currentProcess ??= Process.GetCurrentProcess(); + var fileName = _currentProcess.MainModule?.FileName ?? + throw new InvalidOperationException($"Could not determine process path, please construct {nameof(IVelopackLocator)} manually."); + return Path.GetFullPath(fileName); + } + + public uint GetCurrentProcessId() + { + _currentProcess ??= Process.GetCurrentProcess(); + return (uint) _currentProcess.Id; + } + + public void StartProcess(string exePath, IEnumerable args, string? workDir, bool showWindow) + { + var psi = new ProcessStartInfo() { + CreateNoWindow = true, + FileName = exePath, + WorkingDirectory = workDir, + }; + + psi.AppendArgumentListSafe(args, out var debugArgs); + _logger.Debug($"Running: {psi.FileName} {debugArgs}"); + + var p = Process.Start(psi); + if (p == null) { + throw new Exception("Failed to launch process."); + } + + if (VelopackRuntimeInfo.IsWindows) { + try { + // this is an attempt to work around a bug where the restarted app fails to come to foreground. + if (!AllowSetForegroundWindow(p.Id)) + throw new Win32Exception(); + } catch (Exception ex) { + _logger.LogWarning(ex, "Failed to allow Update.exe to set foreground window."); + } + } + } + } +} \ No newline at end of file diff --git a/src/lib-csharp/Locators/IProcessImpl.cs b/src/lib-csharp/Locators/IProcessImpl.cs new file mode 100644 index 00000000..7d416266 --- /dev/null +++ b/src/lib-csharp/Locators/IProcessImpl.cs @@ -0,0 +1,14 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System.Collections; +using System.Collections.Generic; + +namespace Velopack.Locators +{ + public interface IProcessImpl + { + public string GetCurrentProcessPath(); + public uint GetCurrentProcessId(); + public void StartProcess(string exePath, IEnumerable args, string workDir, bool showWindow); + } +} \ No newline at end of file diff --git a/src/lib-csharp/Locators/IVelopackLocator.cs b/src/lib-csharp/Locators/IVelopackLocator.cs index a05ac5d1..308e19f2 100644 --- a/src/lib-csharp/Locators/IVelopackLocator.cs +++ b/src/lib-csharp/Locators/IVelopackLocator.cs @@ -52,17 +52,11 @@ namespace Velopack.Locators bool IsPortable { get; } /// - /// The process for which the Velopack Locator has been constructed. This should usually be the current process path. + /// Provides an abstraction for dealing with the dotnet Process API. This is used to start processes and + /// get information about the current process. /// - string ProcessExePath { get; } + IProcessImpl Process { get; } - /// - /// The process ID for which the Velopack Locator has been constructed. This should usually be the current process ID. - /// Setting this to zero will disable some features of Velopack (like the ability to wait for the process to exit - /// before installing updates). - /// - uint ProcessId { get; } - /// /// Finds .nupkg files in the PackagesDir and returns a list of ReleaseEntryName objects. /// diff --git a/src/lib-csharp/Locators/LinuxVelopackLocator.cs b/src/lib-csharp/Locators/LinuxVelopackLocator.cs index 7963fdb9..65768c8c 100644 --- a/src/lib-csharp/Locators/LinuxVelopackLocator.cs +++ b/src/lib-csharp/Locators/LinuxVelopackLocator.cs @@ -24,6 +24,9 @@ namespace Velopack.Locators /// public override string? UpdateExePath { get; } + /// + public override IProcessImpl Process { get; } + /// public override SemanticVersion? CurrentlyInstalledVersion { get; } @@ -51,28 +54,23 @@ namespace Velopack.Locators /// File path of the .AppImage which mounted and ran this application. public string? AppImagePath => Environment.GetEnvironmentVariable("APPIMAGE"); - /// - public override uint ProcessId { get; } - - /// - public override string ProcessExePath { get; } - /// /// Creates a new and auto-detects the /// app information from metadata embedded in the .app. /// - public LinuxVelopackLocator(string currentProcessPath, uint currentProcessId, IVelopackLogger? customLog) + public LinuxVelopackLocator(IProcessImpl? processImpl, IVelopackLogger? customLog) { if (!VelopackRuntimeInfo.IsLinux) throw new NotSupportedException($"Cannot instantiate {nameof(LinuxVelopackLocator)} on a non-linux system."); - ProcessId = currentProcessId; - var ourPath = ProcessExePath = currentProcessPath; - var combinedLog = new CombinedVelopackLogger(); combinedLog.Add(customLog); Log = combinedLog; + Process = processImpl ??= new DefaultProcessImpl(combinedLog); + var ourPath = processImpl.GetCurrentProcessPath(); + var currentProcessId = processImpl.GetCurrentProcessId(); + using var initLog = new CachedVelopackLogger(combinedLog); initLog.Info($"Initializing {nameof(LinuxVelopackLocator)}"); var logFilePath = Path.Combine(Path.GetTempPath(), DefaultLoggingFileName); diff --git a/src/lib-csharp/Locators/OsxVelopackLocator.cs b/src/lib-csharp/Locators/OsxVelopackLocator.cs index f7f4fc57..236d01df 100644 --- a/src/lib-csharp/Locators/OsxVelopackLocator.cs +++ b/src/lib-csharp/Locators/OsxVelopackLocator.cs @@ -24,6 +24,9 @@ namespace Velopack.Locators /// public override string? UpdateExePath { get; } + /// + public override IProcessImpl Process { get; } + /// public override SemanticVersion? CurrentlyInstalledVersion { get; } @@ -48,27 +51,22 @@ namespace Velopack.Locators /// public override string? Channel { get; } - /// - public override uint ProcessId { get; } - - /// - public override string ProcessExePath { get; } - /// /// Creates a new and auto-detects the /// app information from metadata embedded in the .app. /// - public OsxVelopackLocator(string currentProcessPath, uint currentProcessId, IVelopackLogger? customLog) + public OsxVelopackLocator(IProcessImpl? processImpl, IVelopackLogger? customLog) { if (!VelopackRuntimeInfo.IsOSX) throw new NotSupportedException($"Cannot instantiate {nameof(OsxVelopackLocator)} on a non-osx system."); - ProcessId = currentProcessId; - var ourPath = ProcessExePath = currentProcessPath; - var combinedLog = new CombinedVelopackLogger(); combinedLog.Add(customLog); Log = combinedLog; + + Process = processImpl ??= new DefaultProcessImpl(combinedLog); + var ourPath = processImpl.GetCurrentProcessPath(); + var currentProcessId = processImpl.GetCurrentProcessId(); using var initLog = new CachedVelopackLogger(combinedLog); initLog.Info($"Initializing {nameof(OsxVelopackLocator)}"); diff --git a/src/lib-csharp/Locators/TestVelopackLocator.cs b/src/lib-csharp/Locators/TestVelopackLocator.cs index 0ff4103f..12222f44 100644 --- a/src/lib-csharp/Locators/TestVelopackLocator.cs +++ b/src/lib-csharp/Locators/TestVelopackLocator.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using NuGet.Versioning; using Velopack.Logging; @@ -13,7 +14,7 @@ namespace Velopack.Locators /// having an installed application. This could be used in a CI/CD pipeline, or unit tests etc. /// [ExcludeFromCodeCoverage] - public class TestVelopackLocator : VelopackLocator + public class TestVelopackLocator : VelopackLocator, IProcessImpl { public override string? AppId { get { @@ -83,6 +84,8 @@ namespace Velopack.Locators public override IVelopackLogger Log { get; } + public override IProcessImpl Process => this; + public override VelopackAsset? GetLatestLocalFullPackage() { if (_asset != null) { @@ -92,10 +95,6 @@ namespace Velopack.Locators return base.GetLatestLocalFullPackage(); } - public override uint ProcessId => 0; - - public override string ProcessExePath { get; } - private readonly string? _updatePath; private readonly SemanticVersion? _version; private readonly string? _packages; @@ -104,6 +103,7 @@ namespace Velopack.Locators private readonly string? _appContent; private readonly string? _channel; private readonly VelopackAsset? _asset; + private readonly string? _processPath; /// public TestVelopackLocator(string appId, string version, string packagesDir, IVelopackLogger? logger = null) @@ -113,7 +113,8 @@ namespace Velopack.Locators /// public TestVelopackLocator(string appId, string version, string packagesDir, string? appDir, - string? rootDir, string? updateExe, string? channel = null, IVelopackLogger? logger = null, VelopackAsset? localPackage = null, string processPath = null!) + string? rootDir, string? updateExe, string? channel = null, IVelopackLogger? logger = null, VelopackAsset? localPackage = null, + string processPath = null!) { _id = appId; _packages = packagesDir; @@ -123,8 +124,23 @@ namespace Velopack.Locators _appContent = appDir; _channel = channel; _asset = localPackage; - ProcessExePath = processPath; + _processPath = processPath; Log = logger ?? new NullVelopackLogger(); } + + public string GetCurrentProcessPath() + { + return _processPath ?? throw new NotSupportedException("GetCurrentProcessPath is not supported in this test implementation."); + } + + public uint GetCurrentProcessId() + { + return 0; // Not implemented in this test mock + } + + public void StartProcess(string exePath, IEnumerable args, string workDir, bool showWindow) + { + new DefaultProcessImpl(Log).StartProcess(exePath, args, workDir, showWindow); + } } } \ No newline at end of file diff --git a/src/lib-csharp/Locators/VelopackLocator.cs b/src/lib-csharp/Locators/VelopackLocator.cs index 83a33aa9..b5bc03de 100644 --- a/src/lib-csharp/Locators/VelopackLocator.cs +++ b/src/lib-csharp/Locators/VelopackLocator.cs @@ -40,21 +40,16 @@ namespace Velopack.Locators } /// Create a new default locator based on the current operating system. - public static IVelopackLocator CreateDefaultForPlatform(IVelopackLogger? logger = null) + public static IVelopackLocator CreateDefaultForPlatform(IProcessImpl? processImpl = null, IVelopackLogger? logger = null) { - var process = Process.GetCurrentProcess(); - var processExePath = process.MainModule?.FileName - ?? throw new InvalidOperationException($"Could not determine process path, please construct {nameof(IVelopackLocator)} manually."); - var processId = (uint) process.Id; - if (VelopackRuntimeInfo.IsWindows) - return _current = new WindowsVelopackLocator(processExePath, processId, logger); + return _current = new WindowsVelopackLocator(processImpl, logger); if (VelopackRuntimeInfo.IsOSX) - return _current = new OsxVelopackLocator(processExePath, processId, logger); + return _current = new OsxVelopackLocator(processImpl, logger); if (VelopackRuntimeInfo.IsLinux) - return _current = new LinuxVelopackLocator(processExePath, processId, logger); + return _current = new LinuxVelopackLocator(processImpl, logger); throw new PlatformNotSupportedException($"OS platform '{VelopackRuntimeInfo.SystemOs.GetOsLongName()}' is not supported."); } @@ -64,9 +59,9 @@ namespace Velopack.Locators _current = locator; } - internal static IVelopackLocator GetCurrentOrCreateDefault(IVelopackLogger? logger = null) + internal static IVelopackLocator GetCurrentOrCreateDefault(IProcessImpl? processImpl = null, IVelopackLogger? logger = null) { - _current ??= CreateDefaultForPlatform(logger); + _current ??= CreateDefaultForPlatform(processImpl, logger); return _current; } @@ -94,20 +89,17 @@ namespace Velopack.Locators /// public abstract IVelopackLogger Log { get; } - /// - public abstract uint ProcessId { get; } - - /// - public abstract string ProcessExePath { get; } - /// public virtual bool IsPortable => false; + /// + public abstract IProcessImpl Process { get; } + /// public virtual string? ThisExeRelativePath { get { if (AppContentDir == null) return null; - var path = ProcessExePath; + var path = Process.GetCurrentProcessPath(); if (path.StartsWith(AppContentDir, StringComparison.OrdinalIgnoreCase)) { return path.Substring(AppContentDir.Length + 1); } else { diff --git a/src/lib-csharp/Locators/WindowsVelopackLocator.cs b/src/lib-csharp/Locators/WindowsVelopackLocator.cs index 1e494ac4..dbbf4b9d 100644 --- a/src/lib-csharp/Locators/WindowsVelopackLocator.cs +++ b/src/lib-csharp/Locators/WindowsVelopackLocator.cs @@ -1,6 +1,8 @@ -using System; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.Versioning; using NuGet.Versioning; using Velopack.Logging; @@ -30,8 +32,10 @@ namespace Velopack.Locators /// public override SemanticVersion? CurrentlyInstalledVersion { get; } + private readonly Lazy _packagesDir; + /// - public override string? PackagesDir => CreateSubDirIfDoesNotExist(RootAppDir, "packages"); + public override string? PackagesDir => _packagesDir.Value; /// public override IVelopackLogger Log { get; } @@ -39,30 +43,30 @@ namespace Velopack.Locators /// public override bool IsPortable => RootAppDir != null && File.Exists(Path.Combine(RootAppDir, ".portable")); + /// + public override IProcessImpl Process { get; } + /// public override string? Channel { get; } - /// - public override uint ProcessId { get; } - - /// - public override string ProcessExePath { get; } - /// - public WindowsVelopackLocator(string currentProcessPath, uint currentProcessId, IVelopackLogger? customLog) + public WindowsVelopackLocator(IProcessImpl? processImpl, IVelopackLogger? customLog) { if (!VelopackRuntimeInfo.IsWindows) throw new NotSupportedException($"Cannot instantiate {nameof(WindowsVelopackLocator)} on a non-Windows system."); - ProcessId = currentProcessId; - var ourPath = ProcessExePath = currentProcessPath; + _packagesDir = new(GetPackagesDir); var combinedLog = new CombinedVelopackLogger(); combinedLog.Add(customLog); Log = combinedLog; + Process = processImpl ??= new DefaultProcessImpl(combinedLog); + var ourPath = processImpl.GetCurrentProcessPath(); + var currentProcessId = processImpl.GetCurrentProcessId(); + using var initLog = new CachedVelopackLogger(combinedLog); - initLog.Info($"Initialising {nameof(WindowsVelopackLocator)}"); + initLog.Info($"Initializing {nameof(WindowsVelopackLocator)}"); // We try various approaches here. Firstly, if Update.exe is in the parent directory, // we use that. If it's not present, we search for a parent "current" or "app-{ver}" directory, @@ -70,7 +74,6 @@ namespace Velopack.Locators // There is some legacy code here, because it's possible that we're running in an "app-{ver}" // directory which is NOT containing a sq.version, in which case we need to infer a lot of info. - ProcessExePath = Path.GetFullPath(ourPath); string myDirPath = Path.GetDirectoryName(ourPath)!; var myDirName = Path.GetFileName(myDirPath); var possibleUpdateExe = Path.GetFullPath(Path.Combine(myDirPath, "..", "Update.exe")); @@ -120,36 +123,99 @@ namespace Velopack.Locators } } - bool fileLogCreated = false; + if (UpdateExePath != null + && Path.GetDirectoryName(UpdateExePath) is { } updateExeDirectory + && !PathUtil.IsDirectoryWritable(updateExeDirectory)) { + var tempTargetUpdateExe = Path.Combine(TempAppRootDirectory, "Update.exe"); + if (File.Exists(UpdateExePath) && !File.Exists(tempTargetUpdateExe)) { + initLog.Warn("Application directory is not writable. Copying Update.exe to temp location: " + tempTargetUpdateExe); + Debugger.Launch(); + Directory.CreateDirectory(TempAppRootDirectory); + File.Copy(UpdateExePath, tempTargetUpdateExe); + } + UpdateExePath = tempTargetUpdateExe; + } + + //bool fileLogCreated = false; + Exception? fileLogException = null; if (!String.IsNullOrEmpty(AppId) && !String.IsNullOrEmpty(RootAppDir)) { try { var logFilePath = Path.Combine(RootAppDir, DefaultLoggingFileName); var fileLog = new FileVelopackLogger(logFilePath, currentProcessId); combinedLog.Add(fileLog); - fileLogCreated = true; - } catch (Exception ex2) { - initLog.Error("Unable to create default file logger: " + ex2); + //fileLogCreated = true; + } catch (Exception ex) { + fileLogException = ex; } } // if the RootAppDir was unwritable, or we don't know the app id, we could try to write to the temp folder instead. - if (!fileLogCreated) { + Exception? tempFileLogException = null; + if (fileLogException is not null) { try { var logFileName = String.IsNullOrEmpty(AppId) ? DefaultLoggingFileName : $"velopack_{AppId}.log"; var logFilePath = Path.Combine(Path.GetTempPath(), logFileName); var fileLog = new FileVelopackLogger(logFilePath, currentProcessId); combinedLog.Add(fileLog); - } catch (Exception ex2) { - initLog.Error("Unable to create temp folder file logger: " + ex2); + } catch (Exception ex) { + tempFileLogException = ex; } } + if (tempFileLogException is not null) { + //NB: fileLogException is not null here + initLog.Error("Unable to create file logger: " + new AggregateException(fileLogException!, tempFileLogException)); + } else if (fileLogException is not null) { + initLog.Info("Unable to create file logger; using temp directory for log instead"); + initLog.Trace($"File logger exception: {fileLogException}"); + } + if (AppId == null) { initLog.Warn( - $"Failed to initialise {nameof(WindowsVelopackLocator)}. This could be because the program is not installed or packaged properly."); + $"Failed to initialize {nameof(WindowsVelopackLocator)}. This could be because the program is not installed or packaged properly."); } else { - initLog.Info($"Initialised {nameof(WindowsVelopackLocator)} for {AppId} v{CurrentlyInstalledVersion}"); + initLog.Info($"Initialized {nameof(WindowsVelopackLocator)} for {AppId} v{CurrentlyInstalledVersion}"); } } + + private string? GetPackagesDir() + { + const string PackagesDirName = "packages"; + + string? writableRootDir = PossibleDirectories() + .FirstOrDefault(IsWritable); + + if (writableRootDir == null) { + Log.Warn("Unable to find a writable root directory for package."); + return null; + } + + Log.Trace("Using writable root directory: " + writableRootDir); + + return CreateSubDirIfDoesNotExist(writableRootDir, PackagesDirName); + + static bool IsWritable(string? directoryPath) + { + if (directoryPath == null) return false; + + try { + if (!Directory.Exists(directoryPath)) { + Directory.CreateDirectory(directoryPath); + } + + return PathUtil.IsDirectoryWritable(directoryPath); + } catch { + return false; + } + } + + IEnumerable PossibleDirectories() + { + yield return RootAppDir; + yield return TempAppRootDirectory; + } + } + + private string TempAppRootDirectory => Path.Combine(Path.GetTempPath(), "velopack_" + AppId); } } \ No newline at end of file diff --git a/src/lib-csharp/UpdateExe.cs b/src/lib-csharp/UpdateExe.cs index 920c670c..c48c42b2 100644 --- a/src/lib-csharp/UpdateExe.cs +++ b/src/lib-csharp/UpdateExe.cs @@ -1,11 +1,5 @@ -using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; using Velopack.Locators; using Velopack.Logging; using Velopack.Util; @@ -19,40 +13,6 @@ namespace Velopack /// public static class UpdateExe { - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool AllowSetForegroundWindow(int dwProcessId); - - private static Process StartUpdateExe(IVelopackLogger logger, IVelopackLocator locator, IEnumerable args) - { - var psi = new ProcessStartInfo() { - CreateNoWindow = true, - FileName = locator.UpdateExePath!, - WorkingDirectory = Path.GetDirectoryName(locator.UpdateExePath)!, - }; - - psi.AppendArgumentListSafe(args, out var debugArgs); - logger.Debug($"Running: {psi.FileName} {debugArgs}"); - - var p = Process.Start(psi); - if (p == null) { - throw new Exception("Failed to launch Update.exe process."); - } - - if (VelopackRuntimeInfo.IsWindows) { - try { - // this is an attempt to work around a bug where the restarted app fails to come to foreground. - if (!AllowSetForegroundWindow(p.Id)) - throw new Win32Exception(); - } catch (Exception ex) { - logger.LogWarning(ex, "Failed to allow Update.exe to set foreground window."); - } - } - - logger.Info("Update.exe executed successfully."); - return p; - } - /// /// Runs Update.exe in the current working directory with the 'start' command which will simply start the application. /// Combined with the `waitForExit` parameter, this can be used to gracefully restart the application. @@ -79,10 +39,24 @@ namespace Velopack } } - StartUpdateExe(locator.Log, locator, args); + var updatePath = locator.UpdateExePath!; + var workingDir = Path.GetDirectoryName(updatePath)!; + locator.Process.StartProcess(updatePath, args, workingDir, false); + locator.Log.Info("Update.exe [start] executed successfully."); } - private static Process ApplyImpl(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart, + /// + /// Runs Update.exe in the current working directory to apply updates, optionally restarting the application. + /// + /// If true, no dialogs will be shown during the update process. This could result + /// in an update failing to install, such as when we need to ask the user for permission to install + /// a new framework dependency. + /// If true, restarts the application after updates are applied (or if they failed) + /// The locator to use to find the path to Update.exe and the packages directory. + /// The update package you wish to apply, can be left null. + /// Optionally wait for the specified process to exit before continuing. + /// The arguments to pass to the application when it is restarted. + public static void Apply(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart, string[]? restartArgs = null) { locator ??= VelopackLocator.Current; @@ -107,6 +81,9 @@ namespace Velopack if (!restart) args.Add("--norestart"); // restarting is now the default Update.exe behavior + args.Add("--root"); + args.Add(locator.RootAppDir!); + if (restart && restartArgs != null && restartArgs.Length > 0) { args.Add("--"); foreach (var a in restartArgs) { @@ -114,42 +91,10 @@ namespace Velopack } } - return StartUpdateExe(locator.Log, locator, args); - } - - /// - /// Runs Update.exe in the current working directory to apply updates, optionally restarting the application. - /// - /// If true, no dialogs will be shown during the update process. This could result - /// in an update failing to install, such as when we need to ask the user for permission to install - /// a new framework dependency. - /// If true, restarts the application after updates are applied (or if they failed) - /// The locator to use to find the path to Update.exe and the packages directory. - /// The update package you wish to apply, can be left null. - /// Optionally wait for the specified process to exit before continuing. - /// The arguments to pass to the application when it is restarted. - /// Thrown if Update.exe does not initialize properly. - public static void Apply(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart, - string[]? restartArgs = null) - { - var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs); - Thread.Sleep(500); - - if (process.HasExited) { - throw new Exception($"Update.exe process exited too soon ({process.ExitCode})."); - } - } - - /// - public static async Task ApplyAsync(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart, - string[]? restartArgs = null) - { - var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs); - await Task.Delay(500).ConfigureAwait(false); - - if (process.HasExited) { - throw new Exception($"Update.exe process exited too soon ({process.ExitCode})."); - } + var updatePath = locator.UpdateExePath!; + var workingDir = Path.GetDirectoryName(updatePath)!; + locator.Process.StartProcess(updatePath, args, workingDir, false); + locator.Log.Info("Update.exe [apply] executed successfully."); } } } \ No newline at end of file diff --git a/src/lib-csharp/UpdateManager.Helpers.cs b/src/lib-csharp/UpdateManager.Helpers.cs index ea4e0d74..328734c1 100644 --- a/src/lib-csharp/UpdateManager.Helpers.cs +++ b/src/lib-csharp/UpdateManager.Helpers.cs @@ -44,13 +44,8 @@ namespace Velopack /// The arguments to pass to the application when it is restarted. public void WaitExitThenApplyUpdates(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null) { - UpdateExe.Apply(Locator, toApply, silent, Locator.ProcessId, restart, restartArgs); - } - - /// - public async Task WaitExitThenApplyUpdatesAsync(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null) - { - await UpdateExe.ApplyAsync(Locator, toApply, silent, Locator.ProcessId, restart, restartArgs).ConfigureAwait(false); + UpdateExe.Apply(Locator, toApply, silent, Locator.Process.GetCurrentProcessId(), restart, restartArgs); } + } } \ No newline at end of file diff --git a/src/lib-csharp/VelopackApp.cs b/src/lib-csharp/VelopackApp.cs index 8a20fe16..9d340592 100644 --- a/src/lib-csharp/VelopackApp.cs +++ b/src/lib-csharp/VelopackApp.cs @@ -172,7 +172,7 @@ namespace Velopack VelopackLocator.SetCurrentLocator(_customLocator); } - var locator = VelopackLocator.GetCurrentOrCreateDefault(_customLogger); + var locator = VelopackLocator.GetCurrentOrCreateDefault(null, _customLogger); var log = locator.Log; log.Info($"Starting VelopackApp.Run (library version {VelopackRuntimeInfo.VelopackNugetVersion})."); @@ -231,7 +231,7 @@ namespace Velopack log.Info($"Launching app is out-dated. Current: {myVersion}, Newest Local Available: {latestLocal.Version}"); if (!restarted && _autoApply) { log.Info("Auto apply is true, so restarting to apply update..."); - UpdateExe.Apply(locator, latestLocal, false, locator.ProcessId, true, args); + UpdateExe.Apply(locator, latestLocal, false, locator.Process.GetCurrentProcessId(), true, args); Exit(0); } else { log.Info("Pre-condition failed, we will not restart to apply updates. (restarted: " + restarted + ", autoApply: " + _autoApply + ")");