; ENSURE FIRST TWO OF THE NEXT LINES ARE UPDATED BEFORE BUILDING THE INSTALLER! ; Full version number of the N2KView executable ; Filename of the update instructions #define MCONNECT_VERSION "2.0.0.20251210" #define MANFILENAME "MConnect User Manual 1.2.0.pdf" #define GETTINGSTARTEDFILENAME "MConnect Quick Install.pdf" #define MCONNECT_RELEASE_DIRECTORY "..\..\mconnect-release\output\" #define MANFILE_DIRECTORY "\\tdy\jup\Projects\MConnect\Users Manual\" #define tsaIP 'http://timestamp.digicert.com' [Setup] AppName=MConnect Update AppVersion= {#MCONNECT_VERSION} OutputBaseFilename=MConnect Update {#MCONNECT_VERSION} DefaultDirName={sd} Uninstallable=no Compression=lzma SolidCompression=true OutputDir=. DisableProgramGroupPage=true UsePreviousGroup=false ShowLanguageDialog=yes AlwaysShowDirOnReadyPage=yes AllowRootDirectory=yes DirExistsWarning=no AppPublisher=Maretron ;SignTool=signapp sign /sha1 a0d2881ac3f87e440e586a65996061540a37f11f /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 $f SignTool=signWrapper $f [Files] ;MConnect tar files and descriptor file and install script Source: "{#MCONNECT_RELEASE_DIRECTORY}install.sh"; DestDir: {code:GetAppDirx}; Source: "{#MCONNECT_RELEASE_DIRECTORY}leds.tar"; DestDir: {code:GetAppDirx}; Source: "{#MCONNECT_RELEASE_DIRECTORY}renegade.tar"; DestDir: {code:GetAppDirx}; Source: "{#MCONNECT_RELEASE_DIRECTORY}script.tar"; DestDir: {code:GetAppDirx}; Source: "{#MCONNECT_RELEASE_DIRECTORY}server.tar"; DestDir: {code:GetAppDirx}; Source: "{#MCONNECT_RELEASE_DIRECTORY}update_20251006.tar"; DestDir: {code:GetAppDirx}; Source: "{#MCONNECT_RELEASE_DIRECTORY}mconnect_update.json"; DestDir: "{code:GetAppDirx}"; Source: "{#MCONNECT_RELEASE_DIRECTORY}VERSION"; DestDir: "{code:GetAppDirx}"; Source: ".\clearactive.bat"; DestDir: "{code:GetAppDirx}"; Source: "{#MANFILE_DIRECTORY}{#MANFILENAME}"; DestDir: "{code:GetAppDirx}"; Source: "{#MANFILE_DIRECTORY}{#GETTINGSTARTEDFILENAME}"; DestDir: "{code:GetAppDirx}"; [CustomMessages] [Messages] WelcomeLabel2=This will copy the MConnect files onto a USB flash drive, which you can then use to update your MConnect.%n%nThis will update your system to the following revision:%n%nMConnect: version {#MCONNECT_VERSION}%n%nPlease ensure that you have a USB flash drive plugged into this computer. SelectDirLabel3=Setup will copy {#SetupSetting("AppName")} files onto the selected USB flash drive. SelectDirBrowseLabel=To continue, click Next. If you would like to select a different USB flash drive, choose it from the list. ReadyLabel1=Setup is now ready to begin copying {#SetupSetting("AppName")} onto the USB flash drive. ReadyLabel2a=Click Install to copy the files, or click Back if you want to review or change any settings. ReadyMemoDir=Destination USB flash drive: InstallingLabel=Please wait while Setup installs {#SetupSetting("AppName")} onto the USB flash drive. FinishedLabelNoIcons=Setup has finished copying {#SetupSetting("AppName")} onto the USB flash drive. Please eject the USB flash drive from your computer and plug it into a running system. Please see the Installation Instructions below for details. [Run] Filename: "{app}\{#GETTINGSTARTEDFILENAME}"; Description: "Read Installation Instructions"; Flags: nowait postinstall skipifsilent shellexec Filename: "{app}\{#MANFILENAME}"; Description: "Read Manual"; Flags: nowait postinstall skipifsilent shellexec [Code] var // combo box for drives cbDrive : TComboBox ; // array of strings that stores the drive letters DrvLetters: array of String; // drive letter to which to install AppDir: String; function GetDriveType( lpDisk: String ): Integer; external 'GetDriveTypeA@kernel32.dll stdcall'; function GetLogicalDriveStrings( nLenDrives: LongInt; lpDrives: String ): Integer; external 'GetLogicalDriveStringsA@kernel32.dll stdcall'; //---------------------------------------------------------------------------------------------- // procedure GetVolumeInformation function GetVolumeInformation( lpRootPathName: PAnsiChar; lpVolumeNameBuffer: PAnsiChar; nVolumeNameSize: LongInt; var lpVolumeSerialNumber: LongInt; var lpMaximumComponentLength: LongInt; var lpFileSystemFlags : LongInt; lpFileSystemNameBuffer: PAnsiChar; nFileSystemNameSize: LongInt) : Integer; external 'GetVolumeInformationA@kernel32.dll'; //---------------------------------------------------------------------------------------------- // procedure ExitProcess procedure ExitProcess(exitCode:integer); external 'ExitProcess@kernel32.dll stdcall'; const DRIVE_UNKNOWN = 0; // The drive type cannot be determined. DRIVE_NO_ROOT_DIR = 1; // The root path is invalid. For example, no volume is mounted at the path. DRIVE_REMOVABLE = 2; // The disk can be removed from the drive. DRIVE_FIXED = 3; // The disk cannot be removed from the drive. DRIVE_REMOTE = 4; // The drive is a remote (network) drive. DRIVE_CDROM = 5; // The drive is a CD-ROM drive. DRIVE_RAMDISK = 6; // The drive is a RAM disk. // function to convert disk type to a regonizable string. This piece needs translation // to other languages function DriveTypeString( dtype: Integer ): String ; begin case dtype of DRIVE_NO_ROOT_DIR : Result := 'Root path invalid'; DRIVE_REMOVABLE : Result := 'Removable'; DRIVE_FIXED : Result := 'Fixed'; DRIVE_REMOTE : Result := 'Network'; DRIVE_CDROM : Result := 'CD-ROM'; DRIVE_RAMDISK : Result := 'Ram disk'; else Result := 'Unknown'; end; end; //---------------------------------------------------------------------------------------------- // procedure GetAppDirx // return chosen installation directory function GetAppDirx( Param: String): String; begin Result := AppDir; end; //---------------------------------------------------------------------------------------------- // procedure GetAppDrive // return chosen installation drive -- installation directory with backslash removed function GetAppDrive( Param: String): String; var posbs : integer; begin posbs := Pos( '\', AppDir ); if posbs >= 0 then begin Result := Copy(AppDir,0,posbs-1); end else begin Result := AppDir; end end; //---------------------------------------------------------------------------------------------- // procedure cbDriveOnClick // change folder accordigly to the drive letter selected procedure cbDriveOnClick(Sender: TObject); begin Log('entering cbDriveOnClick() ind = ' + IntToStr(cbDrive.ItemIndex)); WizardForm.DirEdit.Text := DrvLetters[ cbDrive.ItemIndex ]; AppDir := WizardForm.DirEdit.Text; end; //---------------------------------------------------------------------------------------------- // procedure FillCombo procedure FillCombo(); var n: Integer; drivesletters: String; lenletters: Integer; drive: String; sernum, disktype, posnull: Integer; sd: String; vollabel: String; fsname: String; clen: integer; flags: integer; posnull2: Integer; gotvolinf : Integer; begin //get the system drive sd := UpperCase(ExpandConstant('{sd}')); Log ('sd =' + sd ); //get all drive letters of the system drivesletters := StringOfChar( ' ', 1024 ); lenletters := GetLogicalDriveStrings( 1023, drivesletters ); Log ('drivesletters = ' + drivesletters); SetLength( drivesletters , lenletters ); drive := ''; n := 0; while ( (Length(drivesletters) > 0) ) do begin Log ('posnull'); drive:= UpperCase( Copy( drivesletters, 1, posnull - 1 ) ); Log('Drive = ' + drive); // get number type of disk posnull := Pos( #0, drivesletters ); if posnull > 0 then begin disktype := GetDriveType( drive ); Log('Called GetDriveType'); vollabel := StringofChar(' ',128); fsname := StringofChar(' ',128); gotvolinf := GetVolumeInformation(drive+'\',vollabel,127,sernum,clen,flags,fsname,127); if (gotvolinf <> 0 ) then begin posnull2 := Pos( #0, vollabel ); SetLength( vollabel , posnull2-1 ); posnull2 := Pos ( #0, fsname ); SetLength( fsname, posnull2-1 ); end; // you can add various types of checks here to limit the types of drives that // are displayed to the user. in this example we add a drive only if is not a // removable drive (ie floppy, USB key, etc). you may add whatever limitations // you need in the next IF statement if ( (disktype = DRIVE_REMOVABLE) and (gotvolinf <> 0) ) then begin if ( fsname = 'FAT32' ) then begin cbDrive.Items.Add( vollabel + ' (' + drive + ') [' + DriveTypeString( disktype ) + ']' ) Log('Added ' + drive + ' ' + vollabel + ' [' + DriveTypeString( disktype ) + ']' ); SetArrayLength(DrvLetters, n+1); DrvLetters[n] := drive; // default select C: Drive (not very wise since the users system drive may not be C: or they // may not even have a C: drive //if ( Copy(drive,1,2) = 'C:' ) then cbDrive.ItemIndex := n; // instead default it to the users system drive //if ( Copy(drive,1,2) = sd ) then cbDrive.ItemIndex := n; cbDrive.ItemIndex := 0; n := n + 1; end else if (n=0) then begin n := -1; end end; // if ((posnull+1) > Length(drivesletters)) then //begin //Log('Setting drivesletters to an empty string'); //drivesletters := ''; //end //else // begin Log ('Calling Copy with drivesletters = ' + drivesletters + ', pos = ' + IntToStr(posnull+1) + ', len = ' + IntToStr(Length(drivesletters))); drivesletters := Copy( drivesletters, posnull+1, Length(drivesletters)); // end end end; if (n > 0) then begin cbDrive.ItemIndex := 0; Log('calling cbDriveOnClick with ind = ' + IntToStr(cbDrive.ItemIndex)); cbDriveOnClick( cbDrive ); Log('exiting FillCombo()'); end else if (n = -1) then begin MsgBox('Removable drive must be formatted FAT32. Please insert a FAT32 removable drive and run this program again.', mbCriticalError, MB_OK); ExitProcess(0); end else begin MsgBox('No removable drives were detected. Please insert a removable drive and run this program again.', mbCriticalError, MB_OK); ExitProcess(0); end end; //---------------------------------------------------------------------------------------------- // procedure CurStepChanged // Clear the bootable flag on the USB drive procedure CurStepChanged (CurStep: TSetupStep); var WorkingDir: String; Arguments: String; ReturnCode: Integer; Success: Boolean; begin Log( 'entering CurStepChanged' ); if (CurStep = ssPostInstall) then begin Log( 'CurStep = ssPostInstall' ); WorkingDir := ExpandConstant ('{app}'); Arguments := GetAppDrive(''); Log('Running program '+ WorkingDir + 'clearactive.bat '+ Arguments); Success := Exec(WorkingDir + 'clearactive.bat', Arguments, WorkingDir, SW_HIDE, ewWaitUntilTerminated, ReturnCode); If Not (Success and (ReturnCode = 0)) then begin MsgBox('Setup was unable to clear the bootable flag on the USB flash drive. Please open a command prompt window, change your working directory to ' + ExpandConstant('{app}') + ', and run clearactive.bat . If this fails, please contact Maretron technical support.', mbCriticalError, MB_OK); ExitProcess(-1); end end; end; // procedure CutStepChanged //---------------------------------------------------------------------------------------------- // procedure CurStepChanged procedure InitializeWizard(); begin // create the combo box for drives cbDrive:= TComboBox.Create(WizardForm.SelectDirPage); with cbDrive do begin Parent := WizardForm.DirEdit.Parent; Left := WizardForm.DirEdit.Left; Top := WizardForm.DirEdit.Top + WizardForm.DirEdit.Height * 2; Width := WizardForm.DirEdit.Width; Style := csDropDownList; end; // hide the Browse button WizardForm.DirBrowseButton.Visible := false; // Edit box for folder is non-editable WizardForm.DirEdit.Enabled := false; // fill combo box with Drives FillCombo; cbDrive.DropDownCount := 0; // set the event on combo change cbDrive.OnClick := @cbDriveOnClick ; end;