Inno Setup: Allowing the user to only choose the d

2019-03-16 17:03发布

问题:

Can I allow the user to only choose the drive in which the software will be installed?

For example they can choose the C or D drive:

C:\Software

D:\Software

But the user can not specify anything else,

Like they can’t choose to install the software under Downloads or MyDocumnets …etc.

Is this possible?

回答1:

How to restrict users to select only drive on which the software will be installed ?

There are hundrends of ways to design this restriction. I chose the one which creates a combo box with available paths that user can choose from. This code as first lists all fixed drives on the machine, and if there's at least one, it creates the combo box which is placed instead of original dir selection controls. It is filled with drive names followed by a fixed directory taken from the DefaultDirName directive value which must not contain a drive portion since it is already concatenated with found fixed drive roots:

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName=My Program

[Messages]
SelectDirBrowseLabel=To continue, click Next.

[Code]
#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif
type
  TDriveType = (
    dtUnknown,
    dtNoRootDir,
    dtRemovable,
    dtFixed,
    dtRemote,
    dtCDROM,
    dtRAMDisk
  );
  TDriveTypes = set of TDriveType;

function GetDriveType(lpRootPathName: string): UINT;
  external 'GetDriveType{#AW}@kernel32.dll stdcall';
function GetLogicalDriveStrings(nBufferLength: DWORD; lpBuffer: string): DWORD;
  external 'GetLogicalDriveStrings{#AW}@kernel32.dll stdcall';

var
  DirCombo: TNewComboBox;

#ifndef UNICODE
function IntToDriveType(Value: UINT): TDriveType;
begin
  Result := dtUnknown;
  case Value of
    1: Result := dtNoRootDir;
    2: Result := dtRemovable;
    3: Result := dtFixed;
    4: Result := dtRemote;
    5: Result := dtCDROM;
    6: Result := dtRAMDisk;
  end;
end;
#endif

function GetLogicalDrives(Filter: TDriveTypes; Drives: TStrings): Integer;
var
  S: string;
  I: Integer;
  DriveRoot: string;
begin
  Result := 0;

  I := GetLogicalDriveStrings(0, #0);
  if I > 0 then
  begin
    SetLength(S, I);
    if GetLogicalDriveStrings(Length(S), S) > 0 then
    begin
      S := TrimRight(S) + #0;
      I := Pos(#0, S);
      while I > 0 do
      begin
        DriveRoot := Copy(S, 1, I - 1);
        #ifdef UNICODE
        if (Filter = []) or
          (TDriveType(GetDriveType(DriveRoot)) in Filter) then
        #else
        if (Filter = []) or
          (IntToDriveType(GetDriveType(DriveRoot)) in Filter) then
        #endif
        begin
          Drives.Add(DriveRoot);
        end;
        Delete(S, 1, I);
        I := Pos(#0, S);
      end;
      Result := Drives.Count;
    end;
  end;
end;

procedure DriveComboChange(Sender: TObject);
begin
  WizardForm.DirEdit.Text := DirCombo.Text;
end;

procedure InitializeWizard;
var
  I: Integer;
  StringList: TStringList;
begin
  StringList := TStringList.Create;
  try
    if GetLogicalDrives([dtFixed], StringList) > 0 then
    begin
      WizardForm.DirEdit.Visible := False;
      WizardForm.DirBrowseButton.Visible := False;

      DirCombo := TNewComboBox.Create(WizardForm);
      DirCombo.Parent := WizardForm.DirEdit.Parent;
      DirCombo.SetBounds(WizardForm.DirEdit.Left, WizardForm.DirEdit.Top,
        WizardForm.DirBrowseButton.Left + WizardForm.DirBrowseButton.Width -
        WizardForm.DirEdit.Left, WizardForm.DirEdit.Height);
      DirCombo.Style := csDropDownList;
      DirCombo.OnChange := @DriveComboChange;

      for I := 0 to StringList.Count - 1 do
        DirCombo.Items.Add(StringList[I] + '{#SetupSetting('DefaultDirName')}');

      DirCombo.ItemIndex := 0;
      DirCombo.OnChange(nil);
    end;
  finally
    StringList.Free;
  end;
end;

And a screenshot:



标签: inno-setup