فهرست منبع

Added new [Setup] section directive: UsePreviousPrivileges

Martijn Laan 6 سال پیش
والد
کامیت
db70dd62bf
9فایلهای تغییر یافته به همراه144 افزوده شده و 63 حذف شده
  1. 1 0
      Components/ScintStylerInnoSetup.pas
  2. 15 0
      ISHelp/isetup.xml
  3. 1 0
      Projects/CompMsgs.pas
  4. 11 1
      Projects/Compile.pas
  5. 1 0
      Projects/Install.pas
  6. 110 58
      Projects/Main.pas
  7. 1 1
      Projects/Struct.pas
  8. 1 1
      setup.iss
  9. 3 2
      whatsnew.htm

+ 1 - 0
Components/ScintStylerInnoSetup.pas

@@ -235,6 +235,7 @@ type
     ssUsePreviousAppDir,
     ssUsePreviousGroup,
     ssUsePreviousLanguage,
+    ssUsePreviousPrivileges,
     ssUsePreviousSetupType,
     ssUsePreviousTasks,
     ssUsePreviousUserInfo,

+ 15 - 0
ISHelp/isetup.xml

@@ -1079,6 +1079,7 @@ DefaultGroupName=My Program
 <li><link topic="setup_usepreviousappdir">UsePreviousAppDir</link></li>
 <li><link topic="setup_usepreviousgroup">UsePreviousGroup</link></li>
 <li><link topic="setup_usepreviouslanguage">UsePreviousLanguage</link></li>
+<li><link topic="setup_usepreviousprivileges">UsePreviousPrivigeles</link></li>
 <li><link topic="setup_useprevioussetuptype">UsePreviousSetupType</link></li>
 <li><link topic="setup_useprevioustasks">UsePreviousTasks</link></li>
 <li><link topic="setup_useprevioususerinfo">UsePreviousUserInfo</link></li>
@@ -3965,6 +3966,8 @@ Name: portablemode; Description: "Portable Mode"</pre></example>
 <p>Can be set to one or more overrides which allow the end user to override the script's default <link topic="setup_privilegesrequired">PrivilegesRequired</link> setting.</p>
 <p>If override <tt>commandline</tt> is allowed then Setup will support two additional command line parameters to override the script's default <link topic="setup_privilegesrequired">PrivilegesRequired</link> setting: /ALLUSERS and /CURRENTUSER. See <link topic="setupcmdline" anchor="ALLUSERS">Setup Command Line Parameters</link> for more details.</p>
 <p>If override <tt>dialog</tt> is allowed then Setup will ask the user to choose the install mode based on the script's default <link topic="setup_privilegesrequired">PrivilegesRequired</link> setting using a suppressible dialog. Allowing <tt>dialog</tt> automatically allows <tt>commandline</tt> and when one of the command line parameters is used then Setup will not ask the user.</p>
+<p><b>See also:</b><br/>
+<link topic="setup_usepreviousprivileges">UsePreviousPrivileges</link></p>
 </body>
 </setuptopic>
 
@@ -4557,6 +4560,18 @@ DiskSliceSize=1457664
 </body>
 </setuptopic>
 
+<setuptopic directive="UsePreviousPrivileges">
+<setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
+<setupdefault><tt>yes</tt></setupdefault>
+<body>
+<p>When this directive is <tt>yes</tt>, the default, at startup Setup will look in the registry to see if the <link topic="sameappnotes">same application</link> is already installed in one of the two install modes, and if so, it will use that install mode and not ask the user.</p>
+<p>If <tt>PrivilegesRequiredOverridesAllowed</tt> does not allow <tt>dialog</tt>, this directive is effectively ignored.</p>
+<p><tt>UsePreviousPrivileges</tt> must be set to <tt>no</tt> when <tt>AppId</tt> includes constants and <tt>PrivilegesRequiredOverridesAllowed</tt> allows <tt>dialog</tt>.</p>
+<p><b>See also:</b><br/>
+<link topic="setup_privilegesrequiredoverridesallowed">PrivilegesRequiredOverridesAllowed</link></p>
+</body>
+</setuptopic>
+
 <setuptopic directive="UsePreviousSetupType">
 <setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
 <setupdefault><tt>yes</tt></setupdefault>

