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?
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: