首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >只在需要时使Inno安装程序请求权限提升

只在需要时使Inno安装程序请求权限提升
EN

Stack Overflow用户
提问于 2014-02-04 15:44:37
回答 2查看 22.6K关注 0票数 30

Inno设置安装程序具有可用于在安装程序启动时控制(如果需要权限提升)的指令。我希望我的安装程序工作,即使是非管理员用户(没有问题安装我的应用程序到用户文件夹,而不是Program Files)。因此,我将PrivilegesRequired设置为none (无文档的值)。这使得UAC提示弹出仅供管理用户使用,这样他们甚至可以安装到Program Files上。对于非管理员用户,没有UAC提示,所以即使他们也可以安装应用程序(到用户文件夹)。

不过,这也有一些缺点:

  • 有些人在他们的机器上使用不同的管理和非管理帐户,正常使用非管理帐户。通常,当使用非管理帐户启动安装时,当他们获得UAC提示时,会输入管理帐户的凭据以继续进行。但是这不适用于我的安装程序,因为没有UAC提示。
  • (过于可疑)管理帐户的人,谁想安装到用户文件夹,不能启动我的安装程序,没有(不需要)管理特权。

是否有办法使Inno安装程序请求特权只有在需要时才能提升(当用户选择安装文件夹时,仅由管理帐户可写)?

我想在Inno安装程序中没有设置此设置。但可能有一个编程解决方案(Inno Setup Pascal脚本)或某种插件/DLL。

注意,Inno安装程序6对非管理安装模式有内置支持。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-02-16 14:45:55

Inno安装程序6对非管理安装模式有内置支持。

基本上,您可以简单地设置PrivilegesRequiredOverridesAllowed

代码语言:javascript
运行
复制
[Setup]
PrivilegesRequiredOverridesAllowed=commandline dialog

此外,您可能希望使用常量的auto*变体。特别是用于{autopf}DefaultDirName

代码语言:javascript
运行
复制
[Setup]
DefaultDirName={pf}\My Program

下面是我基于@TLama的回答的Inno Setup 5的解决方案(现在已经过时)。

当安装非提升启动时,它将请求高度,但有一些例外情况:

  • 仅适用于Windows和更新版本(尽管它也应适用于Windows )
  • 升级时,安装程序将检查当前用户是否对前一个安装位置具有写访问权限。如果用户有写访问权限,安装程序将不会请求高度。因此,如果用户以前已将应用程序安装到用户文件夹,则升级时不会请求提升。

如果用户拒绝新安装的提升,安装程序将自动返回“本地应用程序数据”文件夹。即C:\Users\standard\AppData\Local\AppName.

其他改进:

  • 高举的例子不会再要求语言
  • 通过使用PrivilegesRequired=none,安装程序将在提升时将卸载信息写入HKLM,而不是将其写入HKCU
代码语言:javascript
运行
复制
#define AppId "myapp"
#define AppName "MyApp"

#define InnoSetupReg \
  "Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
#define InnoSetupAppPathReg "Inno Setup: App Path"

[Setup]
AppId={#AppId}
PrivilegesRequired=none
...

[Code]

function IsWinVista: Boolean;
begin
  Result := (GetWindowsVersion >= $06000000);
end;

function HaveWriteAccessToApp: Boolean;
var
  FileName: string;
begin
  FileName := AddBackslash(WizardDirValue) + 'writetest.tmp';
  Result := SaveStringToFile(FileName, 'test', False);
  if Result then
  begin
    Log(Format(
      'Have write access to the last installation path [%s]', [WizardDirValue]));
    DeleteFile(FileName);
  end
    else
  begin
    Log(Format('Does not have write access to the last installation path [%s]', [
      WizardDirValue]));
  end;
end;

procedure ExitProcess(uExitCode: UINT);
  external 'ExitProcess@kernel32.dll stdcall';
function ShellExecute(hwnd: HWND; lpOperation: string; lpFile: string;
  lpParameters: string; lpDirectory: string; nShowCmd: Integer): THandle;
  external 'ShellExecuteW@shell32.dll stdcall';

function Elevate: Boolean;
var
  I: Integer;
  RetVal: Integer;
  Params: string;
  S: string;
begin
  { Collect current instance parameters }
  for I := 1 to ParamCount do
  begin
    S := ParamStr(I);
    { Unique log file name for the elevated instance }
    if CompareText(Copy(S, 1, 5), '/LOG=') = 0 then
    begin
      S := S + '-elevated';
    end;
    { Do not pass our /SL5 switch }
    if CompareText(Copy(S, 1, 5), '/SL5=') <> 0 then
    begin
      Params := Params + AddQuotes(S) + ' ';
    end;
  end;

  { ... and add selected language }
  Params := Params + '/LANG=' + ActiveLanguage;

  Log(Format('Elevating setup with parameters [%s]', [Params]));
  RetVal :=
    ShellExecute(0, 'runas', ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
  Log(Format('Running elevated setup returned [%d]', [RetVal]));
  Result := (RetVal > 32);
  { if elevated executing of this setup succeeded, then... }
  if Result then
  begin
    Log('Elevation succeeded');
    { exit this non-elevated setup instance }
    ExitProcess(0);
  end
    else
  begin
    Log(Format('Elevation failed [%s]', [SysErrorMessage(RetVal)]));
  end;
end;

procedure InitializeWizard;
var
  S: string;
  Upgrade: Boolean;
begin
  Upgrade :=
    RegQueryStringValue(HKLM, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S) or
    RegQueryStringValue(HKCU, '{#InnoSetupReg}', '{#InnoSetupAppPathReg}', S);

  { elevate }

  if not IsWinVista then
  begin
    Log(Format('This version of Windows [%x] does not support elevation', [
      GetWindowsVersion]));
  end
    else
  if IsAdminLoggedOn then
  begin
    Log('Running elevated');
  end
    else
  begin
    Log('Running non-elevated');
    if Upgrade then
    begin
      if not HaveWriteAccessToApp then
      begin
        Elevate;
      end;
    end
      else
    begin
      if not Elevate then
      begin
        WizardForm.DirEdit.Text := ExpandConstant('{localappdata}\{#AppName}');
        Log(Format('Falling back to local application user folder [%s]', [
          WizardForm.DirEdit.Text]));
      end;
    end;
  end;
end;
票数 20
EN

Stack Overflow用户

发布于 2014-02-04 23:09:42

在Inno安装程序中,在安装过程的生存期内没有条件提升的内置方式。但是,您可以通过使用runas谓词来执行安装过程,并终止非提升的设置过程。我编写的脚本有点棘手,但展示了一种可能的方法。

警告:

这里使用的代码总是尝试执行提升的安装实例;没有检查实际是否需要提升(请在另一个问题中选择是否需要提升)。而且,我现在还不知道,做这样的人工高程是否安全。我不确定Inno安装程序是否在某种程度上依赖于PrivilegesRequired指令的值。最后,这种提升应该只在相关的Windows版本上执行。在此脚本中不进行检查:

代码语言:javascript
运行
复制
[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;
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21556853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档