Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change all entries to all users #1632

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

mpheath
Copy link
Collaborator

@mpheath mpheath commented Feb 15, 2022

This change will be a little disruptive and may require changes in Sandman to be compatible. More changes can be done to the installer if needed.

I have made changes with Inno constants and registry hives to all be automatically for All Users. This change may create duplicate icons to display on the desktop (Current User and All Users desktops), so the InstallDelete section will remove the icons on the Current User desktop. Duplicate entries will be in the HKCU and HKLM hives. These duplicate entries will probably not be noticable to the user and will be removed at unistall.

I recommend uninstall and install instead of upgrade once the changes are released, though the new InstallDelete section entries may help prevent bug reports for those who unknowingly upgrade.

These All Users changes put the installer out of sync with Sandmans ability of creating and changing registry entries which Sandman does for the Current User. I suggest that Sandman hide these options when installed and only show them in portable mode to avoid the user from duplicating registry entries. If Sandman does not hide these options then the Uninstaller may need to remove the entries to cleanup.

Some options in Shell Integration tab of Sandman:

  • Start UI with Windows
    • Installer adds to HKLM hive. Sandman adds to HKCU hive. Sandman can enable, though cannot disable if already set by the installer or unless running as admin. Unistaller may need to remove these entries created by Sandman if Sandman does not hide the option to create them.
  • Start UI when a sandboxed process is started
    • This would be a change to sandboxie.ini. Not handled by the installer.
  • Add "Run Sandboxed" to the explorer context menu
    • See "Start UI with Windows".
  • Always use DefaultBox
    • This would be a change to Sandboxie-Plus.ini. Not handled by the installer.

2 out of 4 of those options could be hidden by Sandman if installed (as not portable).

Will assign to David and if Sandman is updated as suggested and David is satisfied, David can merge. If other, let me know.

@isaak654
Copy link
Collaborator

isaak654 commented Feb 16, 2022

Since Plus 1.0.10 there is a new option called Add "Run Un-Sandboxed" in Shell Integration tab, so it would be 3 out of 5 if that will be ever implemented as installer option.

Anyway, I really doubt that hiding those entries in Sandman is a great solution, since some users are expressly pointed in different threads to uncheck them and reapply them. Hiding them would mean less customization, so I would prefer a specific "Reset" or "Reassociate" button / function to be applied when needed in the Shell Integration tab (according to what you would like to achieve). Or the shell entries may be adapted for both HKLM and HKCU use cases.

I recommend uninstall and install instead of upgrade once the changes are released

I would suggest skipping the upgrade screen programmatically when one of the duplicate entries is found on both HKCU and HKLM hives. In this case, a MessageBox like this would be needed:
Duplicated entries detected, Sandboxie Plus must be uninstalled first. Do you want to uninstall it now?

It would result similar to the english.ClassicFound reference in Languages.iss.

@mpheath
Copy link
Collaborator Author

mpheath commented Feb 17, 2022

Since Plus 1.0.10 there is a new option called Add "Run Un-Sandboxed" in Shell Integration tab, so it would be 3 out of 5 if that will be ever implemented as installer option.

Thanks for the info, updated test files from 1.0.8 to 1.0.11. I doubt some people would want the "Run Un-Sandboxed" context menu entry as it is only useful for those who use forced programs. So might be a separate checkbox item, unless it is not needed as it may confuse people who do not understand what it is meant for. Perhaps the checkbox item should be delayed until this option is tested, tried and understood by everyone, including me.

Anyway, I really doubt that hiding those entries in Sandman is a great solution, since some users are expressly pointed in different threads to uncheck them and reapply them. But it would be acceptable if accompanied with a specific "Reset" or "Reassociate" button in the Shell Integration tab (according to what you would like to achieve).

What is not great is booting the VM and having sandman.exe running 2 instances. Will have to change to running sandman.exe back to the HKCU hive, as the instance run from the HKLM hive would be running as admin. So perhaps can keep the autorun Sandman option shown in Sandman. The question becomes, should the autorun Sandman option be in the installer as it will not be for All Users. I may need to test HKU and see if it is useful, else it will be HKCU.

I recommend uninstall and install instead of upgrade once the changes are released

