From e3a679609f87d508efb502daa478e777f61ef0cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 01:41:18 +0000 Subject: [PATCH 1/3] Initial plan Former-commit-id: d910034ea1889096ee95094600bdc1e6c0c1d9a5 From 10fa5acb0bf9d22c427c0766fb4e35bf7b6c83cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 01:44:40 +0000 Subject: [PATCH 2/3] Fix Windows PATH removal issue by implementing custom uninstall procedure Co-authored-by: oschwartz10612 <4999704+oschwartz10612@users.noreply.github.com> Former-commit-id: 1168f5541cada58c40b2770e7b8213e51377e542 --- olm.iss | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/olm.iss b/olm.iss index 8a76a18..cf08e57 100644 --- a/olm.iss +++ b/olm.iss @@ -57,13 +57,13 @@ Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" ; The 'Path' variable is located under 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'. ; ValueType: expandsz allows for environment variables (like %ProgramFiles%) in the path. ; ValueData: "{olddata};{app}" appends the current application directory to the existing PATH. -; Flags: uninsdeletevalue ensures the entry is removed upon uninstallation. -; Check: IsWin64 ensures this is applied on 64-bit systems, which matches ArchitecturesAllowed. +; Note: Removal during uninstallation is handled by CurUninstallStepChanged procedure in [Code] section. +; Check: NeedsAddPath ensures this is applied only if the path is not already present. [Registry] ; Add the application's installation directory to the system PATH. Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; \ - Flags: uninsdeletevalue; Check: NeedsAddPath(ExpandConstant('{app}')) + Check: NeedsAddPath(ExpandConstant('{app}')) [Code] function NeedsAddPath(Path: string): boolean; @@ -85,4 +85,75 @@ begin Result := False else Result := True; +end; + +procedure RemovePathEntry(PathToRemove: string); +var + OrigPath: string; + NewPath: string; + P: Integer; + UpperOrigPath: string; + UpperPathToRemove: string; +begin + if not RegQueryStringValue(HKEY_LOCAL_MACHINE, + 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', + 'Path', OrigPath) + then begin + // Path variable doesn't exist, nothing to remove + exit; + end; + + // Prepare for case-insensitive search + UpperOrigPath := ';' + UpperCase(OrigPath) + ';'; + UpperPathToRemove := ';' + UpperCase(PathToRemove) + ';'; + + // Check if the path exists in PATH + P := Pos(UpperPathToRemove, UpperOrigPath); + if P = 0 then + begin + // Path not found, nothing to remove + exit; + end; + + // Remove the path entry from OrigPath + // We need to handle the actual string with proper casing + NewPath := ';' + OrigPath + ';'; + + // Find and remove the entry (case-insensitive search but preserve original casing in other entries) + // We search for the pattern in the upper-case version but remove from the original + Delete(NewPath, P, Length(PathToRemove) + 1); // +1 for the semicolon + + // Clean up: remove leading and trailing semicolons, and reduce multiple semicolons to one + while (Length(NewPath) > 0) and (NewPath[1] = ';') do + Delete(NewPath, 1, 1); + while (Length(NewPath) > 0) and (NewPath[Length(NewPath)] = ';') do + Delete(NewPath, Length(NewPath), 1); + + // Replace multiple semicolons with single semicolon + while Pos(';;', NewPath) > 0 do + StringChangeEx(NewPath, ';;', ';', True); + + // Write the new PATH back to the registry + if RegWriteExpandStringValue(HKEY_LOCAL_MACHINE, + 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', + 'Path', NewPath) + then + Log('Successfully removed path entry: ' + PathToRemove) + else + Log('Failed to write modified PATH to registry'); +end; + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +var + AppPath: string; +begin + if CurUninstallStep = usUninstall then + begin + // Get the application installation path + AppPath := ExpandConstant('{app}'); + Log('Removing PATH entry for: ' + AppPath); + + // Remove only our path entry from the system PATH + RemovePathEntry(AppPath); + end; end; \ No newline at end of file From 36d47a7331fefa07d07dfc374400b2302f3334e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 01:46:51 +0000 Subject: [PATCH 3/3] Refactor PATH removal to use TStringList for more robust parsing Co-authored-by: oschwartz10612 <4999704+oschwartz10612@users.noreply.github.com> Former-commit-id: 91f0230d21e7d52e2f98059cf1cfaa4c40d130ed --- olm.iss | 73 ++++++++++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/olm.iss b/olm.iss index cf08e57..e903528 100644 --- a/olm.iss +++ b/olm.iss @@ -91,9 +91,8 @@ procedure RemovePathEntry(PathToRemove: string); var OrigPath: string; NewPath: string; - P: Integer; - UpperOrigPath: string; - UpperPathToRemove: string; + PathList: TStringList; + I: Integer; begin if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', @@ -103,44 +102,38 @@ begin exit; end; - // Prepare for case-insensitive search - UpperOrigPath := ';' + UpperCase(OrigPath) + ';'; - UpperPathToRemove := ';' + UpperCase(PathToRemove) + ';'; - - // Check if the path exists in PATH - P := Pos(UpperPathToRemove, UpperOrigPath); - if P = 0 then - begin - // Path not found, nothing to remove - exit; + // Create a string list to parse the PATH entries + PathList := TStringList.Create; + try + // Split the PATH by semicolons + PathList.Delimiter := ';'; + PathList.StrictDelimiter := True; + PathList.DelimitedText := OrigPath; + + // Find and remove the matching entry (case-insensitive) + for I := PathList.Count - 1 downto 0 do + begin + if CompareText(Trim(PathList[I]), Trim(PathToRemove)) = 0 then + begin + Log('Found and removing PATH entry: ' + PathList[I]); + PathList.Delete(I); + end; + end; + + // Reconstruct the PATH + NewPath := PathList.DelimitedText; + + // Write the new PATH back to the registry + if RegWriteExpandStringValue(HKEY_LOCAL_MACHINE, + 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', + 'Path', NewPath) + then + Log('Successfully removed path entry: ' + PathToRemove) + else + Log('Failed to write modified PATH to registry'); + finally + PathList.Free; end; - - // Remove the path entry from OrigPath - // We need to handle the actual string with proper casing - NewPath := ';' + OrigPath + ';'; - - // Find and remove the entry (case-insensitive search but preserve original casing in other entries) - // We search for the pattern in the upper-case version but remove from the original - Delete(NewPath, P, Length(PathToRemove) + 1); // +1 for the semicolon - - // Clean up: remove leading and trailing semicolons, and reduce multiple semicolons to one - while (Length(NewPath) > 0) and (NewPath[1] = ';') do - Delete(NewPath, 1, 1); - while (Length(NewPath) > 0) and (NewPath[Length(NewPath)] = ';') do - Delete(NewPath, Length(NewPath), 1); - - // Replace multiple semicolons with single semicolon - while Pos(';;', NewPath) > 0 do - StringChangeEx(NewPath, ';;', ';', True); - - // Write the new PATH back to the registry - if RegWriteExpandStringValue(HKEY_LOCAL_MACHINE, - 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', - 'Path', NewPath) - then - Log('Successfully removed path entry: ' + PathToRemove) - else - Log('Failed to write modified PATH to registry'); end; procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);