+ 1 - 0
Projects/CompMsgs.pas

@@ -187,6 +187,7 @@ const
   SCompilerDirectiveRequiresWindows2000 = 'The [%s] section directive "%s" may not be used when compiling on Windows 95/98/Me/NT4';
   SCompilerMustUseDisableStartupPrompt = 'DisableStartupPrompt must be set to "yes" when AppName includes constants';
   SCompilerMustNotUsePreviousLanguage = 'UsePreviousLanguage must be set to "no" when AppId includes constants';
+  SCompilerMustNotUsePreviousPrivileges = 'UsePreviousPrivileges must be set to "no" when AppId includes constants and PrivilegesRequiredOverridesAllowed allows "dialog"';
   SCompilerDirectiveNotUsingDefault = 'The [Setup] section directive "%s" is not assuming a default value because %s includes constants.';
   SCompilerDirectiveNotUsingPreferredDefault = 'The [Setup] section directive "%s" is defaulting to %s because %s includes constants.';
   SCompilerDirectivePatternTooLong = 'The [Setup] section directive "%s" contains a pattern that is too long';

+ 11 - 1
Projects/Compile.pas

@@ -182,6 +182,7 @@ type
     ssUsePreviousAppDir,
     ssUsePreviousGroup,
     ssUsePreviousLanguage,
+    ssUsePreviousPrivileges,
     ssUsePreviousSetupType,
     ssUsePreviousTasks,
     ssUsePreviousUserInfo,
@@ -4340,6 +4341,9 @@ begin
     ssUsePreviousLanguage: begin
         SetSetupHeaderOption(shUsePreviousLanguage);
       end;
+    ssUsePreviousPrivileges: begin
+        SetSetupHeaderOption(shUsePreviousPrivileges);
+      end;
     ssUsePreviousSetupType: begin
         SetSetupHeaderOption(shUsePreviousSetupType);
       end;
@@ -8598,7 +8602,8 @@ begin
       shAllowUNCPath, shUsePreviousUserInfo, shRestartIfNeededByRun,
       shAllowCancelDuringInstall, shWizardImageStretch, shAppendDefaultDirName,
       shAppendDefaultGroupName, shUsePreviousLanguage, shCloseApplications,
-      shRestartApplications, shAllowNetworkDrive, shDisableWelcomePage];
+      shRestartApplications, shAllowNetworkDrive, shDisableWelcomePage,
+      shUsePreviousPrivileges];
     SetupHeader.PrivilegesRequired := prAdmin;
     SetupHeader.UninstallFilesDir := '{app}';
     SetupHeader.DefaultUserInfoName := '{sysuserinfoname}';
@@ -8650,6 +8655,11 @@ begin
       LineNumber := SetupDirectiveLines[ssUsePreviousLanguage];
       AbortCompile(SCompilerMustNotUsePreviousLanguage);
     end;
+    if AppIdHasConsts and (proDialog in SetupHeader.PrivilegesRequiredOverridesAllowed) and (shUsePreviousPrivileges in SetupHeader.Options) then begin
+      { AppId has contants so UsePreviousPrivileges must not be used }
+      LineNumber := SetupDirectiveLines[ssUsePreviousPrivileges];
+      AbortCompile(SCompilerMustNotUsePreviousPrivileges);
+    end;
     LineNumber := SetupDirectiveLines[ssAppVerName];
     CheckConst(SetupHeader.AppVerName, SetupHeader.MinVersion, []);
     LineNumber := SetupDirectiveLines[ssAppComments];

+ 1 - 0
Projects/Install.pas

@@ -512,6 +512,7 @@ var
       Result := I = 0;
     end;
 
+    { Also see Main.pas }
     function ExistingInstallationAt(const RegView: TRegView; const RootKey: HKEY): Boolean;
     var
       K: HKEY;

+ 110 - 58
Projects/Main.pas