I would suggest disabling the upgrade button programmatically when one of the duplicate entries is found on both HKCU and HKLM hives. In this case, a MessageBox like this would be needed:
Duplicated entries detected, Sandboxie Plus must be uninstalled first. Do you want to uninstall it now?

Thanks for suggestion. Programmic blocks should not be done unless absolutely necessary. I expect something else will be done like I did with InstallDelete. Upgrade is expected to be possible, just a good idea to uninstall so as to avoid possible weird behavior due to the changes. A recommendation is not some must do or else kind of thing.

It would result similar to the english.ClassicFound reference in Languages.iss.

Comparing some registry entries with an install of Classic is quite different to me.

I will put this PR into draft mode temporarily as some more time is needed to test new ideas and overcome some issues.

@mpheath mpheath marked this pull request as draft February 17, 2022 07:39
@mpheath
Copy link
Collaborator Author

mpheath commented Feb 17, 2022

The run and shell entries can be in HKCU as previously done. This allows Sandman to keep it's Shell Integration tab settings.

This would make the change to only the 2 desktop icons to use the All Users desktop instead of the Current Users desktop.

In my opinion, the least confusing solution. The uninstaller will not be able to remove HKCU entries that have been created in other user accounts, so it becomes the users responsiblity to clean up in the Shell Integration tab settings before doing an uninstall.

The alternative is complex to manage for Sandman and the Installer/Uninstaller.

The "Run Un-Sandboxed" could be added to the installer with the task name AddRunSandboxed initially so no new task checkbox and could be given it's own task name later if desired. The custom messages could be copied from the Sandman xml files or do new translations. If another task checkbox is wanted, then custom messages will be needed like the messages that Sandman has.

Do this the easier way or try the complex way?

I am for the easier way 👍 . The alternative will be fugly.

@isaak654
Copy link
Collaborator

In my opinion, the least confusing solution. The uninstaller will not be able to remove HKCU entries that have been created in other user accounts, so it becomes the users responsiblity to clean up in the Shell Integration tab settings before doing an uninstall.

I would suggest at least a minimum cleanup script to be provided in the Plus installation folder that would prompt for Yes, No, Cancel input in order to avoid accidental clicks.

@mpheath
Copy link
Collaborator Author

mpheath commented Feb 17, 2022

I would suggest at least a minimum cleanup script to be provided in the Plus installation folder that would prompt for Yes, No, Cancel input in order to avoid accidental clicks.

I cannot comprehend what you suggest. Especially the "accidental clicks" part with what, where or why would that occur. You may need to describe in a way so that I or another can understand. The "cleanup script" is what? "Yes, No, Cancel" seems like a messagebox. Please explain better.

@isaak654
Copy link
Collaborator

A .cmd or .bat script into the Plus installation folder that would guide you into cleaning the shell integration entries.. a .reg file may still be fine, but only whether the duplicated entries are common for all cases (portable and non-portable users).

@DavidXanatos
Copy link
Member

hmm...

so here is what the classic sandboxie does:
It does not install any of these entries, this is done automatically by sbiectrl.exe when it is started for the first time by a new user.
All entries are installed in the user registry and desktop.
And yea the classic installer does not clean up other users so they are stuck with shell entries they can't remove.
So unfortunately there isn't much to learn from it :/

I see currently two ways forward:

Plan A:
We keep installing everything to the the user space, and add a clean up script, by sandman.exe to the user location where Sandboxie-Plus.ini is stored: "C:\Users[User]\AppData\Local\Sandboxie-Plus"
This is by far the easiest as its just adding to sandman the option to create a file and the ability to add shell integration on first start.
For that the installer would need to log into the uninstall key for example the preset what to add.
Or we get rid of all the check boxes and always add all, or may be even leave it entirely to sandman.exe
The script would as a last step remove the ...\Local\Sandboxie-Plus folder.

Plan B:
We install the shell extension for all users, sandman will get an option to elevate itself to admin when needed and add/remove the extension from the UI, all would be like now just with an UAC prompt in between.
And we install everything else to the user's own locations not using the registry so we add links to the users start menu StartUp folder and the user's Desktop folder, nothing more.
Also here the installer may record default presets for the first run of sandman in a new account.
This way the user can clean up the links manually, no regedit needed, if an other user would to uninstall sandboxie.

