From 51ebcddda052190a0a043bf8be0603abc90f1ea4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Mar 2026 17:12:34 +0000 Subject: [PATCH 1/3] Fix service not restarting after update: elevate Start-Service call The update PowerShell script runs as the current user (non-admin), but Start-Service requires admin privileges. The previous code used -ErrorAction SilentlyContinue which silently swallowed the access-denied error, leaving the service stopped after every update. Fix by launching an elevated PowerShell subprocess with -Verb RunAs to perform the Start-Service, and refresh the service object before verifying status. https://claude.ai/code/session_01QH1N8t4s4SqfVA1ZcaWSpp --- Class/UpdateManager.vb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Class/UpdateManager.vb b/Class/UpdateManager.vb index 72baea4..cdd3d96 100644 --- a/Class/UpdateManager.vb +++ b/Class/UpdateManager.vb @@ -325,16 +325,17 @@ try {{ # Ignore cleanup errors }} -# Restart the service if it was installed +# Restart the service if it was installed (requires elevation) try {{ $service = Get-Service -Name 'LiteTaskService' -ErrorAction SilentlyContinue if ($service) {{ - Start-Service -Name 'LiteTaskService' -ErrorAction SilentlyContinue - # Wait briefly for service to start + Start-Process powershell -ArgumentList '-NoProfile -Command ""Start-Service LiteTaskService""' -Verb RunAs -WindowStyle Hidden -Wait -ErrorAction Stop + # Refresh and verify the service started + $service.Refresh() $service.WaitForStatus('Running', (New-TimeSpan -Seconds 30)) | Out-Null }} }} catch {{ - # Service not installed or failed to start, ignore + # Service not installed, user declined UAC, or failed to start }} # Restart the application From 1fe768e4f2007e9ee64d861eac2d0343960ef76d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Mar 2026 17:27:03 +0000 Subject: [PATCH 2/3] Fix service restart after update and clean up startup path - Update script: try Start-Service directly first, fall back to elevated subprocess only if it fails (avoids unnecessary UAC prompt when the current user already has admin rights). - Program.RunAsService: remove duplicate InitializeContainer() and temp-file cleanup that Main() already performed before reaching this method. - LiteTaskService: remove dead private RunAsService() that duplicated Program.RunAsService() and would dispose the service singleton prematurely via a Using block if ever called. https://claude.ai/code/session_01QH1N8t4s4SqfVA1ZcaWSpp --- Class/LiteTaskService.vb | 29 ----------------------------- Class/UpdateManager.vb | 10 +++++++--- Program.vb | 17 ++--------------- 3 files changed, 9 insertions(+), 47 deletions(-) diff --git a/Class/LiteTaskService.vb b/Class/LiteTaskService.vb index b3552a0..091b8e9 100644 --- a/Class/LiteTaskService.vb +++ b/Class/LiteTaskService.vb @@ -569,34 +569,5 @@ Namespace LiteTask End Using End Sub - Private Sub RunAsService() - Try - If Not EventLog.SourceExists("LiteTaskService") Then - EventLog.CreateEventSource("LiteTaskService", "Application") - End If - - InitializeContainer() - - Using service = ApplicationContainer.GetService(Of LiteTaskService)() - EventLog.WriteEntry("LiteTaskService", "Starting service...", EventLogEntryType.Information) - - service.EnsureRequiredPermissions() - - Dim servicesToRun() As ServiceBase = {service} - ServiceBase.Run(servicesToRun) - End Using - - Catch ex As Exception - LogServiceError("Error starting service", ex) - EventLog.WriteEntry("LiteTaskService", $"Error starting service: {ex.Message}", EventLogEntryType.Error) - Throw - Finally - Try - ApplicationContainer.Dispose() - Catch disposeEx As Exception - LogServiceError("Error disposing container", disposeEx) - End Try - End Try - End Sub End Class End Namespace diff --git a/Class/UpdateManager.vb b/Class/UpdateManager.vb index cdd3d96..080d800 100644 --- a/Class/UpdateManager.vb +++ b/Class/UpdateManager.vb @@ -325,12 +325,16 @@ try {{ # Ignore cleanup errors }} -# Restart the service if it was installed (requires elevation) +# Restart the service if it was installed try {{ $service = Get-Service -Name 'LiteTaskService' -ErrorAction SilentlyContinue if ($service) {{ - Start-Process powershell -ArgumentList '-NoProfile -Command ""Start-Service LiteTaskService""' -Verb RunAs -WindowStyle Hidden -Wait -ErrorAction Stop - # Refresh and verify the service started + try {{ + Start-Service -Name 'LiteTaskService' -ErrorAction Stop + }} catch {{ + # Direct start failed (e.g. insufficient privileges), try elevated + Start-Process powershell -ArgumentList '-NoProfile -Command ""Start-Service LiteTaskService""' -Verb RunAs -WindowStyle Hidden -Wait -ErrorAction Stop + }} $service.Refresh() $service.WaitForStatus('Running', (New-TimeSpan -Seconds 30)) | Out-Null }} diff --git a/Program.vb b/Program.vb index f2ffcc7..429d53a 100644 --- a/Program.vb +++ b/Program.vb @@ -389,21 +389,8 @@ Namespace LiteTask InitializeEventLogSource() EventLog.WriteEntry(ServiceName, "Starting service...", EventLogEntryType.Information) - ' Initialize app with secure defaults - InitializeContainer() - - ' Clean up any orphaned temp files from previous runs - Try - Dim logger = ApplicationContainer.GetService(Of Logger)() - logger.CleanupAllTempFiles() - - ' Also cleanup config files and backups - Dim xmlManager = ApplicationContainer.GetService(Of XMLManager)() - xmlManager.CleanupConfigFiles() - Catch ex As Exception - EventLog.WriteEntry(ServiceName, $"Warning: Failed to cleanup temp files: {ex.Message}", EventLogEntryType.Warning) - End Try - + ' Container and temp-file cleanup already performed in Main() + Dim service = ApplicationContainer.GetService(Of LiteTaskService)() Dim servicesToRun() As ServiceBase = {service} From 3265863116c32a78dd41c616f778c3bfa179ac75 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 19 Mar 2026 17:30:39 +0000 Subject: [PATCH 3/3] Guard against duplicate GUI instances at startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the single-instance mutex check before container initialization so a duplicate process exits immediately without spinning up the full DI container (Logger, CustomScheduler timers, XMLManager, etc.). The check now covers both the default GUI path (no args) and the -elevated path, which previously skipped the mutex entirely and could launch a second GUI alongside an existing one. Also removed the redundant InitializeContainer() call in HandleElevatedMode — Main() already initializes it before dispatch. https://claude.ai/code/session_01QH1N8t4s4SqfVA1ZcaWSpp --- Program.vb | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Program.vb b/Program.vb index 429d53a..9f30bdc 100644 --- a/Program.vb +++ b/Program.vb @@ -30,14 +30,30 @@ Namespace LiteTask Application.SetCompatibleTextRenderingDefault(False) End If + ' For GUI modes (no args or -elevated), check single instance + ' BEFORE initializing the container so a duplicate exits immediately + ' without spinning up DI services, timers, etc. + Dim isGuiMode = args.Length = 0 OrElse + (args.Length > 0 AndAlso args(0).Equals("-elevated", StringComparison.OrdinalIgnoreCase)) + + If isGuiMode Then + Dim createdNew As Boolean + _mutex = New Mutex(True, MutexName, createdNew) + If Not createdNew Then + MessageBox.Show("Another instance of LiteTask is already running.", "LiteTask", + MessageBoxButtons.OK, MessageBoxIcon.Information) + Return + End If + End If + ' Initialize container InitializeContainer() - + ' Clean up any orphaned temp files from previous runs Try Dim logger = ApplicationContainer.GetService(Of Logger)() logger.CleanupAllTempFiles() - + ' Also cleanup config files and backups Dim xmlManager = ApplicationContainer.GetService(Of XMLManager)() xmlManager.CleanupConfigFiles() @@ -53,15 +69,6 @@ Namespace LiteTask If args.Length > 0 Then HandleCommandLineArguments(args) Else - ' Check for single instance only in UI mode - Dim createdNew As Boolean - _mutex = New Mutex(True, MutexName, createdNew) - If Not createdNew Then - MessageBox.Show("Another instance of LiteTask is already running.", "LiteTask", - MessageBoxButtons.OK, MessageBoxIcon.Information) - Return - End If - ' Create and show the main application context Application.Run(New ApplicationContext()) End If @@ -190,11 +197,9 @@ Namespace LiteTask Private Sub HandleElevatedMode() Try - ' Perform elevated operations here - _logger?.LogInfo("Application running in elevated mode") - - ' Initialize with elevated privileges - InitializeContainer() + ' Container already initialized in Main(); mutex already acquired + Dim logger = TryGetService(Of Logger)() + logger?.LogInfo("Application running in elevated mode") ' Run the application Application.Run(New ApplicationContext())