@@ -209,6 +209,7 @@ function GetUninstallRegSubkeyName(const UninstallRegKeyBaseName: String): Strin
 function GetPreviousData(const ExpandedAppID, ValueName, DefaultValueData: String): String;
 procedure InitializeAdminInstallMode(const AAdminInstallMode: Boolean);
 procedure Initialize64BitInstallMode(const A64BitInstallMode: Boolean);
+procedure Log64BitInstallMode;
 procedure InitializeCommonVars;
 procedure InitializeSetup;
 procedure InitMainNonSHFolderConsts;
@@ -2502,7 +2503,6 @@ end;
 procedure Initialize64BitInstallMode(const A64BitInstallMode: Boolean);
 { Initializes Is64BitInstallMode and other global variables that depend on it }
 begin
-  LogFmt('64-bit install mode: %s', [SYesNo[A64BitInstallMode]]);
   Is64BitInstallMode := A64BitInstallMode;
   InstallDefaultDisableFsRedir := A64BitInstallMode;
   ScriptFuncDisableFsRedir := A64BitInstallMode;
@@ -2512,6 +2512,11 @@ begin
     InstallDefaultRegView := rv32Bit;
 end;
 
+procedure Log64BitInstallMode;
+begin
+  LogFmt('64-bit install mode: %s', [SYesNo[Is64BitInstallMode]]);
+end;
+
 procedure InitializeSetup;
 { Initializes various vars used by the setup. This is called in the project
   source. }
@@ -2775,6 +2780,94 @@ var
       end;
     end;
   end;