I think option B is more clean as we definitely avoid leaving any registry entries behind.
The down side is that we will leave a Sandboxie-Plus.ini behind.

What's your thoughts on the two options @isaak654 @mpheath ?

Cheers
David

@DavidXanatos
Copy link
Member

I have a Plan C:
Sandman.exe when starting for the first time under a new user would copy a small exe from its own location to "C:\Users[User]\AppData\Local\Sandboxie-Plus" the shell menu entries, in the user's registry, would be set up such that they invoke that exe instead of sandman directly which then starts sandman, if present.
If not, it shows a message box informing the user that sandboxie isn't installed offering to clean up, or to download an installer and re install.

@isaak654
Copy link
Collaborator

Plan B > Plan A without removing the checkboxes from anywhere > Plan C

@DavidXanatos
Copy link
Member

This feature request: #1836 will make a proper clean up problematic as these links would be set per user

Copy link
Collaborator

@isaak654 isaak654 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, the changes in v1.2.7 introduced some conflicts in this pull request.

Copy link
Collaborator

@isaak654 isaak654 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested changes to resolve the new v1.2.7 conflicts
#define MyAppName "Sandboxie-Plus"
#include "Languages.iss"

; Use commandline to populate:
; ISCC.exe /ORelease Sandboxie-Plus.iss /DMyAppVersion=%SbiePlusVer% /DMyAppArch=x64 /DMyAppSrc=SbiePlus64
;
;#define MyAppVersion "0.7.5"
;#define MyDrvVersion "5.49.8"
;#define MyAppArch "x64"
;#define MyAppSrc "SbiePlus64"


