“You must enter a full path with driver […] or a U

2019-09-04 14:15发布

Apologies if my code is terrible. I am running into this error message:

enter image description here

The installer currently starts as a non-admin user then kills and restarts itself as an admin user right before files start being copied. The error message only comes up when 'Register' install is selected.

This occurs if I enter any top-level drive in the install location. If I enter a folder on a network share, I'll get a different error (another privilege issue) and if I input a folder on the C:\ drive (as in C:\xyz) then it works fine.

#define MyAppName "O"
#define MyAppVersion "0.0"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{9BB6F4FD-5530-4043-BD9E-A405BAEDDDFF}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
DefaultDirName={sd}\{#MyAppName}
DisableDirPage=yes
AllowNoIcons=yes
OutputDir={desktop}
OutputBaseFilename=dummy
Compression=lzma
SolidCompression=yes

PrivilegesRequired=lowest

[Types]
Name: "server"; Description: "Odin Server Install"
Name: "client"; Description: "Odin Register/Workstation Install"

[Components]
Name: "data_shared_exe"; Description: "Core apps installed"; Types: server;
Name: "C_Odin"; Description: "Database stuff"; Types: server client;
Name: "shortcuts"; Description: "Shortcuts to Odin apps"; Types: server client;

[Code]

var
  SelectOdinSharePage: TInputDirWizardPage;
  SelectOdinInstallPage: TInputDirWizardPage;

  Elevated: Boolean;
  InstallType: Integer;
  DirParam: string;

type
  HINSTANCE = THandle;

// Privilege Escalation code
// Inspired by/Courtesy of http://stackoverflow.com/questions/21556853/make-inno-setup-installer-request-privileges-elevation-only-when-needed
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 'ShellExecuteW@shell32.dll stdcall';

function IsServerInstall(): Boolean;
begin
  Result := (InstallType=0)
end;

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;

function CmdLineParamReadInt(const Value: string): integer;
var
  I: Integer;  
begin
  Result := -1;
  for I := 1 to ParamCount do
    if Pos(Value, ParamStr(I)) = 1 then
    begin
      Result := StrToInt(Copy(ParamStr(I), Length(Value)+2, 1));
      //MsgBox(Format('ReadInt: %s', [Copy(ParamStr(I), Length(Value)+2, 1)]), mbInformation, MB_OK);
      Exit;
    end;
end;

function CmdLineParamReadStr(const Value: string): string;
var
  I: Integer;  
begin
  Result := '';
  for I := 1 to ParamCount do
    if Pos(Value, ParamStr(I)) = 1 then
    begin
      Result := Copy(ParamStr(I), Length(Value)+2, Length(ParamStr(I))-Length(Value)-1);
      //MsgBox(Format('ReadStr: %s',[Result]), mbInformation, MB_OK)
      Exit;
    end;
end;

procedure OnTypeChange(Sender: TObject);
begin
  // set the item index in hidden TypesCombo
  WizardForm.TypesCombo.ItemIndex := TNewRadioButton(Sender).Tag;
  InstallType := TNewRadioButton(Sender).Tag;
  // notify TypesCombo about the selection change
  WizardForm.TypesCombo.OnChange(nil);
end;

procedure InitializeWizard();
var
  I: Integer;
  RadioButton: TNewRadioButton;
begin
  // By default, InstallType is 1 ('Register')
  InstallType := 1;

  // Privilege escalation parameters
  Elevated := CmdLineParamExists('/ELEVATE');
  if Elevated then
  begin
    InstallType := CmdLineParamReadInt('/INSTALLTYPE');
    DirParam := CmdLineParamReadStr('/DIR');
    //MsgBox(Format('DirParam: %s', [DirParam]), mbInformation, MB_OK);
  end;

  for I := 0 to WizardForm.TypesCombo.Items.Count - 1 do
  begin
    // create radio button and set the basic properties
    RadioButton := TNewRadioButton.Create(WizardForm);
    RadioButton.Parent := WizardForm.SelectComponentsPage;
    RadioButton.Left := WizardForm.TypesCombo.Left;
    RadioButton.Top := WizardForm.TypesCombo.Top + I * RadioButton.Height;
    RadioButton.Width := WizardForm.TypesCombo.Width;
    // the Tag property substitutes the index property
    RadioButton.Tag := I;
    RadioButton.TabOrder := I;     
    RadioButton.OnClick := @OnTypeChange;
    // check just the first item
    RadioButton.Checked := I = InstallType;
    RadioButton.Caption := WizardForm.TypesCombo.Items[I];
  end;
  // hide the TypesCombo combo box
  WizardForm.TypesCombo.Visible := False;

  SelectOdinSharePage := CreateInputDirPage(wpSelectComponents,
  'Select Odin Exe''s directory', 'Where are the Odin exe''s located?',
  'The Odin exe''s are usually located on the Odin Network Share under "exe" or "exes". ' +
  'Once you have found this directory, click Next. If you would like to select a different folder, click Browse.',
  False, 'New Folder');
  SelectOdinSharePage.Add('');
  SelectOdinSharePage.Values[0] := 'O:';

  SelectOdinInstallPage := CreateInputDirPage(wpSelectComponents,
  'Select Odin Install directory', 'Select where to install Odin core apps',
  'To continue, click Next. If you would like to select a different folder, click Browse.',
  False, 'New Folder');
  SelectOdinInstallPage.Add('');
  SelectOdinInstallPage.Values[0] := 'C:\Program Files (x86)\Odin';

  if Elevated then
  begin
    if IsServerInstall() then SelectOdinInstallPage.Values[0] := DirParam;
    if not IsServerInstall() then SelectOdinSharePage.Values[0] := DirParam;
  end;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
  Result := False;
  if ((PageID=100) and IsServerInstall()) then Result := True;
  if ((PageID=101) and not IsServerInstall()) then Result := True;

  if Elevated then
  begin
    if IsServerInstall() then
    begin
      if ((PageID=7) or (PageID=101)) then Result := True;
    end;
    if InstallType=1 then
    begin
      if ((PageID=7) or (PageID=100)) then Result := True;
    end;
  end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var
  Params: string;
  RetVal: HINSTANCE;
begin
  Result := True;
  //MsgBox(Format('Is Server Install: %d', [WizardForm.TypesCombo.ItemIndex]), mbInformation, MB_OK);
  if (CurPageID=101) and IsServerInstall() then
  begin
    Params := ExpandConstant('/DIR="' + SelectOdinInstallPage.Values[0] + '" /ELEVATE /INSTALLTYPE=0');
    RetVal := ShellExecute(WizardForm.Handle, 'runas',
      ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
    if RetVal > 32 then
    begin
      ExitProcess(0);
    end
    else
      MsgBox('Administrative privilege escalation failed. Install aborted. Contact Odin Support.', mbInformation, MB_OK);
      ExitProcess(0);
  end;
  if (CurPageID=100) and (not IsServerInstall()) then
  begin
    Params := ExpandConstant('/DIR="' + SelectOdinSharePage.Values[0] + '" /ELEVATE /INSTALLTYPE=1');

    RetVal := ShellExecute(WizardForm.Handle, 'runas',
      ExpandConstant('{srcexe}'), Params, '', SW_SHOW);
    if RetVal > 32 then
    begin
      ExitProcess(0);
    end
    else
      MsgBox('Administrative privilege escalation failed. Install aborted. Contact Odin Support.', mbInformation, MB_OK);
      ExitProcess(0);
  end;
end;

标签: inno-setup
1条回答
家丑人穷心不美
2楼-- · 2019-09-04 15:05

As it turns out, the problem lies in the lines

if (CurPageID=100) and (not IsServerInstall()) then
  begin
    Params := ExpandConstant('/DIR="' + SelectOdinSharePage.Values[0] + '" /ELEVATE /INSTALLTYPE=1');

    RetVal := ShellExecute(WizardForm.Handle, 'runas',
      ExpandConstant('{srcexe}'), Params, '', SW_SHOW);

In this section of code, the launcher is re-launched with administrative privileges. IN THE PARAMS SECTION, the '/DIR' option is an Inno Setup option, which overrides the default InstallDirectory. This needs to be set to something that is not a top-level drive (i.e., not 'C:\' or 'O:\', but 'C:\xyz').

As long as that is changed, the above program stub will work fine.

查看更多
登录 后发表回答