Faire Inno Setup installer demande d'élévation de privilèges uniquement lorsque cela est nécessaire

Inno Setup l'installateur a le PrivilegesRequired la directive qui peut être utilisé pour contrôler, si l'élévation des privilèges est requise, le démarrage de l'installateur. Je veux que mon installateur fonctionne même pour les utilisateurs non-administrateurs (pas de problème pour installer mon application dans le dossier utilisateur, au lieu du Program Files). Alors j'ai mis le PrivilegesRequirednone (valeur non documentée). Cela fait popup UAC prompt pour les utilisateurs admin seulement, de sorte qu'ils peuvent installer même à la Program Files. Aucune invite UAC pour les utilisateurs non-administrateurs, ainsi, même eux peuvent installer l'application (dossier utilisateur).

Cela a quelques inconvénients cependant:

  • certaines personnes utilisent des comptes admin et non-admin distincts sur leurs machines, travaillant avec des comptes non-admin normalement. En général, lors du lancement de l'installation en utilisant un compte non-administrateur, lorsqu'ils reçoivent l'invite UAC, ils saisissent les informations d'identification pour que le compte administrateur puisse continuer. Mais ça ne marchera pas avec mon installateur, parce qu'il n'y a pas d'invite UAC.
  • (Trop suspect) les personnes avec un compte administrateur, qui veulent installer dans le dossier utilisateur, ne peuvent pas lancer mon installeur Sans (pas-nécessaire) privilèges admin.

y a-t-il un moyen de faire en sorte que les privilèges D'élévation de la requête de configuration Inno ne soient accordés qu'en cas de besoin (lorsque l'utilisateur sélectionne le dossier d'installation accessible en écriture uniquement par un compte administrateur)?

je suppose qu'il n'y a pas de paramètre pour cela dans la configuration Inno. Mais peut-être, il y a une solution programmatique (Inno Setup Pascal scripting) ou une sorte de plugin / DLL.

19
demandé sur Martin Prikryl 2014-02-04 19:44:37

2 réponses

il n'y a pas de manière intégrée pour l'élévation conditionnelle du processus de configuration pendant sa durée de vie dans Inno Setup. Cependant, vous pouvez exécuter le processus de configuration en utilisant runas verbe et tuer le non-élevé. Le script que j'ai écrit est un peu délicat, mais montre une voie possible comment le faire.

Avertissement:

le code utilisé ici tente d'exécuter l'instance de configuration élevée toujours; il n'y a aucune vérification si l'élévation est réellement nécessaire ou non (comment décider si l'élévation est nécessaire éventuellement demander à une autre question, s'il vous plaît). Aussi, je ne peux pas dire pour le moment, si c'est sans danger de faire une telle élévation manuelle. Je ne suis pas sûr que Inno Setup ne se fie pas (ou ne se fie pas) à la valeur de PrivilegesRequired la directive, d'une certaine façon. Et enfin, ce truc d'élévation ne doit être exécuté que sur les versions Windows correspondantes. Aucune vérification de ce qui est fait dans ce script:

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
PrivilegesRequired=lowest

[Code]
#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif
type
  HINSTANCE = THandle;

procedure ExitProcess(uExitCode: UINT);
  external 'ExitProcess@kernel32.dll stdcall';
function ShellExecute(hwnd: HWND; lpOperation: string; lpFile: string;
  lpParameters: string; lpDirectory: string; nShowCmd: Integer): HINSTANCE;
  external 'ShellExecute{#AW}@shell32.dll stdcall';

var
  Elevated: Boolean;
  PagesSkipped: Boolean;

function CmdLineParamExists(const Value: string): Boolean;
var
  I: Integer;  
begin
  Result := False;
  for I := 1 to ParamCount do
    if CompareText(ParamStr(I), Value) = 0 then
    begin
      Result := True;
      Exit;
    end;
end;

procedure InitializeWizard;
begin
  { initialize our helper variables }
  Elevated := CmdLineParamExists('/ELEVATE');
  PagesSkipped := False;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
  { if we've executed this instance as elevated, skip pages unless we're }
  { on the directory selection page }
  Result := not PagesSkipped and Elevated and (PageID <> wpSelectDir);
  { if we've reached the directory selection page, set our flag variable }
  if not Result then
    PagesSkipped := True;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var
  Params: string;
  RetVal: HINSTANCE;
begin
  Result := True;
  { if we are on the directory selection page and we are not running the }
  { instance we've manually elevated, then... }
  if not Elevated and (CurPageID = wpSelectDir) then
  begin
    { pass the already selected directory to the executing parameters and }
    { include our own custom /ELEVATE parameter which is used to tell the }
    { setup to skip all the pages and get to the directory selection page }
    Params := ExpandConstant('/DIR="{app}" /ELEVATE');
    { because executing of the setup loader is not possible with ShellExec }
    { function, we need to use a WinAPI workaround }
    RetVal := ShellExecute(WizardForm.Handle, 'runas',
      ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
    { if elevated executing of this setup succeeded, then... }
    if RetVal > 32 then
    begin
      { exit this non-elevated setup instance }
      ExitProcess(0);
    end
    else
    { executing of this setup failed for some reason; one common reason may }
    { be simply closing the UAC dialog }
    begin
      { handling of this situation is upon you, this line forces the wizard }
      { stay on the current page }
      Result := False;
      { and possibly show some error message to the user }
      MsgBox(Format('Elevating of this setup failed. Code: %d', [RetVal]),
        mbError, MB_OK);
    end;
  end;
end;
9
répondu TLama 2016-12-07 18:29:42

Ma solution basée sur la réponse de@TLama.

quand la configuration est démarrée non-Elevée, elle demandera une élévation, avec quelques exceptions:

  • Uniquement sur Windows Vista et versions plus récentes (mais il devrait fonctionner sur Windows XP aussi)
  • lors de la mise à jour, la configuration vérifiera si l'utilisateur courant a un accès en écriture à l'emplacement d'installation précédent. Si l'Utilisateur a l'accès en écriture, la configuration ne demandera pas l'élévation. Donc, si l'utilisateur a précédemment installé dans le dossier application to user, l'élévation ne sera pas demandée lors de la mise à niveau.

si l'utilisateur rejette l'élévation sur une nouvelle installation, l'installateur retombera automatiquement dans le dossier "données de l'application locale". I. e. C:\Users\standard\AppData\Local\AppName.

d'Autres améliorations:

  • l'élévation de l'instance ne le demandons pas de langue de nouveau
  • en utilisant PrivilegesRequired=none, l'installateur écrira les informations de désinstallation à