[Setup]
AppName={#MyAppName}
AppVerName={#MyAppName} v{#MyAppVersion}
AppId=Sandboxie-Plus
AppVersion={#MyAppVersion}
AppPublisher=http://xanasoft.com/
AppPublisherURL=http://sandboxie-plus.com/
AppMutex=SBIEPLUS_MUTEX
DefaultDirName={code:InstallPath}
DefaultGroupName={#MyAppName}
Uninstallable=not IsPortable
UninstallDisplayIcon={app}\SandMan.exe
OutputBaseFilename={#MyAppName}-{#MyAppArch}-v{#MyAppVersion}
Compression=lzma
ArchitecturesAllowed={#MyAppArch}
ArchitecturesInstallIn64BitMode=x64
AllowNoIcons=yes
AlwaysRestart=no
LicenseFile=.\license.txt
UsedUserAreasWarning=no
VersionInfoCopyright=Copyright (C) 2020-2022 by David Xanatos (xanasoft.com)
VersionInfoVersion={#MyAppVersion}

; Handled in code section as always want DirPage for portable mode.
DisableDirPage=no

; Allow /CURRENTUSER to be used with /PORTABLE=1 to avoid admin requirement.
PrivilegesRequiredOverridesAllowed=commandline


[Tasks]
Name: "DesktopIcon"; Description: "{cm:CreateDesktopIcon}"; MinVersion: 0.0,5.0; Check: not IsPortable
;Name: "DesktopIcon2"; Description: "{cm:AddSandboxedBrowser}"; MinVersion: 0.0,5.0; Check: not IsPortable
;Name: "AutoStartEntry"; Description: "{cm:AutoStartProgram,{#MyAppName}}"; MinVersion: 0.0,5.0; Check: not IsPortable
;Name: "AddRunSandboxed"; Description: "{cm:AddSandboxedMenu}"; MinVersion: 0.0,5.0; Check: not IsPortable


[Files]
; Both portable and install.
Source: ".\Release\{#MyAppSrc}\*"; DestDir: "{app}"; MinVersion: 0.0,5.0; Flags: recursesubdirs ignoreversion; Excludes: "*.pdb"
; include the driver pdb
Source: ".\Release\{#MyAppSrc}\SbieDrv.pdb"; DestDir: "{app}"; MinVersion: 0.0,5.0; Flags: ignoreversion

; Only if portable.
Source: ".\Sandboxie.ini"; DestDir: "{app}"; Flags: ignoreversion onlyifdoesntexist; Check: IsPortable
Source: ".\Sandboxie-Plus.ini"; DestDir: "{app}"; Flags: ignoreversion onlyifdoesntexist; Check: IsPortable


[Icons]
Name: "{group}\Sandboxie-Plus"; Filename: "{app}\SandMan.exe"; MinVersion: 0.0,5.0
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "http://sandboxie-plus.com/"; MinVersion: 0.0,5.0
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; MinVersion: 0.0,5.0
Name: "{group}\{cm:SandboxieStartMenu1}"; Filename: "{app}\Start.exe"; Parameters: "/box:__ask__ run_dialog"; MinVersion: 0.0,5.0
Name: "{group}\{cm:SandboxieStartMenu2}"; Filename: "{app}\Start.exe"; Parameters: "default_browser"; MinVersion: 0.0,5.0
Name: "{group}\{cm:SandboxieStartMenu3}"; Filename: "{app}\Start.exe"; Parameters: "/box:__ask__ start_menu"; MinVersion: 0.0,5.0
Name: "{autodesktop}\Sandboxie-Plus"; Filename: "{app}\SandMan.exe"; Tasks: DesktopIcon; MinVersion: 0.0,5.0
;Name: "{autodesktop}\{cm:SandboxedBrowser}"; Filename: "{app}\Start.exe"; Parameters: "default_browser"; Tasks: DesktopIcon2; MinVersion: 0.0,5.0


[INI]
; Set Sandman language.
Filename: "{localappdata}\{#MyAppName}\{#MyAppName}.ini"; Section: "Options"; Key: "UiLanguage"; String: "{code:SandmanLanguage|{language}}"; Check: not IsPortable
Filename: "{app}\{#MyAppName}.ini"; Section: "Options"; Key: "UiLanguage"; String: "{code:SandmanLanguage|{language}}"; Check: IsPortable


[InstallDelete]
; Remove deprecated files at install time.
Type: files; Name: "{app}\translations\sandman_zh-CN.qm"
Type: files; Name: "{app}\translations\sandman_zh-TW.qm"
Type: files; Name: "{app}\translations\sandman_pt.qm"
Type: files; Name: "{app}\translations\sandman_ua.qm"
Type: files; Name: "{app}\SbieDrv.sys.w10"
Type: files; Name: "{app}\SbieDrv.sys.rc4"
Type: files; Name: "{userdesktop}\Sandboxie-Plus.lnk"
Type: files; Name: "{userdesktop}\{cm:SandboxedBrowser}.lnk"


[Registry]
; Autostart Sandman.
;Root: HKLM; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueName: "SandboxiePlus_AutoRun"; ValueType: string; ValueData: """{app}\SandMan.exe"" -autorun"; Flags: uninsdeletevalue; Tasks: AutoStartEntry

; AddRunSandboxed all files.
;Root: HKLM; Subkey: "Software\Classes\*\shell"; Flags: uninsdeletekeyifempty; Tasks: AddRunSandboxed
;Root: HKLM; Subkey: "Software\Classes\*\shell\sandbox"; ValueName: ""; ValueType: string; ValueData: "{cm:RunSandboxedMenu}"; Flags: uninsdeletekey; Tasks: AddRunSandboxed
;Root: HKLM; Subkey: "Software\Classes\*\shell\sandbox"; ValueName: "Icon"; ValueType: string; ValueData: """{app}\start.exe"""; Tasks: AddRunSandboxed
;Root: HKLM; Subkey: "Software\Classes\*\shell\sandbox\command"; ValueName: ""; ValueType: string; ValueData: """{app}\SandMan.exe"" /box:__ask__ ""%1"" %*"; Tasks: AddRunSandboxed

; AddRunSandboxed folder.
;Root: HKLM; Subkey: "Software\Classes\Folder\shell"; Flags: uninsdeletekeyifempty; Tasks: AddRunSandboxed
;Root: HKLM; Subkey: "Software\Classes\Folder\shell\sandbox"; ValueName: ""; ValueType: string; ValueData: "{cm:RunSandboxedMenu}"; Flags: uninsdeletekey; Tasks: AddRunSandboxed
;Root: HKLM; Subkey: "Software\Classes\Folder\shell\sandbox"; ValueName: "Icon"; ValueType: string; ValueData: """{app}\start.exe"""; Tasks: AddRunSandboxed
;Root: HKLM; Subkey: "Software\Classes\Folder\shell\sandbox\command"; ValueName: ""; ValueType: string; ValueData: """{app}\SandMan.exe"" /box:__ask__ ""%1"" %*"; Tasks: AddRunSandboxed

; External manifest for Sbie service.
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Services\SbieSvc"; ValueName: "PreferExternalManifest"; ValueType: dword; ValueData: "1"; Check: not IsPortable

; Set language for Sbie service.
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Services\SbieSvc"; ValueType: dword; ValueName: "Language"; ValueData: "{code:SystemLanguage}"; Check: not IsPortable


[Run]
; Install the Sbie driver.
Filename: "{app}\KmdUtil.exe"; Parameters: "install SbieDrv ""{app}\SbieDrv.sys"" type=kernel start=demand msgfile=""{app}\SbieMsg.dll"" altitude=86900"; StatusMsg: "KmdUtil install SbieDrv..."; Check: not IsPortable

; Install the Sbie service.
Filename: "{app}\KmdUtil.exe"; Parameters: "install SbieSvc ""{app}\SbieSvc.exe"" type=own start=auto msgfile=""{app}\SbieMsg.dll"" display=""Sandboxie Service"" group=UIGroup"; StatusMsg: "KmdUtil install SbieSvc..."; Check: not IsPortable

; Start the Sbie service.
Filename: "{app}\KmdUtil.exe"; Parameters: "start SbieSvc"; StatusMsg: "KmdUtil start SbieSvc"; Check: not IsPortable

; Start the Sandman UI.
Filename: "{app}\SandMan.exe"; StatusMsg: "Launch SandMan UI..."; Flags: postinstall nowait; Check: (not IsPortable) and (not WizardSilent)
;Filename: "{app}\SandMan.exe"; Parameters: "-autorun"; StatusMsg: "Launch SandMan UI..."; Flags: runasoriginaluser nowait; Check: not IsPortable


[UninstallDelete]
Type: dirifempty; Name: "{app}"
Type: dirifempty; Name: "{localappdata}\{#MyAppName}"


[Messages]
; Include with commandline /? message.
HelpTextNote=/PORTABLE=1%nEnable portable mode.%n


[Code]
var
  CustomPage: TInputOptionWizardPage;
  IsInstalled: Boolean;
  Portable: Boolean;


function IsPortable(): Boolean;
begin

  // Return True or False for the value of Check.
  if (ExpandConstant('{param:portable|0}') = '1') or Portable then begin
    Result := True;
  end;
end;


function IsUpgrade(): Boolean;
var
  S: String;
  InnoSetupReg: String;
  AppPathName: String;
begin

  // Detect if already installed.
  // Source: https://stackoverflow.com/a/30568071
  InnoSetupReg := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppName")}_is1');
  AppPathName := 'Inno Setup: App Path';

  Result := RegQueryStringValue(HKLM, InnoSetupReg, AppPathName, S) or
            RegQueryStringValue(HKCU, InnoSetupReg, AppPathName, S);
end;


function InstallPath(Dummy: String): String;
var
  DrvPath: String;
  SbiePath: String;
begin

  // Return the path to use for the value of DefaultDirName.
  IsInstalled := False;
  SbiePath := ExpandConstant('{param:dir}');

  if SbiePath = '' then begin
    if (ExpandConstant('{param:portable|0}') = '1') or Portable then begin
      SbiePath := ExpandConstant('{src}') + '\{#MyAppName}';
    end else begin
      if RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Services\SbieDrv', 'ImagePath', DrvPath) then begin
        IsInstalled := True;
        DrvPath := ExtractFilePath(DrvPath);

        if Copy(DrvPath, 1, 4) = '\??\' then begin
          DrvPath := Copy(DrvPath, 5, Length(DrvPath) - 5);
        end;

        SbiePath := DrvPath;
      end else begin
        SbiePath := ExpandConstant('{autopf}') + '\{#MyAppName}';
      end;
    end;
  end;

  Result := SbiePath;
end;


function SandmanLanguage(Language: String): String;
begin

  // Language values for Sandboxie-Plus.ini.
  case Lowercase(Language) of
    'english': Result := 'en';
    'chinesesimplified': Result := 'zh_CN';
    'chinesetraditional': Result := 'zh_TW';
    'dutch': Result := 'nl';
    'french': Result := 'fr';
    'german': Result := 'de';
    'italian': Result := 'it';
    'korean': Result := 'ko';
    'polish': Result := 'pl';
    'brazilianportuguese': Result := 'pt_BR';
    'portuguese': Result := 'pt_PT';
    'russian': Result := 'ru';
    'spanish': Result := 'es';
    'swedish': Result := 'sv_SE';
    'turkish': Result := 'tr';
    'ukrainian': Result := 'uk';
  end;
end;


function SystemLanguage(Dummy: String): String;
begin

  // Language identifier for the System Eventlog messages.
  Result := IntToStr(GetUILanguage());
end;


procedure UpdateStatus(OutputProgressPage: TOutputProgressWizardPage; Text: String; Percentage: Integer);
begin

  // Called by ShutdownSbie() to update status or progress.
  if IsUninstaller() then
    UninstallProgressForm.StatusLabel.Caption := Text
  else begin
    OutputProgressPage.SetProgress(Percentage, 100);
    OutputProgressPage.SetText(Text, '');
  end;

  // Output status information to log.
  Log('Debug: ' + Text);
end;


function ShutdownSbie(): Boolean;
var
  ExecRet: Integer;
  StatusText: String;
  OutputProgressPage: TOutputProgressWizardPage;
begin

  // Require KmdUtil.exe to continue.
  if (FileExists(ExpandConstant('{app}\KmdUtil.exe')) = False) then
  begin
    Result := True;
    exit;
  end;

  try

    // Backup status text (uninstall). Prepare progress page (install).
    if IsUninstaller() then
      StatusText := UninstallProgressForm.StatusLabel.Caption
    else begin
      OutputProgressPage := CreateOutputProgressPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc));
      OutputProgressPage.Show();
    end;

    // Run KmdUtil scandll.
    UpdateStatus(OutputProgressPage, 'KmdUtil scandll', 5);
    Exec(ExpandConstant('{app}\KmdUtil.exe'), 'scandll_silent', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);

    if (ExecRet <> 0) then
    begin
      Result := False;
      exit;
    end;

    // Stop processes.
    UpdateStatus(OutputProgressPage, 'Taskkill /IM Sandman.exe /IM SbieCtrl.exe /IM Start.exe /F', 30);
    Exec(ExpandConstant('{sys}\taskkill.exe'), '/IM Sandman.exe /IM SbieCtrl.exe /IM Start.exe /F', '', SW_HIDE, ewWaitUntilTerminated, ExecRet);

    // Stop service and driver.
    UpdateStatus(OutputProgressPage, 'KmdUtil stop SbieSvc', 55);
    Exec(ExpandConstant('{app}\KmdUtil.exe'), 'stop SbieSvc', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);

    UpdateStatus(OutputProgressPage, 'KmdUtil stop SbieDrv', 85);
    Exec(ExpandConstant('{app}\KmdUtil.exe'), 'stop SbieDrv', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);

    // Uninstall service and driver.
    UpdateStatus(OutputProgressPage, 'KmdUtil delete SbieSvc', 95);
    Exec(ExpandConstant('{app}\KmdUtil.exe'), 'delete SbieSvc', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);

    UpdateStatus(OutputProgressPage, 'KmdUtil delete SbieDrv', 100);
    Exec(ExpandConstant('{app}\KmdUtil.exe'), 'delete SbieDrv', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);

    // Query driver which can remove SbieDrv key if exist.
    if RegKeyExists(HKLM, 'SYSTEM\CurrentControlSet\services\SbieDrv') then begin
      UpdateStatus(OutputProgressPage, 'SC query SbieDrv', 100);
      Exec(ExpandConstant('{sys}\sc.exe'), 'query SbieDrv', '', SW_HIDE, ewWaitUntilTerminated, ExecRet);
    end;
  finally

    // Restore status text (uninstall). Hide Prepare progress page (install).
    if IsUninstaller() then
      UninstallProgressForm.StatusLabel.Caption := StatusText
    else begin
      OutputProgressPage.SetProgress(0, 100);
      OutputProgressPage.Hide();
    end;
  end;

  Result := True;
end;


//////////////////////////////////////////////////////
// Installation Events
//


function NextButtonClick(CurPageID: Integer): Boolean;
begin

  // Get mode setting from Custom page and set path for the Dir page.
  if CurPageID = CustomPage.ID then begin
    Portable := not (CustomPage.SelectedValueIndex = 0);
    WizardForm.DirEdit.Text := InstallPath('');

    // No Start Menu folder setting on Ready page if portable.
    if Portable then begin
      WizardForm.NoIconsCheck.Checked := True;
    end else begin
      WizardForm.NoIconsCheck.Checked := False;
    end;
  end;

  // Shutdown service, driver and processes as ready to install.
  if ((CurPageID = wpReady) and (not IsPortable())) then
  begin
    Result := ShutdownSbie();
    exit;
  end;

  Result := True;
end;


function ShouldSkipPage(PageID: Integer): Boolean;
begin

  // Skip Custom page and Group page if portable.
  if PageID = CustomPage.ID then begin
    if ExpandConstant('{param:portable|0}') = '1' then
      Result := True;
  end else if PageID = wpSelectDir then begin
    if not IsPortable and IsUpgrade then
      Result := True;
  end else if PageID = wpSelectProgramGroup then begin
    if IsPortable then
      Result := True;
  end;
end;


procedure InitializeWizard();
begin

  // Create the custom page.
  // Source: https://timesheetsandstuff.wordpress.com/2008/06/27/the-joy-of-part-2/
  CustomPage := CreateInputOptionPage(wpLicense,
                                      CustomMessage('CustomPageLabel1'),
                                      CustomMessage('CustomPageLabel2'),
                                      CustomMessage('CustomPageLabel3'), True, False);

  if IsInstalled = True then begin
    CustomPage.Add(CustomMessage('CustomPageUpgradeMode'));
  end else begin
    CustomPage.Add(CustomMessage('CustomPageInstallMode'));
  end;

  CustomPage.Add(CustomMessage('CustomPagePortableMode'));

  // Default to Normal Installation if not argument /PORTABLE=1.
  if ExpandConstant('{param:portable|0}') = '1' then begin
    WizardForm.NoIconsCheck.Checked := True;
    CustomPage.SelectedValueIndex := 1;
  end else begin
    CustomPage.SelectedValueIndex := 0;
  end;
end;


function InitializeSetup(): Boolean;
var
  Version: TWindowsVersion;
  ExecRet: Integer;
  UninstallString: String;
begin

  // Require Windows 7 or later.
  GetWindowsVersionEx(Version);

  if (Version.NTPlatform = False) or (Version.Major < 6) then
  begin
    SuppressibleMsgBox(CustomMessage('RequiresWin7OrLater'), mbError, MB_OK, MB_OK);
    Result := False;
    exit;
  end;

  // Ask to uninstall Sandboxie Classic if found.
  ExecRet := IDYES;

  while (ExecRet = IDYES) do
  begin
      if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sandboxie', 'UninstallString', UninstallString) then begin

        ExecRet := MsgBox(CustomMessage('ClassicFound'), mbConfirmation, MB_YESNOCANCEL);

        if ExecRet = IDCANCEL then
        begin
          Result := False;
          exit;
        end;

        if ExecRet = IDYES then
        begin
          Exec('cmd.exe', '/c ' + UninstallString, '', SW_HIDE, ewWaitUntilTerminated, ExecRet);
          ExecRet := IDYES;
        end;

      end else begin
        break;
      end;
  end;

  Result := True;
end;


//////////////////////////////////////////////////////
// Uninstallation Exclusive
//


procedure UninstallCleanup(ButtonCount: Integer);
var
  Buttons: Cardinal;
  ButtonLabels: TArrayOfString;
  ExecRet: Integer;
  I: Integer;
  Paths: TStringList;
  ShowMsgbox: Boolean;
  TaskRet: Integer;
begin

  // Require 2 or 3 for button count.
  if (ButtonCount < 2) or (ButtonCount > 3) then
    exit;

  // Require Sandman.exe to continue.
  //if not FileExists(ExpandConstant('{app}\Sandman.exe')) then
  //  exit;

  // Make a list.
  Paths := TStringList.Create;

  // Append file paths to the list for removal.
  Paths.Append('{localappdata}\{#MyAppName}\{#MyAppName}.ini');
  Paths.Append('{win}\Sandboxie.ini');
  Paths.Append('{app}\{#MyAppName}.ini');
  Paths.Append('{app}\Sandboxie.ini');

  // Expand paths and detect if any file exist.
  for I := 0 to Paths.Count - 1 do begin
    Paths[I] := ExpandConstant(Paths[I]);

    if FileExists(Paths[I]) then
      ShowMsgbox := True;
  end;

  // Delete the config files and the sandboxes.
  if ShowMsgbox then begin
    case ButtonCount of
      2: begin
        Buttons := MB_YESNO;
        ButtonLabels := [CustomMessage('UninstallTaskLabel3'),
                         CustomMessage('UninstallTaskLabel4')];
      end;

      3: begin
        Buttons := MB_ABORTRETRYIGNORE;
        ButtonLabels := [CustomMessage('UninstallTaskLabel3'),
                         CustomMessage('UninstallTaskLabel4'),
                         CustomMessage('UninstallTaskLabel5')];
      end;
    end;

    case TaskDialogMsgBox(CustomMessage('UninstallTaskLabel1'),
                          CustomMessage('UninstallTaskLabel2'),
                          mbConfirmation, Buttons, ButtonLabels, 0) of

      IDRETRY: TaskRet := 1;
      IDIGNORE: TaskRet := 2;
      IDABORT: TaskRet := 3;
      IDYES: TaskRet := 1;
      IDNO: TaskRet := 2;
    end;

    if TaskRet > 2 then begin
      Log('Debug: Start terminate_all');
      Exec(ExpandConstant('{app}\start.exe'), 'terminate_all', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);
    end;

    if TaskRet > 2 then begin
      Log('Debug: Start delete_all_sandboxes');
      Exec(ExpandConstant('{app}\start.exe'), 'delete_all_sandboxes', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);
    end;

    if TaskRet > 1 then begin
      for I := 0 to Paths.Count - 1 do
        if FileExists(Paths[I]) then begin
          Log('Debug: DeleteFile(' + Paths[I] + ')');
          DeleteFile(Paths[I]);
        end;
    end;
  end;

  // Release the list.
  Paths.Free;
end;

procedure ShellUninstall();
var
  ExecRet: Integer;
begin

  if FileExists(ExpandConstant('{app}\Sandman.exe')) then begin
    Log('Debug: SandMan /ShellUninstall');
    Exec(ExpandConstant('{app}\Sandman.exe'), '/ShellUninstall', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);
  end else begin
    Log('Debug: SbieCtrl /uninstall');
    Exec(ExpandConstant('{app}\sbiectrl.exe'), '/uninstall', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ExecRet);
  end;
end;


//////////////////////////////////////////////////////
// Uninstallation Events
//


procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin

  // Before the uninstallation.
  if (CurUninstallStep <> usUninstall) then
    exit;

  // User to confirm extra files to remove.
  if not UninstallSilent then
    UninstallCleanup(3);

  // Shutdown service, driver and processes.
  if (ShutdownSbie() = False) then
  begin
    Abort();
    exit;
  end;

  // remove shell integration.
  ShellUninstall();

end;

@isaak654
Copy link
Collaborator

isaak654 commented Oct 9, 2022

Status update

All_users_PR

For those unfamiliar with the start menu integration feature:
image
image

@isaak654 isaak654 added Stalled work Progress stopped due to uncertainty and removed High priority To be done as soon as possible labels Oct 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Stalled work Progress stopped due to uncertainty
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Install as non admin - SB was running and available until restart then not in task tray.
3 participants