Sometimes you want to copy or install files to a removable disk (usb stick, sd card, …)
This inno setup script detects removable disks and creates a setup dialog for the removeable devices only.
Features
- detects any removeable disk
- Install to root usb folder
- ignores hidden disks
- compatible with unicode and ansi version of inno setup
- x32 and x64 compatible
[Setup] AppName=Setup to USB AppVersion=1.0 DefaultDirName=USB CreateUninstallRegKey=no AllowRootDirectory=yes Uninstallable=no [Messages] SelectDirBrowseLabel=Please insert a USB stick into your computer. [Files] Source: {src}\Files\* ;DestDir: {app}; Flags: recursesubdirs external [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'; function GetLogicalDrives(): DWORD; external 'GetLogicalDrives@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 GetVolumeInformation( #ifdef UNICODE lpRootPathName: PAnsiChar; lpVolumeNameBuffer: PAnsiChar; nVolumeNameSize: DWORD; var lpVolumeSerialNumber: DWORD; var lpMaximumComponentLength: DWORD; var lpFileSystemFlags: DWORD; lpFileSystemNameBuffer: PAnsiChar; nFileSystemNameSize: DWORD ): BOOL; external 'GetVolumeInformationA@kernel32.dll stdcall'; #else lpRootPathName: PChar; lpVolumeNameBuffer: PChar; nVolumeNameSize: DWORD; var lpVolumeSerialNumber: DWORD; var lpMaximumComponentLength: DWORD; var lpFileSystemFlags: DWORD; lpFileSystemNameBuffer: PChar; nFileSystemNameSize: DWORD ): BOOL; external 'GetVolumeInformationA@kernel32.dll stdcall'; #endif function LoWord(dw: DWORD): WORD; begin Result := WORD(dw); end; function HiWord(dw: DWORD): WORD; begin Result := WORD((dw shr 16) and $FFFF); end; function WordToHex(w: WORD): string; begin Result := Format('%.4x', [w]); end; function FindVolumeSerial(const Drive: string): string; var FileSystemFlags: DWORD; VolumeSerialNumber: DWORD; MaximumComponentLength: DWORD; begin Result := ''; // Note on passing PChars using RemObjects Pascal Script: // '' pass a nil PChar // #0 pass an empty PChar if GetVolumeInformation( #ifdef UNICODE PAnsiChar(Drive), #else PChar(Drive), #endif '', // nil 0, VolumeSerialNumber, MaximumComponentLength, FileSystemFlags, '', // nil 0) then Result := WordToHex(HiWord(VolumeSerialNumber)) + '-' + WordToHex(LoWord(VolumeSerialNumber)); end; function ListLogicalDrives(Filter: TDriveTypes; Drives: TStrings): Integer; var S: string; I: Integer; DriveRoot: string; begin Result := 0; GetLogicalDrives(); 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); Log('The Value is: ' + IntToStr(GetDriveType(DriveRoot))); #ifdef UNICODE if (Filter = []) or ((TDriveType(GetDriveType(DriveRoot)) in Filter)) and (FindVolumeSerial(DriveRoot) <> '') then #else if (Filter = []) or (IntToDriveType(GetDriveType(DriveRoot)) in Filter) and (FindVolumeSerial(DriveRoot) <> '') 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 ListLogicalDrives([dtRemovable], 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]); DirCombo.ItemIndex := 0; DirCombo.OnChange(nil); end else begin MsgBox('No usb stick detected. Please insert an usb stick and restart setup', mbCriticalError, MB_OK); Abort; end; finally StringList.Free; end; end;
Download example project: sd_setup_inno_example.zip