+  
+  { Also see Install.pas }
+  function ExistingInstallationAt(const RootKey: HKEY; const SubkeyName: String): Boolean;
+  var
+    K: HKEY;
+  begin
+    if RegOpenKeyExView(InstallDefaultRegView, RootKey, PChar(SubkeyName), 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
+      Result := True;
+      RegCloseKey(K);
+    end else
+      Result := False;
+  end;
+
+  procedure HandlePrivilegesRequiredOverrides(var ExtraRespawnParam: String);
+  var
+    ExistingAtAdminInstallMode, ExistingAtNonAdminInstallMode, DesireAnInstallMode, DesireAdminInstallMode: Boolean;
+    SubkeyName, AppName: String;
+  begin
+    if HasInitPrivilegesRequired and (proCommandLine in SetupHeader.PrivilegesRequiredOverridesAllowed) then begin
+      SetupHeader.PrivilegesRequired := InitPrivilegesRequired;
+      { We don't need to set ExtraRespawnParam since the existing command line
+        already contains the needed parameters and it will automatically be
+        passed on to any respawned Setup(Ldr). }
+    end else if proDialog in SetupHeader.PrivilegesRequiredOverridesAllowed then begin
+      if shUsePreviousPrivileges in SetupHeader.Options then begin
+        { Note: if proDialog is used and UsePreviousPrivileges is set to "yes"
+          then the compiler does not allow AppId to include constants so we can
+          safely use it here without having to call ExpandConstant first. }
+        SubkeyName := GetUninstallRegSubkeyName(GetUninstallRegKeyBaseName(SetupHeader.AppID));
+        ExistingAtAdminInstallMode := ExistingInstallationAt(HKEY_LOCAL_MACHINE, SubkeyName);
+        ExistingAtNonAdminInstallMode := ExistingInstallationAt(HKEY_CURRENT_USER, SubkeyName);
+      end else begin
+        ExistingAtAdminInstallMode := False;
+        ExistingAtNonAdminInstallMode := False;
+      end;
+
+      DesireAnInstallMode := True;
+      DesireAdminInstallMode := False; { Silence compiler }
+
+      if ExistingAtAdminInstallMode and not ExistingAtNonAdminInstallMode then
+        DesireAdminInstallMode := True
+      else if not ExistingAtAdminInstallMode and ExistingAtNonAdminInstallMode then
+        DesireAdminInstallMode := False
+      else if not InitSuppressMsgBoxes then begin
+        { Ask user. Doesn't log since logging hasn't started yet. Also doesn't
+          use ExpandedAppName since it isn't set yet. Afterwards we need to tell
+          any respawned Setup(Ldr) about the user choice (and avoid asking again).
+          Will use the command line parameter for this. Allowing proDialog forces
+          allowing proCommandLine, so we can count on the parameter to work. }
+        if shAppNameHasConsts in SetupHeader.Options then
+          AppName := SetupMessages[msgPrivilegesRequiredOverrideThisProgram]
+        else
+          AppName := SetupHeader.AppName;
+        if SetupHeader.PrivilegesRequired = prLowest then begin
+          case TaskDialogMsgBox('MAINICON', SetupMessages[msgPrivilegesRequiredOverrideInstruction],
+                 FmtSetupMessage(msgPrivilegesRequiredOverrideTaskDialogText2, [AppName]),
+                 FmtSetupMessage(msgPrivilegesRequiredOverrideMsgBoxText2, [AppName]),
+                 SetupMessages[msgSetupAppTitle], mbInformation, MB_YESNOCANCEL,
+                 [FmtSetupMessage(msgPrivilegesRequiredOverrideRecommended, [SetupMessages[msgPrivilegesRequiredOverrideCurrentUser]]), SetupMessages[msgPrivilegesRequiredOverrideAllUsers]], IDNO, False) of
+            IDYES: DesireAdminInstallMode := False;
+            IDNO: DesireAdminInstallMode := True;
+            IDCANCEL: Abort;
+            end;
+        end else begin
+          case TaskDialogMsgBox('MAINICON', SetupMessages[msgPrivilegesRequiredOverrideInstruction],
+                 FmtSetupMessage(msgPrivilegesRequiredOverrideTaskDialogText1, [AppName]),
+                 FmtSetupMessage(msgPrivilegesRequiredOverrideMsgBoxText1, [AppName]),
+                 SetupMessages[msgSetupAppTitle], mbInformation, MB_YESNOCANCEL,
+                 [FmtSetupMessage(msgPrivilegesRequiredOverrideRecommended, [SetupMessages[msgPrivilegesRequiredOverrideAllUsers]]), SetupMessages[msgPrivilegesRequiredOverrideCurrentUser]], IDYES, False) of
+            IDYES: DesireAdminInstallMode := True;
+            IDNO: DesireAdminInstallMode := False;
+            IDCANCEL: Abort;
+          end;
+        end;
+      end else
+        DesireAnInstallMode := False; { No previous found and msgboxes are suppressed, just keep things as they are. }
+
+      if DesireAnInstallMode then begin
+        if DesireAdminInstallMode then begin
+          SetupHeader.PrivilegesRequired := prAdmin;
+          ExtraRespawnParam := '/ALLUSERS';
+        end else begin
+          SetupHeader.PrivilegesRequired := prLowest;
+          ExtraRespawnParam := '/CURRENTUSER';
+        end;
+      end;
+    end;
+  end;
 
 var
   ParamName, ParamValue: String;
@@ -2791,7 +2884,7 @@ var
   LastShownComponentEntry, ComponentEntry: PSetupComponentEntry;
   MinimumTypeSpace: Integer64;
   SourceWildcard: String;
-  ExpandedSetupMutex, AppName, ExtraRespawnParam, RespawnParams: String;
+  ExpandedSetupMutex, ExtraRespawnParam, RespawnParams: String;
 begin
   InitializeCommonVars;
 
@@ -2986,51 +3079,21 @@ begin
 
         ActivateDefaultLanguage;
         
-        { Apply InitPrivilegesRequired }
-        if HasInitPrivilegesRequired and (proCommandLine in SetupHeader.PrivilegesRequiredOverridesAllowed) then
-          SetupHeader.PrivilegesRequired := InitPrivilegesRequired
-        else if not InitSuppressMsgBoxes and (proDialog in SetupHeader.PrivilegesRequiredOverridesAllowed) then begin
-          { Ask user. Doesn't log since logging hasn't started yet. Also doesn't use ExpandedAppName since it isn't set yet.
-            Afterwards we need to tell the respawned Setup about the user choice (and avoid it asking agin). Will use the
-            command line parameter for this. Allowing proDialog forces allowing proCommandLine, so we can count on the parameter to work. }
-          if shAppNameHasConsts in SetupHeader.Options then
-            AppName := SetupMessages[msgPrivilegesRequiredOverrideThisProgram]
-          else
-            AppName := SetupHeader.AppName;          
-          if SetupHeader.PrivilegesRequired = prLowest then begin
-            case TaskDialogMsgBox('MAINICON', SetupMessages[msgPrivilegesRequiredOverrideInstruction],
-                   FmtSetupMessage(msgPrivilegesRequiredOverrideTaskDialogText2, [AppName]),
-                   FmtSetupMessage(msgPrivilegesRequiredOverrideMsgBoxText2, [AppName]),
-                   SetupMessages[msgSetupAppTitle], mbInformation, MB_YESNOCANCEL,
-                   [FmtSetupMessage(msgPrivilegesRequiredOverrideRecommended, [SetupMessages[msgPrivilegesRequiredOverrideCurrentUser]]), SetupMessages[msgPrivilegesRequiredOverrideAllUsers]], IDNO, False) of
-              IDYES:
-                ExtraRespawnParam := '/CURRENTUSER';
-              IDNO:
-                begin
-                  SetupHeader.PrivilegesRequired := prAdmin;
-                  ExtraRespawnParam := '/ALLUSERS';
-                end;
-              IDCANCEL:
-                Abort;
-              end;
-          end else begin
-            case TaskDialogMsgBox('MAINICON', SetupMessages[msgPrivilegesRequiredOverrideInstruction],
-                   FmtSetupMessage(msgPrivilegesRequiredOverrideTaskDialogText1, [AppName]),
-                   FmtSetupMessage(msgPrivilegesRequiredOverrideMsgBoxText1, [AppName]),
-                   SetupMessages[msgSetupAppTitle], mbInformation, MB_YESNOCANCEL,
-                   [FmtSetupMessage(msgPrivilegesRequiredOverrideRecommended, [SetupMessages[msgPrivilegesRequiredOverrideAllUsers]]), SetupMessages[msgPrivilegesRequiredOverrideCurrentUser]], IDYES, False) of
-              IDYES:
-                ExtraRespawnParam := '/ALLUSERS';
-              IDNO:
-                begin
-                  SetupHeader.PrivilegesRequired := prLowest;
-                  ExtraRespawnParam := '/CURRENTUSER';
-                end;
-              IDCANCEL:
-                Abort;
-            end;
+        { Set Is64BitInstallMode if we're on Win64 and the processor architecture is
+          one on which a "64-bit mode" install should be performed. Doing this early
+          so that UsePreviousPrivileges knows where to look. Will log later. }
+        if ProcessorArchitecture in SetupHeader.ArchitecturesInstallIn64BitMode then begin
+          if not IsWin64 then begin
+            { A 64-bit processor was detected and 64-bit install mode was requested,
+              but IsWin64 is False, indicating required WOW64 APIs are not present }
+            AbortInitFmt1(msgMissingWOW64APIs, '1');
           end;
-        end;
+          Initialize64BitInstallMode(True);
+        end
+        else
+          Initialize64BitInstallMode(False);
+          
+        HandlePrivilegesRequiredOverrides(ExtraRespawnParam);
 
         { Start a new, elevated Setup(Ldr) process if needed }
         if not IsRespawnedProcess and
@@ -3160,18 +3223,7 @@ begin
   
   InitializeAdminInstallMode(IsAdmin and (SetupHeader.PrivilegesRequired <> prLowest));
 
-  { Set Is64BitInstallMode if we're on Win64 and the processor architecture is
-    one on which a "64-bit mode" install should be performed }
-  if ProcessorArchitecture in SetupHeader.ArchitecturesInstallIn64BitMode then begin
-    if not IsWin64 then begin
-      { A 64-bit processor was detected and 64-bit install mode was requested,
-        but IsWin64 is False, indicating required WOW64 APIs are not present }
-      AbortInitFmt1(msgMissingWOW64APIs, '1');
-    end;
-    Initialize64BitInstallMode(True);
-  end
-  else
-    Initialize64BitInstallMode(False);
+  Log64BitInstallMode;
 
   { Show "Select Language" dialog if necessary - requires "64-bit mode" to be
     initialized else it might query the previous language from the wrong registry

+ 1 - 1
Projects/Struct.pas

@@ -65,7 +65,7 @@ type
     {$IFNDEF UNICODE}shShowUndisplayableLanguages, {$ENDIF}shSetupLogging,
     shSignedUninstaller, shUsePreviousLanguage, shDisableWelcomePage,
     shCloseApplications, shRestartApplications, shAllowNetworkDrive,
-    shForceCloseApplications, shAppNameHasConsts);
+    shForceCloseApplications, shAppNameHasConsts, shUsePreviousPrivileges);
   TSetupLanguageDetectionMethod = (ldUILanguage, ldLocale, ldNone);
   TSetupCompressMethod = (cmStored, cmZip, cmBzip, cmLZMA, cmLZMA2);
   TSetupSalt = array[0..7] of Byte;

+ 1 - 1
setup.iss

@@ -18,7 +18,7 @@ AppMutex=InnoSetupCompilerAppMutex,Global\InnoSetupCompilerAppMutex
 SetupMutex=InnoSetupCompilerSetupMutex,Global\InnoSetupCompilerSetupMutex
 DefaultDirName={autopf}\Inno Setup 6
 DefaultGroupName=Inno Setup 6
-PrivilegesRequiredOverridesAllowed=commandline
+PrivilegesRequiredOverridesAllowed=dialog
 AllowNoIcons=yes
 Compression=lzma2/max
 SolidCompression=yes

+ 3 - 2
whatsnew.htm

@@ -52,14 +52,15 @@ For conditions of distribution and use, see <a href="http://www.jrsoftware.org/f
   <li>Pascal Scripting changes: Added new <tt>IsAdminInstallMode</tt> support function.</li>
 </ul>
 <p><span class="head2">Overridable install mode</span></p>
-<p>Once your script is fully updated to support both administrative and non administrative mode (for example by using the new &quot;auto&quot; constants and the new [Registry] section <tt>Root</tt> value <tt>HKA</tt>) you can then use the following:</p>
+<p>Once your script is fully updated to support both administrative and non administrative install mode (for example by using the new &quot;auto&quot; constants and the new [Registry] section <tt>Root</tt> value <tt>HKA</tt>) you can then use the following:</p>
 <ul>
   <li>Added new [Setup] section directive: <tt>PrivilegesRequiredOverridesAllowed</tt>, which can be set to one or more overrides which allow the end user to override the script's default <tt>PrivilegesRequired</tt> setting. The following overrides are supported: <tt>commandline</tt> and <tt>dialog</tt>.</li>
   <ul>
     <li>If override <tt>commandline</tt> is allowed then Setup will support two additional command line parameters to override the script's default <tt>PrivilegesRequired</tt> setting: /ALLUSERS and /CURRENTUSER.</li>
     <li>If override <tt>dialog</tt> is allowed then Setup will ask the user to choose the install mode based on the script's default <tt>PrivilegesRequired</tt> setting using a suppressible dialog (<a href="https://i.imgur.com/9tjXjmg.png">example</a> if <tt>PrivilegesRequired</tt> is set to <tt>admin</tt>). Allowing <tt>dialog</tt> automatically allows <tt>commandline</tt> and when one of the command line parameters is used then Setup will not ask the user.</li>
   </ul>
-  <li>Inno Setup's own installer now supports both administrative and non administrative mode and allows the <tt>commandline</tt> override.</li>
+  <li>Added new [Setup] section directive: <tt>UsePreviousPrivileges</tt>. If this directive is set to <tt>yes</tt> (which it is by default) and <tt>PrivilegesRequiredOverridesAllowed</tt> is set to <tt>dialog</tt>, at startup Setup will look in the registry to see if the <a href="http://www.jrsoftware.org/is6help/index.php?topic=sameappnotes">same application</a> is already installed in one of the two install modes, and if so, it will use that install mode and not ask the user.</li>
+  <li>Inno Setup's own installer script now supports both administrative and non administrative install mode and allows the <tt>dialog</tt> override.</li>
 </ul>
 <p><span class="head2">Side-by-side installations</span></p>
 <p>Support for <a href="http://www.jrsoftware.org/is6help/index.php?topic=sidebyside">side-by-side</a> installations has been improved:</p>