From 0b0c0d32d3358c76931f3bf0086b76c735158222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Wed, 13 Aug 2025 10:08:01 +0200 Subject: [PATCH 01/19] Rename components on the form to make them easier to identify Add drag and drop support for the setup.ini file --- Source/MultiInstaller.dproj | 7 +- Source/MultiInstaller.res | Bin 29268 -> 29268 bytes Source/unit1.dfm | 74 +++--- Source/unit1.pas | 445 +++++++++++++++++++++--------------- 4 files changed, 306 insertions(+), 220 deletions(-) diff --git a/Source/MultiInstaller.dproj b/Source/MultiInstaller.dproj index e43afa7..8d23e47 100644 --- a/Source/MultiInstaller.dproj +++ b/Source/MultiInstaller.dproj @@ -4,12 +4,13 @@ MultiInstaller.dpr Debug DCC32 - 20.1 + 20.3 True Application VCL Win32 1 + MultiInstaller true @@ -179,8 +180,8 @@ - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components + Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver + Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server diff --git a/Source/MultiInstaller.res b/Source/MultiInstaller.res index c61c42aabe9d65b22a33e3a3cd036ed9786a8fa6..35d5ad7e0b12e28f7b5930b08cdd8c31cf137572 100644 GIT binary patch delta 15 Wcmccegz?G~#tkAxj4YEyi|he9d 0; + btnBack.Enabled := I > 0; case I of - 0: LabelTitle.Caption := SWelcomeTitle; - 1: LabelTitle.Caption := SDestinationTitle; - 2: begin - LabelTitle.Caption := SInstallingTitle; - Timer1.Enabled := True; // Delay it a little for UI responsiveness - end; + 0: + lblTitle.Caption := SWelcomeTitle; + 1: + lblTitle.Caption := SDestinationTitle; + 2: + begin + lblTitle.Caption := SInstallingTitle; + Timer1.Enabled := True; // Delay it a little for UI responsiveness + end; else - LabelTitle.Caption := ''; + lblTitle.Caption := ''; end; end; -procedure TForm1.CompileCheckboxClick(Sender: TObject); +procedure TForm1.chkCompileInIdeClick(Sender: TObject); begin - RadioGroup1.Enabled := CompileCheckbox.Checked; + rgSelectIde.Enabled := chkCompileInIde.Checked; +end; + +procedure TForm1.CreateInstaller(const APath: string); +begin + FreeAndNil(FInstaller); + + FInstaller := TSpMultiInstaller.Create(APath); + FillCheckListBox; + FillRadioGroup; + ValidateCheckListBox; + + if DirectoryExists(FInstaller.ComponentPackages.DefaultInstallFolder) then + edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; end; procedure TForm1.FillCheckListBox; var I, G, P: Integer; begin - for I := 0 to Installer.ComponentPackages.Count - 1 do begin - P := -1; - G := Installer.ComponentPackages[I].GroupIndex; - if G > 0 then begin - P := CheckListBox1.Items.IndexOfObject(Pointer(G)); - if P > -1 then - CheckListBox1.Items[P] := CheckListBox1.Items[P] + #13#10 + Installer.ComponentPackages[I].Name; - end; + clbSelectComponents.Clear; + clbSelectComponents.ItemIndex := -1; + + for I := 0 to FInstaller.ComponentPackages.Count - 1 do + begin + P := -1; + G := FInstaller.ComponentPackages[I].GroupIndex; + if G > 0 then + begin + P := clbSelectComponents.Items.IndexOfObject(Pointer(G)); + if P > -1 then + clbSelectComponents.Items[P] := clbSelectComponents.Items[P] + #13#10 + FInstaller.ComponentPackages[I].Name; + end; - if P = -1 then begin - P := CheckListBox1.Items.AddObject(Installer.ComponentPackages[I].Name, Pointer(G)); - CheckListBox1.Checked[P] := True; - if Installer.ComponentPackages[I].Git <> '' then - CheckListBox1.Items[P] := CheckListBox1.Items[P] + #13#10 + - 'GIT: ' + Installer.ComponentPackages[I].Git; + if P = -1 then + begin + P := clbSelectComponents.Items.AddObject(FInstaller.ComponentPackages[I].Name, Pointer(G)); + clbSelectComponents.Checked[P] := True; + if FInstaller.ComponentPackages[I].Git <> '' then + clbSelectComponents.Items[P] := clbSelectComponents.Items[P] + #13#10 + + 'GIT: ' + FInstaller.ComponentPackages[I].Git; + end; end; - end; end; procedure TForm1.FillRadioGroup; var IDE: TSpIDEType; begin - RadioGroup1.ItemIndex := -1; + rgSelectIde.Items.Clear; + rgSelectIde.ItemIndex := -1; for IDE := Low(TSpIDEType) to High(TSpIDEType) do - if IDE >= Installer.ComponentPackages.MinimumIDE then - if TSpDelphiIDE.Installed(IDE) then begin - RadioGroup1.Items.AddObject(IDETypes[IDE].IDEName, Pointer(Ord(IDE))); - if IDE = Installer.ComponentPackages.DefaultInstallIDE then - RadioGroup1.ItemIndex := RadioGroup1.Items.Count - 1; - end; + if IDE >= FInstaller.ComponentPackages.MinimumIDE then + if TSpDelphiIDE.Installed(IDE) then + begin + rgSelectIde.Items.AddObject(IDETypes[IDE].IDEName, Pointer(Ord(IDE))); + if IDE = FInstaller.ComponentPackages.DefaultInstallIDE then + rgSelectIde.ItemIndex := rgSelectIde.Items.Count - 1; + end; - if RadioGroup1.ItemIndex = -1 then - RadioGroup1.ItemIndex := RadioGroup1.Items.Count - 1 + if rgSelectIde.ItemIndex = -1 then + rgSelectIde.ItemIndex := rgSelectIde.Items.Count - 1 else - CompileCheckbox.Checked := True; + chkCompileInIde.Checked := True; end; function TForm1.ValidateCheckListBox: Boolean; @@ -248,44 +296,76 @@ function TForm1.ValidateCheckListBox: Boolean; I: Integer; begin Result := False; - for I := 0 to CheckListBox1.Count - 1 do - if CheckListBox1.Checked[I] then begin - Result := True; - Break; - end; + for I := 0 to clbSelectComponents.Count - 1 do + if clbSelectComponents.Checked[I] then + begin + Result := True; + Break; + end; - ButtonNext.Enabled := Result; + btnNext.Enabled := Result; end; -procedure TForm1.CheckListBox1ClickCheck(Sender: TObject); +procedure TForm1.WMDROPFILES(var Msg: TWMDropFiles); +var + LDropHandle : HDROP; + FileNameLength: Integer; + LCount : Integer; + LFileName : string; + LFileExt : string; +begin + inherited; + + LDropHandle := Msg.Drop; + LCount := DragQueryFile(LDropHandle, $FFFFFFFF, nil, 0); + + try + if LCount = 1 then + begin + FileNameLength := DragQueryFile(LDropHandle, 0, nil, 0); + SetLength(LFileName, FileNameLength); + DragQueryFile(LDropHandle, 0, PChar(LFileName), FileNameLength + 1); + LFileExt := ExtractFileExt(LFileName); + if SameText(LFileExt, '.ini') then + CreateInstaller(LFileName); + end; + + finally + DragFinish(LDropHandle); + Msg.Result := 0; + end; +end; + +procedure TForm1.clbSelectComponentsClickCheck(Sender: TObject); begin ValidateCheckListBox; end; -procedure TForm1.CheckListBox1MeasureItem(Control: TWinControl; +procedure TForm1.clbSelectComponentsMeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); var R: TRect; begin if Index > -1 then - Height := DrawText(CheckListBox1.Canvas.Handle, PChar(CheckListBox1.Items[Index]), -1, R, DT_CALCRECT) + 4; + Height := DrawText(clbSelectComponents.Canvas.Handle, PChar(clbSelectComponents.Items[Index]), -1, R, DT_CALCRECT) + 4; end; -procedure TForm1.CheckListBox1DrawItem(Control: TWinControl; +procedure TForm1.clbSelectComponentsDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); begin - if Index > -1 then begin - CheckListBox1.Canvas.FillRect(Rect); - OffsetRect(Rect, 8, 2); - DrawText(CheckListBox1.Canvas.Handle, PChar(CheckListBox1.Items[Index]), -1, Rect, 0); - end; + if Index > -1 then + begin + clbSelectComponents.Canvas.FillRect(Rect); + OffsetRect(Rect, 8, 2); + DrawText(clbSelectComponents.Canvas.Handle, PChar(clbSelectComponents.Items[Index]), -1, Rect, 0); + end; end; -procedure TForm1.PaintBoxLabelPaint(Sender: TObject); +procedure TForm1.pbxVersionInfoPaint(Sender: TObject); var C: TCanvas; begin - C := PaintBoxLabel.Canvas; + C := pbxVersionInfo.Canvas; C.Brush.Style := bsClear; C.Font.Color := clBtnHighlight; C.TextOut(1, 1, rvMultiInstallerVersion); @@ -293,13 +373,13 @@ procedure TForm1.PaintBoxLabelPaint(Sender: TObject); C.TextOut(0, 0, rvMultiInstallerVersion); end; -procedure TForm1.PaintBoxLabelClick(Sender: TObject); +procedure TForm1.pbxVersionInfoClick(Sender: TObject); begin SpOpenLink(rvMultiInstallerLink); end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM -{ Actions } +{$REGION 'Actions'} procedure TForm1.aBackExecute(Sender: TObject); begin @@ -324,7 +404,7 @@ procedure TForm1.aFinishExecute(Sender: TObject); procedure TForm1.aSaveLogExecute(Sender: TObject); begin if SaveDialog1.Execute then - LogMemo.Lines.SaveToFile(SaveDialog1.FileName); + memInstallationLog.Lines.SaveToFile(SaveDialog1.FileName); end; procedure TForm1.aBrowseExecute(Sender: TObject); @@ -332,20 +412,22 @@ procedure TForm1.aBrowseExecute(Sender: TObject); D: string; begin if SpSelectDirectory('', D) then - InstallFolderEdit.Text := D; + edtInstallFolder.Text := D; end; +{$ENDREGION 'Actions'} + //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM + { Install } procedure TForm1.CloseDelphi; var Cancel: Boolean; begin - {$IFDEF SPDEBUGMODE} +{$IFDEF SPDEBUGMODE} Exit; - {$ENDIF} - +{$ENDIF} Cancel := False; while not Cancel and ((FindWindow('TAppBuilder', nil) <> 0) or (FindWindow('TAppBuilder', nil) <> 0)) do Cancel := MessageDlg(SCloseDelphi, mtWarning, [mbOK, mbCancel], 0) = mrCancel; @@ -356,35 +438,37 @@ procedure TForm1.CloseDelphi; function TForm1.Install: Boolean; var I, J, G: Integer; - IDE: TSpIDEType; + IDE : TSpIDEType; begin Result := False; CloseDelphi; // Get IDE version IDE := ideNone; - I := RadioGroup1.ItemIndex; - if (CompileCheckbox.Checked) and (I > -1) and Assigned(RadioGroup1.Items.Objects[I]) then - IDE := TSpIDEType(RadioGroup1.Items.Objects[I]); + I := rgSelectIde.ItemIndex; + if chkCompileInIde.Checked and (I > -1) and Assigned(rgSelectIde.Items.Objects[I]) then + IDE := TSpIDEType(rgSelectIde.Items.Objects[I]); // Delete unchecked components from the ComponentPackages list - for I := 0 to CheckListBox1.Count - 1 do - if not CheckListBox1.Checked[I] then begin - G := Integer(CheckListBox1.Items.Objects[I]); - for J := Installer.ComponentPackages.Count - 1 downto 0 do - if (G > 0) and (Installer.ComponentPackages[J].GroupIndex = G) then - Installer.ComponentPackages.Delete(J) - else - if CheckListBox1.items[I].Contains(Installer.ComponentPackages[J].Name) then - Installer.ComponentPackages.Delete(J); - end; + for I := 0 to clbSelectComponents.Count - 1 do + if not clbSelectComponents.Checked[I] then + begin + G := Integer(clbSelectComponents.Items.Objects[I]); + for J := FInstaller.ComponentPackages.Count - 1 downto 0 do + if (G > 0) and (FInstaller.ComponentPackages[J].GroupIndex = G) then + FInstaller.ComponentPackages.Delete(J) + else + if clbSelectComponents.Items[I].Contains(FInstaller.ComponentPackages[J].Name) then + FInstaller.ComponentPackages.Delete(J); + end; // Prioritize GIT over ZIP - if CheckBox1.Checked then begin - for J := 0 to Installer.ComponentPackages.Count - 1 do - if not Installer.ComponentPackages[J].Git.IsEmpty then - Installer.ComponentPackages[J].ZipFile := ''; - end; + if chkGetFromGit.Checked then + begin + for J := 0 to FInstaller.ComponentPackages.Count - 1 do + if not FInstaller.ComponentPackages[J].Git.IsEmpty then + FInstaller.ComponentPackages[J].ZipFile := ''; + end; aFinish.Visible := True; aSaveLog.Visible := True; @@ -394,17 +478,18 @@ function TForm1.Install: Boolean; Application.ProcessMessages; try // Check, Unzip, Patch, Compile, Install - if Installer.Install(AppPath, InstallFolderEdit.Text, IDE, LogMemo.Lines) then + if FInstaller.Install(FAppPath, edtInstallFolder.Text, IDE, memInstallationLog.Lines) then Result := True; finally - LabelTitle.Caption := SFinishTitle; + lblTitle.Caption := SFinishTitle; aFinish.Enabled := True; aSaveLog.Enabled := True; - if not Result then begin - FinishLabel.Font.Color := clRed; - FinishLabel.Caption := SErrorLabel; - end; - FinishLabel.Visible := True; + if not Result then + begin + lblInstallationFinished.Font.Color := clRed; + lblInstallationFinished.Caption := SErrorLabel; + end; + lblInstallationFinished.Visible := True; end; end; From 41e4ef25257ef8286fc99bfc4959db0c75cad64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Wed, 13 Aug 2025 10:18:53 +0200 Subject: [PATCH 02/19] Rename the installer main form --- Source/{unit1.dfm => Form.Installer.dfm} | 0 Source/{unit1.pas => Form.Installer.pas} | 2 +- Source/MultiInstaller.dpr | 2 +- Source/MultiInstaller.dproj | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename Source/{unit1.dfm => Form.Installer.dfm} (100%) rename Source/{unit1.pas => Form.Installer.pas} (96%) diff --git a/Source/unit1.dfm b/Source/Form.Installer.dfm similarity index 100% rename from Source/unit1.dfm rename to Source/Form.Installer.dfm diff --git a/Source/unit1.pas b/Source/Form.Installer.pas similarity index 96% rename from Source/unit1.pas rename to Source/Form.Installer.pas index 69b3400..8d0e6e2 100644 --- a/Source/unit1.pas +++ b/Source/Form.Installer.pas @@ -1,4 +1,4 @@ -unit Unit1; +unit Form.Installer; interface diff --git a/Source/MultiInstaller.dpr b/Source/MultiInstaller.dpr index 951a3cf..0368fb3 100644 --- a/Source/MultiInstaller.dpr +++ b/Source/MultiInstaller.dpr @@ -2,7 +2,7 @@ program MultiInstaller; uses Forms, - unit1 in 'unit1.pas' {Form1}; + Form.Installer in 'Form.Installer.pas' {Form1}; {$R *.res} diff --git a/Source/MultiInstaller.dproj b/Source/MultiInstaller.dproj index 8d23e47..1572fb7 100644 --- a/Source/MultiInstaller.dproj +++ b/Source/MultiInstaller.dproj @@ -127,7 +127,7 @@ MainSource - +
Form1
From e2385ce1fd5efc52da5959713d1ad26cf62cc411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Wed, 13 Aug 2025 11:17:46 +0200 Subject: [PATCH 03/19] Rename the form itself, fix typo Allow to pass the setup ini file name on the command line Allow to turn off autostart via the command line --- Source/Form.Installer.dfm | 4 +-- Source/Form.Installer.pas | 72 ++++++++++++++++++++++--------------- Source/MultiInstaller.dpr | 4 +-- Source/MultiInstaller.dproj | 3 +- 4 files changed, 50 insertions(+), 33 deletions(-) diff --git a/Source/Form.Installer.dfm b/Source/Form.Installer.dfm index 9d2b592..033efe6 100644 --- a/Source/Form.Installer.dfm +++ b/Source/Form.Installer.dfm @@ -1,4 +1,4 @@ -object Form1: TForm1 +object FormInstall: TFormInstall Left = 293 Top = 145 BorderStyle = bsDialog @@ -100,7 +100,7 @@ object Form1: TForm1 Top = 78 Width = 195 Height = 17 - Caption = 'Compile packages and install on IDE' + Caption = 'Compile packages and install in IDE' TabOrder = 3 OnClick = chkCompileInIdeClick end diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index 8d0e6e2..6f3e73d 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -28,7 +28,7 @@ interface SpComponentInstaller; type - TForm1 = class(TForm) + TFormInstall = class(TForm) PageControl1: TPageControl; tshSelectComponents: TTabSheet; tshSelectIde: TTabSheet; @@ -85,6 +85,7 @@ TForm1 = class(TForm) procedure pbxVersionInfoClick(Sender: TObject); private FAppPath : string; + FAutoStart: boolean; FInstaller: TSpMultiInstaller; function ChangePage(Next: Boolean): Boolean; @@ -99,7 +100,7 @@ TForm1 = class(TForm) end; var - Form1: TForm1; + FormInstall: TFormInstall; implementation @@ -108,6 +109,7 @@ implementation uses Winapi.ShellAPI, + System.StrUtils, System.SysUtils, System.UITypes; @@ -130,7 +132,10 @@ implementation //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { Form UI } -procedure TForm1.FormCreate(Sender: TObject); +procedure TFormInstall.FormCreate(Sender: TObject); +var + LAutoStart: string; + LSetupIni : string; begin Screen.Cursors[crIDC_HAND] := LoadCursor(0, IDC_HAND); pbxVersionInfo.Cursor := crIDC_HAND; @@ -142,26 +147,36 @@ procedure TForm1.FormCreate(Sender: TObject); lblTitle.Caption := SWelcomeTitle; SaveDialog1.InitialDir := FAppPath; - CreateInstaller(FAppPath + rvSetupIni); + // Allow to turn the autostart off via command line. Default:on + if FindCmdLineswitch('A', LAutoStart) then + FAutoStart := MatchText(LautoStart, ['Yes', 'True', '1']) + else + FAutoStart := true; + + // Allow to pass the ini file via command line + if FindCmdLineswitch('I', LSetupIni) then + CreateInstaller(LSetupIni) + else + CreateInstaller(FAppPath + rvSetupIni); {$IFDEF SPDEBUGMODE} ReportMemoryLeaksOnShutdown := True; {$ENDIF} end; -procedure TForm1.FormDestroy(Sender: TObject); +procedure TFormInstall.FormDestroy(Sender: TObject); begin FInstaller.Free; end; -procedure TForm1.FormShow(Sender: TObject); +procedure TFormInstall.FormShow(Sender: TObject); begin CloseDelphi; if DirectoryExists(FInstaller.ComponentPackages.DefaultInstallFolder) then begin edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; - if chkCompileInIde.Checked then + if FAutoStart and chkCompileInIde.Checked then begin PageControl1.ActivePageIndex := PageControl1.PageCount - 1; Timer1.Enabled := True; // Delay it a little for UI responsiveness @@ -169,13 +184,13 @@ procedure TForm1.FormShow(Sender: TObject); end; end; -procedure TForm1.Timer1Timer(Sender: TObject); +procedure TFormInstall.Timer1Timer(Sender: TObject); begin Timer1.Enabled := False; Install; end; -function TForm1.ChangePage(Next: Boolean): Boolean; +function TFormInstall.ChangePage(Next: Boolean): Boolean; var I, C: Integer; begin @@ -222,12 +237,12 @@ function TForm1.ChangePage(Next: Boolean): Boolean; end; end; -procedure TForm1.chkCompileInIdeClick(Sender: TObject); +procedure TFormInstall.chkCompileInIdeClick(Sender: TObject); begin rgSelectIde.Enabled := chkCompileInIde.Checked; end; -procedure TForm1.CreateInstaller(const APath: string); +procedure TFormInstall.CreateInstaller(const APath: string); begin FreeAndNil(FInstaller); @@ -240,7 +255,7 @@ procedure TForm1.CreateInstaller(const APath: string); edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; end; -procedure TForm1.FillCheckListBox; +procedure TFormInstall.FillCheckListBox; var I, G, P: Integer; begin @@ -269,7 +284,7 @@ procedure TForm1.FillCheckListBox; end; end; -procedure TForm1.FillRadioGroup; +procedure TFormInstall.FillRadioGroup; var IDE: TSpIDEType; begin @@ -291,7 +306,7 @@ procedure TForm1.FillRadioGroup; chkCompileInIde.Checked := True; end; -function TForm1.ValidateCheckListBox: Boolean; +function TFormInstall.ValidateCheckListBox: Boolean; var I: Integer; begin @@ -306,7 +321,7 @@ function TForm1.ValidateCheckListBox: Boolean; btnNext.Enabled := Result; end; -procedure TForm1.WMDROPFILES(var Msg: TWMDropFiles); +procedure TFormInstall.WMDROPFILES(var Msg: TWMDropFiles); var LDropHandle : HDROP; FileNameLength: Integer; @@ -336,12 +351,12 @@ procedure TForm1.WMDROPFILES(var Msg: TWMDropFiles); end; end; -procedure TForm1.clbSelectComponentsClickCheck(Sender: TObject); +procedure TFormInstall.clbSelectComponentsClickCheck(Sender: TObject); begin ValidateCheckListBox; end; -procedure TForm1.clbSelectComponentsMeasureItem(Control: TWinControl; +procedure TFormInstall.clbSelectComponentsMeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); var R: TRect; @@ -350,7 +365,7 @@ procedure TForm1.clbSelectComponentsMeasureItem(Control: TWinControl; Height := DrawText(clbSelectComponents.Canvas.Handle, PChar(clbSelectComponents.Items[Index]), -1, R, DT_CALCRECT) + 4; end; -procedure TForm1.clbSelectComponentsDrawItem(Control: TWinControl; +procedure TFormInstall.clbSelectComponentsDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); begin if Index > -1 then @@ -361,7 +376,7 @@ procedure TForm1.clbSelectComponentsDrawItem(Control: TWinControl; end; end; -procedure TForm1.pbxVersionInfoPaint(Sender: TObject); +procedure TFormInstall.pbxVersionInfoPaint(Sender: TObject); var C: TCanvas; begin @@ -373,7 +388,7 @@ procedure TForm1.pbxVersionInfoPaint(Sender: TObject); C.TextOut(0, 0, rvMultiInstallerVersion); end; -procedure TForm1.pbxVersionInfoClick(Sender: TObject); +procedure TFormInstall.pbxVersionInfoClick(Sender: TObject); begin SpOpenLink(rvMultiInstallerLink); end; @@ -381,33 +396,34 @@ procedure TForm1.pbxVersionInfoClick(Sender: TObject); //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM {$REGION 'Actions'} -procedure TForm1.aBackExecute(Sender: TObject); + +procedure TFormInstall.aBackExecute(Sender: TObject); begin ChangePage(False); end; -procedure TForm1.aNextExecute(Sender: TObject); +procedure TFormInstall.aNextExecute(Sender: TObject); begin ChangePage(True); end; -procedure TForm1.aCancelExecute(Sender: TObject); +procedure TFormInstall.aCancelExecute(Sender: TObject); begin Close; end; -procedure TForm1.aFinishExecute(Sender: TObject); +procedure TFormInstall.aFinishExecute(Sender: TObject); begin Close; end; -procedure TForm1.aSaveLogExecute(Sender: TObject); +procedure TFormInstall.aSaveLogExecute(Sender: TObject); begin if SaveDialog1.Execute then memInstallationLog.Lines.SaveToFile(SaveDialog1.FileName); end; -procedure TForm1.aBrowseExecute(Sender: TObject); +procedure TFormInstall.aBrowseExecute(Sender: TObject); var D: string; begin @@ -421,7 +437,7 @@ procedure TForm1.aBrowseExecute(Sender: TObject); { Install } -procedure TForm1.CloseDelphi; +procedure TFormInstall.CloseDelphi; var Cancel: Boolean; begin @@ -435,7 +451,7 @@ procedure TForm1.CloseDelphi; Close; end; -function TForm1.Install: Boolean; +function TFormInstall.Install: Boolean; var I, J, G: Integer; IDE : TSpIDEType; diff --git a/Source/MultiInstaller.dpr b/Source/MultiInstaller.dpr index 0368fb3..2b78306 100644 --- a/Source/MultiInstaller.dpr +++ b/Source/MultiInstaller.dpr @@ -2,13 +2,13 @@ program MultiInstaller; uses Forms, - Form.Installer in 'Form.Installer.pas' {Form1}; + Form.Installer in 'Form.Installer.pas' {FormInstall}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; - Application.CreateForm(TForm1, Form1); + Application.CreateForm(TFormInstall, FormInstall); Application.Run; end. diff --git a/Source/MultiInstaller.dproj b/Source/MultiInstaller.dproj index 1572fb7..7667773 100644 --- a/Source/MultiInstaller.dproj +++ b/Source/MultiInstaller.dproj @@ -118,6 +118,7 @@ true true MultiInstaller_Icon.ico + -I:D:\Projekte\DiagRA-MCD\trunk\Build\Tools\Multiinstaller.ini -a:off
true @@ -128,7 +129,7 @@ MainSource -
Form1
+
FormInstall
Base From 44c82ce5ec2c72fe0cb6618dfbdc3bd1f0c2e869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Wed, 13 Aug 2025 14:59:27 +0200 Subject: [PATCH 04/19] Allow the default installation folder to be a relative path Use TPath.GetFullPath to make relative paths more readable when they are converted into absolute paths Emit a separate error message when registering the package fails --- Source/MultiInstaller.dproj | 1 - Source/SpComponentInstaller.pas | 33 +++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Source/MultiInstaller.dproj b/Source/MultiInstaller.dproj index 7667773..43813ce 100644 --- a/Source/MultiInstaller.dproj +++ b/Source/MultiInstaller.dproj @@ -118,7 +118,6 @@ true true MultiInstaller_Icon.ico - -I:D:\Projekte\DiagRA-MCD\trunk\Build\Tools\Multiinstaller.ini -a:off
true diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index 4c85f10..e538f7d 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -70,6 +70,7 @@ interface SLogErrorDeleting = 'Error deleting %s'; SLogErrorExecuting = 'Error executing %s'; SLogErrorCompiling = 'Error compiling %s'; + SLogErrorRegistering = 'Error registering %s'; SLogCopying = 'Copying:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; SLogExecuting = 'Executing:' + #13#10 + ' %s'; @@ -1175,8 +1176,10 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, L: TStringList; I: Integer; S, R: string; // Auxiliary strings + LError: string; begin Result := False; + LError := ''; if FIDEVersion = ideNone then Exit; if not Exists then begin if Assigned(Log) then @@ -1282,14 +1285,20 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, if Assigned(Log) then Log.Text := Log.Text + DosOutput + #13#10; if Result then - Result := RegisterPackage(Log); + begin + Result := RegisterPackage(Log); + if not Result then + LError := SLogErrorRegistering; + end + else + LError := SLogErrorCompiling; finally DeleteFile(DCCConfig); end; end; if not Result and Assigned(Log) then - SpWriteLog(Log, SLogErrorCompiling, FDPKFilename, ''); + SpWriteLog(Log, LError, FDPKFilename, ''); end; function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; @@ -1356,6 +1365,22 @@ destructor TSpComponentPackage.Destroy; { TSpComponentPackageList } procedure TSpComponentPackageList.LoadFromIni(Filename: string); + + function MakeAbsolutePath(APath:string):string; + var + LPath:string; + begin + // Allow to specify the installation path relative to the .ini file + if TPath.IsRelativePath(APath) then + begin + LPath := TPath.GetDirectoryName(FileName); + LPath := TPath.Combine([LPath, APath]); + Result := TPath.GetFullPath(LPath); + end + else + Result := APath; + end; + var F: TMemIniFile; LSections: TStringList; @@ -1373,7 +1398,7 @@ procedure TSpComponentPackageList.LoadFromIni(Filename: string); // Read Options S := F.ReadString(rvOptionsIniSection, rvDefaultInstallIDE, ''); FDefaultInstallIDE := TSpDelphiIDE.StringToIDEType(S); - FDefaultInstallFolder := F.ReadString(rvOptionsIniSection, rvDefaultInstallFolder, ''); + FDefaultInstallFolder := MakeAbsolutePath(F.ReadString(rvOptionsIniSection, rvDefaultInstallFolder, '')); S := F.ReadString(rvOptionsIniSection, rvMinimumIDE, ''); FMinimumIDE := TSpDelphiIDE.StringToIDEType(S); if FMinimumIDE = ideNone then @@ -1535,7 +1560,7 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; SourcesL.CommaText := Item.SearchPath; // Add the destination search path for J := 0 to SourcesL.Count - 1 do - SourcesL[J] := TPath.Combine(Item.Destination, SourcesL[J]); + SourcesL[J] := TPath.GetFullPath(TPath.Combine(Item.Destination, SourcesL[J])); end else SourcesL.Add(Item.Destination); From 3d8079fc043a8129a6e72dcb1df09153c746f19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Wed, 13 Aug 2025 15:20:50 +0200 Subject: [PATCH 05/19] Update Readme.md --- Readme.md | 31 ++++++++++++++++++++----------- Source/MultiInstaller.dproj | 2 +- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Readme.md b/Readme.md index 845294f..87b0ab5 100644 --- a/Readme.md +++ b/Readme.md @@ -7,42 +7,52 @@ Silverpoint MultiInstaller can help you install multiple component packs in a fe Just download the zips and select the destination folder, all the components will be uninstalled from the IDE if they were previously installed, unziped, patched, compiled and installed. It can also install multiple packages directly from GIT repositories. +For more info go to: -For more info go to: -www.silverpointdevelopment.com +## Changes in this version +This fork features some useful additions: + +- The setup .ini file can be dragged and dropped onto the installer form. + Default: use the setup.ini file from the same folder as the installer executable. +- The setup .ini file can be passed via the `-I:Setup.ini` command line switch. + Default: use the setup.ini file from the same folder as the installer executable. +- Autostarting the installer can be turned off via the `-A:off|false|0` command line switch. + Default: on. +- The default installation folder `DefaultInstallFolder` can be relative to the setup .ini file. ## License The contents of this package are licensed under a disjunctive tri-license giving you the choice of one of the three following sets of free software/open source licensing terms: - - Mozilla Public License, version 1.1 - http://www.mozilla.org/MPL/MPL-1.1.html - - GNU General Public License, version 2.0 - http://www.gnu.org/licenses/gpl-2.0.html - - GNU Lesser General Public License, version 2.1 - http://www.gnu.org/licenses/lgpl-2.1.html +- Mozilla Public License, version 1.1 + +- GNU General Public License, version 2.0 + +- GNU Lesser General Public License, version 2.1 + Software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. The initial developer of this package is Robert Lee. - ## Installation Requirements: -- RAD Studio XE or newer +- RAD Studio XE or newer ## Getting Started To install a component pack with MultiInstaller you have to follow these steps: + 1) Read the licenses of the component packs you want to install. 2) Get the zip files of component packs. 3) Get the Silverpoint MultiInstaller. 4) Get the Setup.ini file for that component pack installation or create one. For example, if you want to install TB2K + SpTBXLib: + 1) Create a new folder for the installation. 2) Download all the component zips to the created folder: SpTBXLib + TB2K + TB2K Patch 3) Download the MultiInstaller @@ -60,4 +70,3 @@ C:\MyInstall ``` You are ready to install the component packages, just run the MultiInstaller, select the destination folder, and all the components will be unziped, patched, compiled and installed on the Delphi IDE. - diff --git a/Source/MultiInstaller.dproj b/Source/MultiInstaller.dproj index 43813ce..427923f 100644 --- a/Source/MultiInstaller.dproj +++ b/Source/MultiInstaller.dproj @@ -2,7 +2,7 @@ {EBF09947-4C9C-4019-AB2C-5AC10A4CEF07} MultiInstaller.dpr - Debug + Release DCC32 20.3 True From b2f0a07b3e9cf7fc2a26604e7d40fe2657c83bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Wed, 13 Aug 2025 15:22:37 +0200 Subject: [PATCH 06/19] Update Readme.md --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 87b0ab5..4ef636a 100644 --- a/Readme.md +++ b/Readme.md @@ -11,12 +11,12 @@ For more info go to: ## Changes in this version +By default the installer uses the setup.ini file from the same folder as the installer executable. + This fork features some useful additions: - The setup .ini file can be dragged and dropped onto the installer form. - Default: use the setup.ini file from the same folder as the installer executable. - The setup .ini file can be passed via the `-I:Setup.ini` command line switch. - Default: use the setup.ini file from the same folder as the installer executable. - Autostarting the installer can be turned off via the `-A:off|false|0` command line switch. Default: on. - The default installation folder `DefaultInstallFolder` can be relative to the setup .ini file. From 03716488a93fab377c3dd5729a035adbd1969ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Mon, 1 Sep 2025 12:48:51 +0200 Subject: [PATCH 07/19] Enable the "Get from Git" checkbox only when Git resources are defined Change the "Installation folder" caption to make clear that the sources will be installed/copied into that folder. --- Source/Form.Installer.dfm | 9 ++++----- Source/Form.Installer.pas | 11 +++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Source/Form.Installer.dfm b/Source/Form.Installer.dfm index 033efe6..da8356b 100644 --- a/Source/Form.Installer.dfm +++ b/Source/Form.Installer.dfm @@ -21,7 +21,7 @@ object FormInstall: TFormInstall Top = 60 Width = 495 Height = 265 - ActivePage = tshInstallation + ActivePage = tshSelectComponents Align = alClient Style = tsFlatButtons TabOrder = 0 @@ -52,8 +52,7 @@ object FormInstall: TFormInstall Width = 249 Height = 17 Caption = 'Get files from GIT repository when available' - Checked = True - State = cbChecked + Enabled = False TabOrder = 1 end end @@ -64,11 +63,11 @@ object FormInstall: TFormInstall object lblInstallfolder: TLabel Left = 8 Top = 16 - Width = 323 + Width = 358 Height = 13 Caption = 'Select a destination directory to install all the component pack' + - 'ages:' + 'age sources:' end object edtInstallFolder: TEdit Left = 8 diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index 6f3e73d..ee2bdc0 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -243,6 +243,8 @@ procedure TFormInstall.chkCompileInIdeClick(Sender: TObject); end; procedure TFormInstall.CreateInstaller(const APath: string); +var + I: Integer; begin FreeAndNil(FInstaller); @@ -251,6 +253,15 @@ procedure TFormInstall.CreateInstaller(const APath: string); FillRadioGroup; ValidateCheckListBox; + // Enable Get from Git only when at least one component has a Git URL + for I := 0 to FInstaller.ComponentPackages.Count - 1 do + if not FInstaller.ComponentPackages[I].Git.IsEmpty then + begin + chkGetFromGit.Enabled := true; + chkGetFromGit.Checked := true; + break; + end; + if DirectoryExists(FInstaller.ComponentPackages.DefaultInstallFolder) then edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; end; From 3768ccc09cae4606877e7a295b963b13853d4c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Tue, 7 Oct 2025 16:58:41 +0200 Subject: [PATCH 08/19] Run source code formatter on SpComponentInstaller.pas --- Source/SpComponentInstaller.pas | 1348 +++++++++++++++++-------------- 1 file changed, 726 insertions(+), 622 deletions(-) diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index e538f7d..cc4123c 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -35,7 +35,7 @@ interface {$WARN SYMBOL_PLATFORM OFF} {$WARN UNIT_PLATFORM OFF} -{$BOOLEVAL OFF} // Unit depends on short-circuit boolean evaluation +{$BOOLEVAL OFF} // Unit depends on short-circuit boolean evaluation {$R 'SpComponentInstallerRes.res'} // Has EmptyResourceFile.res file as a resource used by TSpDelphiDPKFile.CreateAndCopyEmptyResIfNeeded @@ -43,19 +43,19 @@ interface Windows, Messages, SysUtils, Classes, Forms, Contnrs, Generics.Collections; resourcestring - SLogStartUnzip = '=========================================' + #13#10 + - 'Unzipping - Cloning' + #13#10 + - '========================================='; + SLogStartUnzip = '=========================================' + #13#10 + + 'Unzipping - Cloning' + #13#10 + + '========================================='; SLogStartExecute = '=========================================' + #13#10 + - 'Executing patches' + #13#10 + - '========================================='; + 'Executing patches' + #13#10 + + '========================================='; SLogStartCompile = '=========================================' + #13#10 + - 'Compiling and installing:' + #13#10 + - '%s' + #13#10 + - '========================================='; - SLogEnd = '=========================================' + #13#10 + - 'Finished' + #13#10 + - '========================================='; + 'Compiling and installing:' + #13#10 + + '%s' + #13#10 + + '========================================='; + SLogEnd = '=========================================' + #13#10 + + 'Finished' + #13#10 + + '========================================='; SLogInvalidPath = 'Error: %s doesn''t exist.'; SLogInvalidIDE = 'Error: %s is not installed.'; @@ -72,10 +72,10 @@ interface SLogErrorCompiling = 'Error compiling %s'; SLogErrorRegistering = 'Error registering %s'; - SLogCopying = 'Copying:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; - SLogExecuting = 'Executing:' + #13#10 + ' %s'; - SLogExtracting = 'Extracting:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; - SLogGitCloning = 'Git cloning:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; + SLogCopying = 'Copying:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; + SLogExecuting = 'Executing:' + #13#10 + ' %s'; + SLogExtracting = 'Extracting:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; + SLogGitCloning = 'Git cloning:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; SLogCompiling = 'Compiling Package: %s'; SLogInstalling = 'Installing Package: %s'; SLogFinished = 'All the component packages have been successfully installed.' + #13#10 + 'Elapsed time: %f secs.'; @@ -107,7 +107,7 @@ interface ideDelphiSydney, // D27 ideDelphiAlexandria, // D28 ideDelphiAthens // D29 - ); + ); TSpIDETypeRec = record IDEVersion: string; @@ -126,7 +126,7 @@ TSpIDETypeRec = record (IDEVersion: 'D11'; IDEName: 'RAD Studio 2007'; IDERegistryPath: 'SOFTWARE\Borland\BDS\5.0'; IDERADStudioVersion: '5.0'), (IDEVersion: 'D12'; IDEName: 'RAD Studio 2009'; IDERegistryPath: 'SOFTWARE\CodeGear\BDS\6.0'; IDERADStudioVersion: '6.0'), (IDEVersion: 'D14'; IDEName: 'RAD Studio 2010'; IDERegistryPath: 'SOFTWARE\CodeGear\BDS\7.0'; IDERADStudioVersion: '7.0'), - (IDEVersion: 'D15'; IDEName: 'RAD Studio XE'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\8.0'; IDERADStudioVersion: '8.0'), + (IDEVersion: 'D15'; IDEName: 'RAD Studio XE'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\8.0'; IDERADStudioVersion: '8.0'), (IDEVersion: 'D16'; IDEName: 'RAD Studio XE2'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\9.0'; IDERADStudioVersion: '9.0'), (IDEVersion: 'D17'; IDEName: 'RAD Studio XE3'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\10.0'; IDERADStudioVersion: '10.0'), (IDEVersion: 'D18'; IDEName: 'RAD Studio XE4'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\11.0'; IDERADStudioVersion: '11.0'), @@ -141,7 +141,7 @@ TSpIDETypeRec = record (IDEVersion: 'D27'; IDEName: 'RAD Studio 10.4 Sydney'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\21.0'; IDERADStudioVersion: '21.0'), (IDEVersion: 'D28'; IDEName: 'RAD Studio 11 Alexandria'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\22.0'; IDERADStudioVersion: '22.0'), (IDEVersion: 'D29'; IDEName: 'RAD Studio 12 Athens'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\23.0'; IDERADStudioVersion: '23.0') - ); + ); type TSpIDEPersonality = (persDelphiWin32, persDelphiNET, persCPPBuilder); @@ -149,7 +149,7 @@ TSpIDETypeRec = record TSpDelphiIDE = class private class var FCachedMacrosCommaDelimited: string; - class var FCachedMacrosIDE: TSpIDEType; + class var FCachedMacrosIDE : TSpIDEType; class procedure GetMacros(IDE: TSpIDEType; NamesAndValues: TStringList); public // IDE @@ -176,25 +176,25 @@ TSpDelphiIDE = class TSpDelphiDPKFile = class private - FDPKFilename: string; - FBPLFilename: string; - FExists: Boolean; - FOnlyRuntime: Boolean; + FDPKFilename : string; + FBPLFilename : string; + FExists : Boolean; + FOnlyRuntime : Boolean; FOnlyDesigntime: Boolean; - FDescription: string; - FLibSuffix: string; - FIDEVersion: TSpIDEType; + FDescription : string; + FLibSuffix : string; + FIDEVersion : TSpIDEType; procedure CreateAndCopyEmptyResIfNeeded; function RegisterPackage(Log: TStrings): Boolean; public - property DPKFilename: string read FDPKFilename; - property BPLFilename: string read FBPLFilename; - property Exists: Boolean read FExists; - property OnlyRuntime: Boolean read FOnlyRuntime; - property OnlyDesigntime : Boolean read FOnlyDesigntime; - property Description: string read FDescription; - property LibSuffix: string read FLibSuffix; - property IDEVersion: TSpIDEType read FIDEVersion; + property DPKFilename : string read FDPKFilename; + property BPLFilename : string read FBPLFilename; + property Exists : Boolean read FExists; + property OnlyRuntime : Boolean read FOnlyRuntime; + property OnlyDesigntime: Boolean read FOnlyDesigntime; + property Description : string read FDescription; + property LibSuffix : string read FLibSuffix; + property IDEVersion : TSpIDEType read FIDEVersion; constructor Create(const Filename: string; IDE: TSpIDEType); virtual; function CompilePackage(DCC: string; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; end; @@ -210,12 +210,12 @@ TSpDelphiDPKFilesList = class(TObjectList) TSpExecuteEntry = class private - FAction: TSpActionType; - FOrigin: string; - FDestination: string; + FAction : TSpActionType; + FOrigin : string; + FDestination : string; public - property Action: TSpActionType read FAction write FAction; - property Origin: string read FOrigin write FOrigin; + property Action : TSpActionType read FAction write FAction; + property Origin : string read FOrigin write FOrigin; property Destination: string read FDestination write FDestination; end; @@ -242,9 +242,9 @@ TSpComponentPackage = class TSpComponentPackageList = class(TObjectList) private - FDefaultInstallIDE: TSpIDEType; + FDefaultInstallIDE : TSpIDEType; FDefaultInstallFolder: string; - FMinimumIDE: TSpIDEType; + FMinimumIDE : TSpIDEType; public procedure LoadFromIni(Filename: string); function ExtractAllZips(Source, Destination: string; Log: TStrings): Boolean; @@ -258,7 +258,7 @@ TSpComponentPackageList = class(TObjectList) TSpMultiInstaller = class protected FComponentPackages: TSpComponentPackageList; - FInstalling: Boolean; + FInstalling : Boolean; public constructor Create(IniFilename: string); virtual; destructor Destroy; override; @@ -305,22 +305,22 @@ implementation Xml.XMLIntf, Xml.XMLDoc, themes; const - rvCount = 'Count'; - rvPackageIniSectionPrefix = 'Package -'; - rvName = 'Name'; - rvZip = 'Zip'; - rvGit = 'Git'; - rvFolder = 'Folder'; - rvSearchPath = 'SearchPath'; - rvGroupIndex = 'GroupIndex'; - rvIncludes = 'Includes'; - rvInstallable = 'Installable'; - rvExecuteIniPrefix = 'Execute'; - rvBaseFolder = '$BaseFolder'; - rvOptionsIniSection = 'Options'; - rvDefaultInstallIDE = 'DefaultInstallIDE'; - rvDefaultInstallFolder = 'DefaultInstallFolder'; - rvMinimumIDE = 'MinimumIDEVersion'; + rvCount = 'Count'; + rvPackageIniSectionPrefix = 'Package -'; + rvName = 'Name'; + rvZip = 'Zip'; + rvGit = 'Git'; + rvFolder = 'Folder'; + rvSearchPath = 'SearchPath'; + rvGroupIndex = 'GroupIndex'; + rvIncludes = 'Includes'; + rvInstallable = 'Installable'; + rvExecuteIniPrefix = 'Execute'; + rvBaseFolder = '$BaseFolder'; + rvOptionsIniSection = 'Options'; + rvDefaultInstallIDE = 'DefaultInstallIDE'; + rvDefaultInstallFolder = 'DefaultInstallFolder'; + rvMinimumIDE = 'MinimumIDEVersion'; ActionTypes: array [TSpActionType] of string = ('none', 'copy', 'copyandrun', 'run'); IDEPersonalityRegNameTypes: array [TSpIDEPersonality] of string = ('Delphi.Win32', 'Delphi.NET', 'BCB'); @@ -336,7 +336,7 @@ function SpStringSearch(S, SubStr: string; Delimiter: Char): Boolean; var L: TStringList; begin - L := TStringList.Create; + L := TStringList.Create; try L.StrictDelimiter := True; L.Delimiter := Delimiter; @@ -349,10 +349,11 @@ function SpStringSearch(S, SubStr: string; Delimiter: Char): Boolean; procedure SpWriteLog(Log: TStrings; ResourceS, Arg1: string; Arg2: string = ''); begin - if Assigned(Log) then begin - Log.Add(Format(ResourceS, [Arg1, Arg2])); - Log.Add(''); - end; + if Assigned(Log) then + begin + Log.Add(Format(ResourceS, [Arg1, Arg2])); + Log.Add(''); + end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -380,13 +381,13 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str // Do not use pipes and redirections in CommandLine (|, >, <) // Ported by Stephane Wierzbicki from JclSysUtils.InternalExecute const - BufferSize = 255; + BufferSize = 255; NativeLineFeed = Char(#10); NativeCarriageReturn = Char(#13); NativeCrLf = string(#13#10); var - Buffer: array [0..BufferSize] of AnsiChar; - TempOutput: string; + Buffer : array [0 .. BufferSize] of AnsiChar; + TempOutput : string; PipeBytesRead: Cardinal; function MuteCRTerminatedLines(const RawOutput: string): string; @@ -394,36 +395,36 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str Delta = 1024; var BufPos, OutPos, LfPos, EndPos: Integer; - C: Char; + C : Char; begin SetLength(Result, Length(RawOutput)); OutPos := 1; LfPos := OutPos; EndPos := OutPos; for BufPos := 1 to Length(RawOutput) do - begin - if OutPos >= Length(Result)-2 then - SetLength(Result, Length(Result) + Delta); - C := RawOutput[BufPos]; - case C of - NativeCarriageReturn: - OutPos := LfPos; - NativeLineFeed: - begin - OutPos := EndPos; - Result[OutPos] := NativeCarriageReturn; - Inc(OutPos); - Result[OutPos] := C; - Inc(OutPos); - EndPos := OutPos; - LfPos := OutPos; - end; - else - Result[OutPos] := C; - Inc(OutPos); - EndPos := OutPos; + begin + if OutPos >= Length(Result) - 2 then + SetLength(Result, Length(Result) + Delta); + C := RawOutput[BufPos]; + case C of + NativeCarriageReturn: + OutPos := LfPos; + NativeLineFeed: + begin + OutPos := EndPos; + Result[OutPos] := NativeCarriageReturn; + Inc(OutPos); + Result[OutPos] := C; + Inc(OutPos); + EndPos := OutPos; + LfPos := OutPos; + end; + else + Result[OutPos] := C; + Inc(OutPos); + EndPos := OutPos; + end; end; - end; SetLength(Result, OutPos - 1); end; @@ -435,10 +436,10 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str procedure ProcessLine(LineEnd: Integer); begin if (TempOutput[LineEnd] <> NativeCarriageReturn) then - begin - while (LineEnd > 0) and CharIsReturn(TempOutput[LineEnd]) do - Dec(LineEnd); - end; + begin + while (LineEnd > 0) and CharIsReturn(TempOutput[LineEnd]) do + Dec(LineEnd); + end; end; procedure ProcessBuffer; @@ -449,21 +450,21 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str // outsourced from Win32ExecAndRedirectOutput var - StartupInfo: TStartupInfo; - ProcessInfo: TProcessInformation; - SecurityAttr: TSecurityAttributes; + StartupInfo : TStartupInfo; + ProcessInfo : TProcessInformation; + SecurityAttr : TSecurityAttributes; PipeRead, PipeWrite: THandle; - PWorkDirChar : PChar; + PWorkDirChar : PChar; begin Result := $FFFFFFFF; SecurityAttr.nLength := SizeOf(SecurityAttr); SecurityAttr.lpSecurityDescriptor := nil; SecurityAttr.bInheritHandle := True; if not CreatePipe(PipeRead, PipeWrite, @SecurityAttr, 0) then - begin - Result := GetLastError; - Exit; - end; + begin + Result := GetLastError; + Exit; + end; FillChar(StartupInfo, SizeOf(TStartupInfo), #0); StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; @@ -472,22 +473,24 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str StartupInfo.hStdOutput := PipeWrite; StartupInfo.hStdError := PipeWrite; - if WorkDir = '' then PWorkDirChar := nil - else PWorkDirChar := PChar(WorkDir); + if WorkDir = '' then + PWorkDirChar := nil + else + PWorkDirChar := PChar(WorkDir); if CreateProcess(nil, PChar(CommandLine), nil, nil, True, NORMAL_PRIORITY_CLASS, nil, PWorkDirChar, StartupInfo, ProcessInfo) then - begin - CloseHandle(PipeWrite); + begin + CloseHandle(PipeWrite); - while ReadFile(PipeRead, Buffer, BufferSize, PipeBytesRead, nil) and (PipeBytesRead > 0) do - ProcessBuffer; - if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) = WAIT_OBJECT_0) and - not GetExitCodeProcess(ProcessInfo.hProcess, Result) then + while ReadFile(PipeRead, Buffer, BufferSize, PipeBytesRead, nil) and (PipeBytesRead > 0) do + ProcessBuffer; + if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) = WAIT_OBJECT_0) and + not GetExitCodeProcess(ProcessInfo.hProcess, Result) then Result := $FFFFFFFF; - CloseHandle(ProcessInfo.hThread); - CloseHandle(ProcessInfo.hProcess); - end + CloseHandle(ProcessInfo.hThread); + CloseHandle(ProcessInfo.hProcess); + end else CloseHandle(PipeWrite); CloseHandle(PipeRead); @@ -500,20 +503,21 @@ function SpFileOperation(Origin, Destination: string; Operation: Cardinal): Bool var F: TShFileOpStruct; begin - Result := False; + Result := False; // Operation can be: FO_COPY, FO_MOVE, FO_DELETE, FO_RENAME - if not (Operation in [FO_MOVE..FO_RENAME]) then Exit; - - Origin := Origin + #0#0; - Destination := Destination + #0#0; - - FillChar(F, SizeOf(F), #0); - F.Wnd := Application.Handle; - F.wFunc := Operation; - F.pFrom := PChar(Origin); - F.pTo := PChar(Destination); - F.fFlags := FOF_SILENT or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR; - Result := SHFileOperation(F) = 0; + if not(Operation in [FO_MOVE .. FO_RENAME]) then + Exit; + + Origin := Origin + #0#0; + Destination := Destination + #0#0; + + FillChar(F, SizeOf(F), #0); + F.Wnd := Application.Handle; + F.wFunc := Operation; + F.pFrom := PChar(Origin); + F.pTo := PChar(Destination); + F.fFlags := FOF_SILENT or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR; + Result := SHFileOperation(F) = 0; end; function SpSelectDirectory(Root: string; out Directory: string): Boolean; @@ -588,10 +592,11 @@ function SpReadRegValue(Key, Name: string; out Value: string): Boolean; try R.RootKey := HKEY_CURRENT_USER; if R.OpenKey(Key, False) then - if R.ValueExists(Name) then begin - Value := R.ReadString(Name); - Result := True; - end; + if R.ValueExists(Name) then + begin + Value := R.ReadString(Name); + Result := True; + end; finally R.Free; end; @@ -599,25 +604,27 @@ function SpReadRegValue(Key, Name: string; out Value: string): Boolean; function SpReadRegKey(Key: string; NamesAndValues: TStringList): Boolean; var - R: TRegistry; + R : TRegistry; Names: TStringList; - I: Integer; + I : Integer; begin Result := False; - if not Assigned(NamesAndValues) then Exit; + if not Assigned(NamesAndValues) then + Exit; NamesAndValues.Clear; R := TRegistry.Create; Names := TStringList.Create; try R.RootKey := HKEY_CURRENT_USER; - if R.OpenKey(Key, False) then begin - R.GetValueNames(Names); - for I := 0 to Names.Count - 1 do - if R.ValueExists(Names[I]) then - NamesAndValues.Values[Names[I]] := R.ReadString(Names[I]); - Result := True; - end; + if R.OpenKey(Key, False) then + begin + R.GetValueNames(Names); + for I := 0 to Names.Count - 1 do + if R.ValueExists(Names[I]) then + NamesAndValues.Values[Names[I]] := R.ReadString(Names[I]); + Result := True; + end; finally R.Free; Names.Free; @@ -632,10 +639,11 @@ function SpWriteRegValue(Key, Name, Value: string): Boolean; R := TRegistry.Create; try R.RootKey := HKEY_CURRENT_USER; - if R.OpenKey(Key, True) then begin - R.WriteString(Name, Value); - Result := True; - end; + if R.OpenKey(Key, True) then + begin + R.WriteString(Name, Value); + Result := True; + end; finally R.Free; end; @@ -643,10 +651,11 @@ function SpWriteRegValue(Key, Name, Value: string): Boolean; procedure SpIniLoadStringList(L: TStringList; IniFilename, Section: string; NamePrefix: string = ''); var - F: TMemIniFile; + F : TMemIniFile; I, C: integer; begin - if not Assigned(L) then Exit; + if not Assigned(L) then + Exit; F := TMemIniFile.Create(IniFilename); try L.Clear; @@ -663,16 +672,18 @@ procedure SpIniSaveStringList(L: TStringList; IniFilename, Section: string; Name F: TMemIniFile; I: integer; begin - if not Assigned(L) then Exit; + if not Assigned(L) then + Exit; F := TMemIniFile.Create(IniFilename); try F.EraseSection(Section); - if L.Count > 0 then begin - F.WriteInteger(Section, NamePrefix + rvCount, L.Count); - for I := 0 to L.Count - 1 do - F.WriteString(Section, NamePrefix + IntToStr(I), L[I]); - F.UpdateFile; - end; + if L.Count > 0 then + begin + F.WriteInteger(Section, NamePrefix + rvCount, L.Count); + for I := 0 to L.Count - 1 do + F.WriteString(Section, NamePrefix + IntToStr(I), L[I]); + F.UpdateFile; + end; finally F.Free; end; @@ -703,41 +714,47 @@ function SpStringToActionType(S: string): TSpActionType; Result := satNone; S := LowerCase(S); for A := Low(ActionTypes) to High(ActionTypes) do - if AnsiSameText(S, ActionTypes[A]) then begin - Result := A; - Exit; - end; + if AnsiSameText(S, ActionTypes[A]) then + begin + Result := A; + Exit; + end; end; procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuilderPath: Boolean); begin Key := ''; Name := ''; - if IDE = ideNone then Exit; + if IDE = ideNone then + Exit; // [IDE-Change] Key := IDETypes[IDE].IDERegistryPath; - if CPPBuilderPath and (IDE >= ideDelphi2006) then begin - if IDE = ideDelphi2006 then begin + if CPPBuilderPath and (IDE >= ideDelphi2006) then + begin + if IDE = ideDelphi2006 then + begin // '\CppPaths\SearchPath' with no space in the middle for C++Builder 2006 - Key := Key + '\CppPaths'; - Name := 'SearchPath'; + Key := Key + '\CppPaths'; + Name := 'SearchPath'; + end + else + begin + Name := 'LibraryPath'; + if IDE >= ideDelphiXE2 then + Key := Key + '\C++\Paths\Win32' // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above + else + Key := Key + '\C++\Paths'; // '\C++\Paths\LibraryPath' with no space in the middle for C++Builder 2009 and above + end; end - else begin - Name := 'LibraryPath'; + else + begin + Name := 'Search Path'; if IDE >= ideDelphiXE2 then - Key := Key + '\C++\Paths\Win32' // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above + Key := Key + '\Library\Win32' else - Key := Key + '\C++\Paths'; // '\C++\Paths\LibraryPath' with no space in the middle for C++Builder 2009 and above + Key := Key + '\Library'; end; - end - else begin - Name := 'Search Path'; - if IDE >= ideDelphiXE2 then - Key := Key + '\Library\Win32' - else - Key := Key + '\Library'; - end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -757,14 +774,16 @@ class function TSpDelphiIDE.PersonalityInstalled(IDE: TSpIDEType; S, PersReg: string; begin Result := False; - if IDE = ideNone then Exit; + if IDE = ideNone then + Exit; - if IDE >= ideDelphi2006 then begin - IDEPersonalityTypeToString(IDEPersonality, PersReg); - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Personalities', PersReg, S); - if S <> ''then - Result := True; - end; + if IDE >= ideDelphi2006 then + begin + IDEPersonalityTypeToString(IDEPersonality, PersReg); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Personalities', PersReg, S); + if S <> '' then + Result := True; + end; end; class function TSpDelphiIDE.StringToIDEType(S: string): TSpIDEType; @@ -773,10 +792,11 @@ class function TSpDelphiIDE.StringToIDEType(S: string): TSpIDEType; begin Result := ideNone; for A := Low(IDETypes) to High(IDETypes) do - if AnsiSameText(S, IDETypes[A].IDEVersion) then begin - Result := A; - Exit; - end; + if AnsiSameText(S, IDETypes[A].IDEVersion) then + begin + Result := A; + Exit; + end; end; class function TSpDelphiIDE.IDEPackageVersion(IDE: TSpIDEType): string; @@ -830,43 +850,54 @@ class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: // This file is used by MSBuild // https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-environment-variables-in-a-build?view=vs-2017 var - LStr: array[0 .. MAX_PATH] of Char; - Filename: string; - Doc: IXMLDocument; + LStr : array [0 .. MAX_PATH] of Char; + Filename : string; + Doc : IXMLDocument; Node, Root: IXMLNode; begin Result := False; - if not Assigned(NamesAndValues) or (IDE < ideDelphi2007) then Exit; + if not Assigned(NamesAndValues) or (IDE < ideDelphi2007) then + Exit; NamesAndValues.Clear; SetLastError(ERROR_SUCCESS); - if SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, @LStr) = S_OK then begin - Filename := TPath.Combine(LStr, 'Embarcadero\BDS\' + IDETypes[IDE].IDERADStudioVersion + '\environment.proj'); - if TFile.Exists(Filename) then begin - Doc := TXMLDocument.Create(Filename); - Root := Doc.ChildNodes.FindNode('Project'); - if Root <> nil then begin - Root := Root.ChildNodes.FindNode('PropertyGroup'); - if Root <> nil then begin + if SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, @LStr) = S_OK then + begin + Filename := TPath.Combine(LStr, 'Embarcadero\BDS\' + IDETypes[IDE].IDERADStudioVersion + '\environment.proj'); + if TFile.Exists(Filename) then + begin + Doc := TXMLDocument.Create(Filename); + Root := Doc.ChildNodes.FindNode('Project'); + if Root <> nil then + begin + Root := Root.ChildNodes.FindNode('PropertyGroup'); + if Root <> nil then + begin // Add $(Delphi), $(BDS), $(BDSPROJECTSDIR), $(BDSCOMMONDIR), // $(BDSUSERDIR), $(BDSLIB) macros - Node := Root.ChildNodes.FindNode('Delphi'); - if Node <> nil then NamesAndValues.AddPair('Delphi', Node.Text); - Node := Root.ChildNodes.FindNode('BDS'); - if Node <> nil then NamesAndValues.AddPair('BDS', Node.Text); - Node := Root.ChildNodes.FindNode('BDSPROJECTSDIR'); - if Node <> nil then NamesAndValues.AddPair('BDSPROJECTSDIR', Node.Text); - Node := Root.ChildNodes.FindNode('BDSCOMMONDIR'); - if Node <> nil then NamesAndValues.AddPair('BDSCOMMONDIR', Node.Text); - Node := Root.ChildNodes.FindNode('BDSUSERDIR'); - if Node <> nil then NamesAndValues.AddPair('BDSUSERDIR', Node.Text); - Node := Root.ChildNodes.FindNode('BDSLIB'); - if Node <> nil then NamesAndValues.AddPair('BDSLIB', Node.Text); - Result := True; + Node := Root.ChildNodes.FindNode('Delphi'); + if Node <> nil then + NamesAndValues.AddPair('Delphi', Node.Text); + Node := Root.ChildNodes.FindNode('BDS'); + if Node <> nil then + NamesAndValues.AddPair('BDS', Node.Text); + Node := Root.ChildNodes.FindNode('BDSPROJECTSDIR'); + if Node <> nil then + NamesAndValues.AddPair('BDSPROJECTSDIR', Node.Text); + Node := Root.ChildNodes.FindNode('BDSCOMMONDIR'); + if Node <> nil then + NamesAndValues.AddPair('BDSCOMMONDIR', Node.Text); + Node := Root.ChildNodes.FindNode('BDSUSERDIR'); + if Node <> nil then + NamesAndValues.AddPair('BDSUSERDIR', Node.Text); + Node := Root.ChildNodes.FindNode('BDSLIB'); + if Node <> nil then + NamesAndValues.AddPair('BDSLIB', Node.Text); + Result := True; + end; + end; end; - end; end; - end; end; class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringList); @@ -880,25 +911,27 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL begin Result := False; I := OverrideL.IndexOfName(Macro); - if I = -1 then begin - I := DefaultL.IndexOfName(Macro); - if I >= 0 then begin + if I = -1 then + begin + I := DefaultL.IndexOfName(Macro); + if I >= 0 then + begin // No override found, use default value - OverrideL.Values[Macro] := DefaultL.ValueFromIndex[I]; - Result := True; + OverrideL.Values[Macro] := DefaultL.ValueFromIndex[I]; + Result := True; + end; end; - end; end; const // English, German, French strings - DirArrayBDS: array [0..2] of string = ('Borland Studio Projects', 'Borland Studio-Projekte', 'Projets Borland Studio'); - DirArrayRAD: array [0..2] of string = ('Projects', 'Projekte', 'Projets'); + DirArrayBDS: array [0 .. 2] of string = ('Borland Studio Projects', 'Borland Studio-Projekte', 'Projets Borland Studio'); + DirArrayRAD: array [0 .. 2] of string = ('Projects', 'Projekte', 'Projets'); var R, MyDocs: string; - I: Integer; - DefaultL: TStringList; + I : Integer; + DefaultL : TStringList; begin // In newer versions of RAD Studio (2007 and up) the macros are stored in: // C:\Users\x\AppData\Roaming\Embarcadero\BDS\19.0\environment.proj @@ -910,7 +943,8 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL // So when the IDE is not running we can't use SysUtils.GetEnvironmentVariable. NamesAndValues.Clear; - if IDE = ideNone then Exit; + if IDE = ideNone then + Exit; DefaultL := TStringList.Create; try @@ -940,53 +974,63 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL // $(BDSPROJECTSDIR) // Example: C:\Users\x\Documents\Embarcadero\Studio\Projects - if IDE >= ideDelphi2005 then begin + if IDE >= ideDelphi2005 then + begin // This macro can be overrided by adding a string value called // 'DefaultProjectsDirectory' containing a different directory to: // HKCU\Software\Borland\BDS\4.0\Globals - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'DefaultProjectsDirectory', R); - if not TDirectory.Exists(R) then - if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSPROJECTSDIR') then begin + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'DefaultProjectsDirectory', R); + if not TDirectory.Exists(R) then + if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSPROJECTSDIR') then + begin // Try to guess it // Since BDSPROJECTSDIR is not defined in the registry we have to find it // manually, looking for all the localized dir names in MyDocuments folder - MyDocs := TPath.GetDocumentsPath; - if IDE in [ideDelphi2005, ideDelphi2006] then begin + MyDocs := TPath.GetDocumentsPath; + if IDE in [ideDelphi2005, ideDelphi2006] then + begin // For older BDS check if it's My Documents\Borland Studio Projects - for I := 0 to High(DirArrayBDS) do begin - R := TPath.Combine(MyDocs, DirArrayBDS[I]); - if TDirectory.Exists(R) then Break; - end; - end - else begin + for I := 0 to High(DirArrayBDS) do + begin + R := TPath.Combine(MyDocs, DirArrayBDS[I]); + if TDirectory.Exists(R) then + Break; + end; + end + else + begin // For newer versions check if it's C:\Users\x\Documents\Embarcadero\Studio\Projects // or C:\Users\x\Documents\RAD Studio\Projects - for I := 0 to High(DirArrayRAD) do begin - if IDE >= ideDelphiXE6 then - R := TPath.Combine(MyDocs, 'Embarcadero\Studio\' + DirArrayRAD[I]) - else - R := TPath.Combine(MyDocs, 'RAD Studio\' + DirArrayRAD[I]); - if TDirectory.Exists(R) then Break; + for I := 0 to High(DirArrayRAD) do + begin + if IDE >= ideDelphiXE6 then + R := TPath.Combine(MyDocs, 'Embarcadero\Studio\' + DirArrayRAD[I]) + else + R := TPath.Combine(MyDocs, 'RAD Studio\' + DirArrayRAD[I]); + if TDirectory.Exists(R) then + Break; + end; + end; + if TDirectory.Exists(R) then + NamesAndValues.Values['BDSPROJECTSDIR'] := R; end; - end; - if TDirectory.Exists(R) then - NamesAndValues.Values['BDSPROJECTSDIR'] := R; - end; - end; + end; // $(BDSUSERDIR) // Example: C:\Users\x\Documents\Embarcadero\Studio\19.0 if IDE >= ideDelphi2007 then - if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSUSERDIR') then begin + if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSUSERDIR') then + begin // Try to guess it // Get BDSPROJECTSDIR and add IDE version - R := NamesAndValues.Values['BDSPROJECTSDIR']; - if TDirectory.Exists(R) then begin - R := TPath.Combine(ExtractFilePath(R), IDETypes[IDE].IDERADStudioVersion); + R := NamesAndValues.Values['BDSPROJECTSDIR']; if TDirectory.Exists(R) then - NamesAndValues.Values['BDSUSERDIR'] := R; + begin + R := TPath.Combine(ExtractFilePath(R), IDETypes[IDE].IDERADStudioVersion); + if TDirectory.Exists(R) then + NamesAndValues.Values['BDSUSERDIR'] := R; + end; end; - end; // $(BDSLIB) // Example: C:\Program Files\Embarcadero\Studio\19.0\lib @@ -1015,12 +1059,13 @@ class function TSpDelphiIDE.ExpandMacros(S: string; IDE: TSpIDEType): string; L: TStringList; begin Result := S; - if IDE = ideNone then Exit; + if IDE = ideNone then + Exit; L := TStringList.Create; try if (FCachedMacrosIDE = IDE) and not FCachedMacrosCommaDelimited.IsEmpty then - L.CommaText := FCachedMacrosCommaDelimited // use the cached macros + L.CommaText := FCachedMacrosCommaDelimited // use the cached macros else GetMacros(IDE, L); // Replace all @@ -1037,44 +1082,49 @@ class function TSpDelphiIDE.GetSearchPath(IDE: TSpIDEType; Key, Name: string; begin Result := ''; - if IDE <> ideNone then begin - SpIDESearchPathRegKey(IDE, Key, Name, CPPBuilderPath); - SpReadRegValue(Key, Name, Result); - end; + if IDE <> ideNone then + begin + SpIDESearchPathRegKey(IDE, Key, Name, CPPBuilderPath); + SpReadRegValue(Key, Name, Result); + end; end; class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType); var - I : Integer; + I : Integer; S, Key, Name: string; begin - for I := 0 to SourcesL.Count - 1 do begin - SourcesL[I] := ExpandMacros(ExcludeTrailingPathDelimiter(SourcesL[I]), IDE); + for I := 0 to SourcesL.Count - 1 do + begin + SourcesL[I] := ExpandMacros(ExcludeTrailingPathDelimiter(SourcesL[I]), IDE); // Add the directory to the Delphi Win32 search path registry entry - S := GetSearchPath(IDE, False); - if (S <> '') and (SourcesL[I] <> '') then - if not SpStringSearch(S, SourcesL[I]) then begin - if S[Length(S)] <> ';' then - S := S + ';'; - S := S + SourcesL[I]; - SpIDESearchPathRegKey(IDE, Key, Name, False); - SpWriteRegValue(Key, Name, S) - end; + S := GetSearchPath(IDE, False); + if (S <> '') and (SourcesL[I] <> '') then + if not SpStringSearch(S, SourcesL[I]) then + begin + if S[Length(S)] <> ';' then + S := S + ';'; + S := S + SourcesL[I]; + SpIDESearchPathRegKey(IDE, Key, Name, False); + SpWriteRegValue(Key, Name, S) + end; // Add the directory to the C++Builder search path registry entry - if IDE >= ideDelphi2006 then begin - S := GetSearchPath(IDE, True); - if (S <> '') and (SourcesL[I] <> '') then - if not SpStringSearch(S, SourcesL[I]) then begin - if S[Length(S)] <> ';' then - S := S + ';'; - S := S + SourcesL[I]; - SpIDESearchPathRegKey(IDE, Key, Name, True); - SpWriteRegValue(Key, Name, S) + if IDE >= ideDelphi2006 then + begin + S := GetSearchPath(IDE, True); + if (S <> '') and (SourcesL[I] <> '') then + if not SpStringSearch(S, SourcesL[I]) then + begin + if S[Length(S)] <> ';' then + S := S + ';'; + S := S + SourcesL[I]; + SpIDESearchPathRegKey(IDE, Key, Name, True); + SpWriteRegValue(Key, Name, S) + end; end; end; - end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -1082,7 +1132,7 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType constructor TSpDelphiDPKFile.Create(const Filename: string; IDE: TSpIDEType); var - L: TStringList; + L : TStringList; P, P2: Integer; begin FDPKFilename := ''; @@ -1094,54 +1144,60 @@ constructor TSpDelphiDPKFile.Create(const Filename: string; IDE: TSpIDEType); FLibSuffix := ''; FIDEVersion := IDE; - if TFile.Exists(Filename) then begin - FDPKFilename := Filename; - FBPLFilename := TPath.ChangeExtension(TPath.GetFileName(Filename), 'bpl'); - - L := TStringList.Create; - try - L.LoadFromFile(Filename); - P := Pos('{$RUNONLY}', L.Text); - if P > 0 then - FOnlyRuntime := True; - P := Pos('{$DESIGNONLY}', L.Text); - if P > 0 then - FOnlyDesigntime := True; - P := Pos('{$DESCRIPTION ''', L.Text); // {$DESCRIPTION 'Package Description'} - if P > 0 then begin - P := P + Length('{$DESCRIPTION '''); - P2 := PosEx('''}', L.Text, P); - if P2 > 0 then - FDescription := Copy(L.Text, P, P2 - P); - end; + if TFile.Exists(Filename) then + begin + FDPKFilename := Filename; + FBPLFilename := TPath.ChangeExtension(TPath.GetFileName(Filename), 'bpl'); + + L := TStringList.Create; + try + L.LoadFromFile(Filename); + P := Pos('{$RUNONLY}', L.Text); + if P > 0 then + FOnlyRuntime := True; + P := Pos('{$DESIGNONLY}', L.Text); + if P > 0 then + FOnlyDesigntime := True; + P := Pos('{$DESCRIPTION ''', L.Text); // {$DESCRIPTION 'Package Description'} + if P > 0 then + begin + P := P + Length('{$DESCRIPTION '''); + P2 := PosEx('''}', L.Text, P); + if P2 > 0 then + FDescription := Copy(L.Text, P, P2 - P); + end; // Try to parse $LIBSUFFIX // Won't work if there are nested $IFDEFs, for example: // {$IFDEF VER340} {$LIBSUFFIX '270'} {$ENDIF} // {$IFDEF VER350} {$LIBSUFFIX '280'} {$ENDIF} // Delphi 10.4 Sydney added the AUTO option: {$LIBSUFFIX AUTO} - P := Pos('{$LIBSUFFIX AUTO}', L.Text); - if P > 0 then begin - FLibSuffix := 'AUTO'; - FBPLFilename := TPath.GetFileNameWithoutExtension(DPKFilename) + TSpDelphiIDE.IDEPackageVersion(IDE) + '.bpl'; - end - else begin - P := Pos('{$LIBSUFFIX ''', L.Text); // {$LIBSUFFIX '280'} for example: file280.bpl - if P > 0 then begin - P := P + Length('{$LIBSUFFIX '''); - P2 := PosEx('''}', L.Text, P); - if P2 > 0 then begin - FLibSuffix := Copy(L.Text, P, P2 - P); - FBPLFilename := TPath.GetFileNameWithoutExtension(DPKFilename) + FLibSuffix + '.bpl'; + P := Pos('{$LIBSUFFIX AUTO}', L.Text); + if P > 0 then + begin + FLibSuffix := 'AUTO'; + FBPLFilename := TPath.GetFileNameWithoutExtension(DPKFilename) + TSpDelphiIDE.IDEPackageVersion(IDE) + '.bpl'; + end + else + begin + P := Pos('{$LIBSUFFIX ''', L.Text); // {$LIBSUFFIX '280'} for example: file280.bpl + if P > 0 then + begin + P := P + Length('{$LIBSUFFIX '''); + P2 := PosEx('''}', L.Text, P); + if P2 > 0 then + begin + FLibSuffix := Copy(L.Text, P, P2 - P); + FBPLFilename := TPath.GetFileNameWithoutExtension(DPKFilename) + FLibSuffix + '.bpl'; + end; + end; end; - end; - end; - FExists := True; - finally - L.Free; + FExists := True; + finally + L.Free; + end; end; - end; end; procedure TSpDelphiDPKFile.CreateAndCopyEmptyResIfNeeded; @@ -1150,17 +1206,19 @@ procedure TSpDelphiDPKFile.CreateAndCopyEmptyResIfNeeded; FStream: TResourceStream; begin // Create and copy a res file if needed - if Exists then begin - ResFile := TPath.ChangeExtension(FDPKFilename, 'res'); - if not TFile.Exists(ResFile) then begin - FStream := TResourceStream.Create(HInstance, 'EMPTYRES', RT_RCDATA); - try - FStream.SaveToFile(ResFile); - finally - FStream.Free; - end; + if Exists then + begin + ResFile := TPath.ChangeExtension(FDPKFilename, 'res'); + if not TFile.Exists(ResFile) then + begin + FStream := TResourceStream.Create(HInstance, 'EMPTYRES', RT_RCDATA); + try + FStream.SaveToFile(ResFile); + finally + FStream.Free; + end; + end; end; - end; end; function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, @@ -1173,27 +1231,30 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, // TempDir = Temp dir where the package dcu will be copied, e.g. 'C:\Windows\Temp\MyCompos' var CommandLine, WorkDir, DOSOutput, DCCConfig: string; - L: TStringList; - I: Integer; - S, R: string; // Auxiliary strings - LError: string; + L : TStringList; + I : Integer; + S, R : string; // Auxiliary strings + LError : string; begin Result := False; LError := ''; - if FIDEVersion = ideNone then Exit; - if not Exists then begin - if Assigned(Log) then - SpWriteLog(Log, SLogInvalidPath, FDPKFilename); + if FIDEVersion = ideNone then Exit; - end - else begin + if not Exists then + begin + if Assigned(Log) then + SpWriteLog(Log, SLogInvalidPath, FDPKFilename); + Exit; + end + else + begin // [IDE Bug]: dcc32.exe won't execute if -Q option is not used // But it works fine without -Q if ShellExecute is used: // ShellExecute(Application.Handle, 'open', DCC, ExtractFileName(FDPKFilename), ExtractFilePath(FDPKFilename), SW_SHOWNORMAL); // There must be something wrong with SpExecuteDosCommand // Example: dcc32.exe -Q sptbxlib.dpk - CommandLine := DCC + ' -Q ' + TPath.GetFileName(FDPKFilename); - WorkDir := TPath.GetDirectoryName(FDPKFilename); + CommandLine := DCC + ' -Q ' + TPath.GetFileName(FDPKFilename); + WorkDir := TPath.GetDirectoryName(FDPKFilename); // Create and save DCC32.CFG file on the Package directory // Example of cfg file: @@ -1205,97 +1266,99 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, // -NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi // -N"C:\Users\x\AppData\Local\Temp\SpMultiInstall" // -JL - L := TStringList.Create; - try + L := TStringList.Create; + try // Add the SourcesL directories to the registry - TSpDelphiIDE.AddToSearchPath(SourcesL, FIDEVersion); + TSpDelphiIDE.AddToSearchPath(SourcesL, FIDEVersion); // Expand SearchPath, replace $(Delphi) and $(BDS) with real directories // and enclose the paths with " " to transform it to a valid // comma delimited string for the -U switch. - L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, False), FIDEVersion); - L.Text := StringReplace(L.Text, ';', #13#10, [rfReplaceAll, rfIgnoreCase]); - for I := 0 to L.Count - 1 do - L[I] := '"' + L[I] + '"'; - S := StringReplace(L.Text, #13#10, ';', [rfReplaceAll, rfIgnoreCase]); - if S[Length(S)] = ';' then - Delete(S, Length(S), 1); + L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, False), FIDEVersion); + L.Text := StringReplace(L.Text, ';', #13#10, [rfReplaceAll, rfIgnoreCase]); + for I := 0 to L.Count - 1 do + L[I] := '"' + L[I] + '"'; + S := StringReplace(L.Text, #13#10, ';', [rfReplaceAll, rfIgnoreCase]); + if S[Length(S)] = ';' then + Delete(S, Length(S), 1); // Save the DCC32.CFG file on the Package directory - DCCConfig := TPath.Combine(WorkDir, 'DCC32.CFG'); - R := IDETypes[FIDEVersion].IDERegistryPath; - L.Clear; + DCCConfig := TPath.Combine(WorkDir, 'DCC32.CFG'); + R := IDETypes[FIDEVersion].IDERegistryPath; + L.Clear; // SearchPath - L.Add('-U' + S); + L.Add('-U' + S); // Resource directories, add the source folder as the default *.dcr search folder - S := ''; - for I := 0 to SourcesL.Count - 1 do - S := S + ';' + SourcesL[I]; - if S <> '' then begin - Delete(S, 1, 1); - S := '"' + S + '"'; - L.Add('-R' + S); - end; + S := ''; + for I := 0 to SourcesL.Count - 1 do + S := S + ';' + SourcesL[I]; + if S <> '' then + begin + Delete(S, 1, 1); + S := '"' + S + '"'; + L.Add('-R' + S); + end; // BPL Output - S := TSpDelphiIDE.GetBPLOutputDir(FIDEVersion); - L.Add('-LE"' + S + '"'); + S := TSpDelphiIDE.GetBPLOutputDir(FIDEVersion); + L.Add('-LE"' + S + '"'); // DCP Output - S := TSpDelphiIDE.GetDCPOutputDir(FIDEVersion); - L.Add('-LN"' + S + '"'); + S := TSpDelphiIDE.GetDCPOutputDir(FIDEVersion); + L.Add('-LN"' + S + '"'); // BPI Output for the compiled packages, required for C++Builder 2006 and above, // same as DCP Output - if FIDEVersion >= ideDelphi2006 then - L.Add('-NB"' + S + '"'); + if FIDEVersion >= ideDelphi2006 then + L.Add('-NB"' + S + '"'); // Unit namespaces for Delphi XE2: - if FIDEVersion >= ideDelphiXE2 then - L.Add('-NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi'); + if FIDEVersion >= ideDelphiXE2 then + L.Add('-NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi'); // Includes, dcc32.exe accepts Includes as a semicolon separated string // enclosed by double quotes, e.g. "C:\dir1;C:\dir2;C:\dir3" - S := ''; - for I := 0 to IncludesL.Count - 1 do - S := S + ';' + IncludesL[I]; - if S <> '' then begin - Delete(S, 1, 1); - S := '"' + S + '"'; - L.Add('-I' + S); - end; + S := ''; + for I := 0 to IncludesL.Count - 1 do + S := S + ';' + IncludesL[I]; + if S <> '' then + begin + Delete(S, 1, 1); + S := '"' + S + '"'; + L.Add('-I' + S); + end; // DCU Output for the compiled packages - if TempDir <> '' then - L.Add('-N"' + TempDir + '"'); + if TempDir <> '' then + L.Add('-N"' + TempDir + '"'); // Add -JL compiler switch to make Hpp files required for C++Builder 2006 and above // This switch is undocumented: // http://groups.google.com/group/borland.public.cppbuilder.ide/browse_thread/thread/456bece4c5665459/0c4c61ecec179ca8 - if FIDEVersion >= ideDelphi2006 then - if TSpDelphiIDE.PersonalityInstalled(FIDEVersion, persCPPBuilder) then - L.Add('-JL'); + if FIDEVersion >= ideDelphi2006 then + if TSpDelphiIDE.PersonalityInstalled(FIDEVersion, persCPPBuilder) then + L.Add('-JL'); - L.SaveToFile(DCCConfig); - finally - L.Free; - end; + L.SaveToFile(DCCConfig); + finally + L.Free; + end; // Create and copy an empty res file if needed. // Some component libraries like VirtualTreeView don't include .res files. - CreateAndCopyEmptyResIfNeeded; + CreateAndCopyEmptyResIfNeeded; // Compile - SpWriteLog(Log, SLogCompiling, FDPKFilename); - try - Result := SpExecuteDosCommand(CommandLine, WorkDir, DOSOutput) = 0; - if Assigned(Log) then - Log.Text := Log.Text + DosOutput + #13#10; - if Result then - begin - Result := RegisterPackage(Log); - if not Result then - LError := SLogErrorRegistering; - end - else - LError := SLogErrorCompiling; - finally - DeleteFile(DCCConfig); + SpWriteLog(Log, SLogCompiling, FDPKFilename); + try + Result := SpExecuteDosCommand(CommandLine, WorkDir, DOSOutput) = 0; + if Assigned(Log) then + Log.Text := Log.Text + DosOutput + #13#10; + if Result then + begin + Result := RegisterPackage(Log); + if not Result then + LError := SLogErrorRegistering; + end + else + LError := SLogErrorCompiling; + finally + DeleteFile(DCCConfig); + end; end; - end; if not Result and Assigned(Log) then SpWriteLog(Log, LError, FDPKFilename, ''); @@ -1306,23 +1369,27 @@ function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; BPL, RegKey: string; begin Result := False; - if FIDEVersion = ideNone then Exit; + if FIDEVersion = ideNone then + Exit; // BPL filename BPL := TPath.Combine(TSpDelphiIDE.GetBPLOutputDir(FIDEVersion), FBPLFilename); RegKey := IDETypes[FIDEVersion].IDERegistryPath + '\Known Packages'; - if FOnlyRuntime then begin - SpDeleteRegValue(RegKey, BPL); - Result := True - end + if FOnlyRuntime then + begin + SpDeleteRegValue(RegKey, BPL); + Result := True + end else - if FOnlyDesigntime and TFile.Exists(BPL) then begin - if SpWriteRegValue(RegKey, BPL, FDescription) then begin - SpWriteLog(Log, SLogInstalling, FDPKFilename); - Result := True; - end; + if FOnlyDesigntime and TFile.Exists(BPL) then + begin + if SpWriteRegValue(RegKey, BPL, FDescription) then + begin + SpWriteLog(Log, SLogInstalling, FDPKFilename); + Result := True; + end; end; end; @@ -1332,18 +1399,18 @@ function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; procedure TSpDelphiDPKFilesList.Sort; begin inherited Sort(TComparer.Construct( - function (const Left, Right: TSpDelphiDPKFile): Integer - begin + function(const Left, Right: TSpDelphiDPKFile): Integer + begin // Runtime packages should be sorted first - if not Left.FOnlyDesigntime and Right.FOnlyDesigntime then - Result := -1 - else - if Left.FOnlyDesigntime and not Right.FOnlyDesigntime then - Result := 1 - else - Result := 0; - end - )); + if not Left.FOnlyDesigntime and Right.FOnlyDesigntime then + Result := -1 + else + if Left.FOnlyDesigntime and not Right.FOnlyDesigntime then + Result := 1 + else + Result := 0; + end + )); end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -1366,9 +1433,9 @@ destructor TSpComponentPackage.Destroy; procedure TSpComponentPackageList.LoadFromIni(Filename: string); - function MakeAbsolutePath(APath:string):string; + function MakeAbsolutePath(APath: string): string; var - LPath:string; + LPath: string; begin // Allow to specify the installation path relative to the .ini file if TPath.IsRelativePath(APath) then @@ -1382,12 +1449,12 @@ procedure TSpComponentPackageList.LoadFromIni(Filename: string); end; var - F: TMemIniFile; + F : TMemIniFile; LSections: TStringList; - Entry: TSpComponentPackage; - I, Aux: integer; - S: string; - A: TSpIDEType; + Entry : TSpComponentPackage; + I, Aux : integer; + S : string; + A : TSpIDEType; begin if not TFile.Exists(Filename) then Exit; @@ -1406,33 +1473,38 @@ procedure TSpComponentPackageList.LoadFromIni(Filename: string); // Read Component Packages F.ReadSections(LSections); - for I := 0 to LSections.Count - 1 do begin - S := LSections[I]; - if Length(S) > Length(rvPackageIniSectionPrefix) then - if AnsiSameText(Copy(S, 1, Length(rvPackageIniSectionPrefix)), rvPackageIniSectionPrefix) then begin - Entry := TSpComponentPackage.Create; - Entry.Name := F.ReadString(S, rvName, ''); - Entry.ZipFile := F.ReadString(S, rvZip, ''); - Entry.Git := F.ReadString(S, rvGit, ''); - Entry.Destination := F.ReadString(S, rvFolder, ''); - Entry.SearchPath := F.ReadString(S, rvSearchPath, ''); - Entry.GroupIndex := F.ReadInteger(S, rvGroupIndex, 0); - Aux := F.ReadInteger(S, rvInstallable, 1); - if Aux < 0 then Aux := 0; - if Aux > Ord(High(TSpInstallType)) then Aux := 1; - Entry.Installable := TSpInstallType(Aux); - Entry.Includes := F.ReadString(S, rvIncludes, ''); + for I := 0 to LSections.Count - 1 do + begin + S := LSections[I]; + if Length(S) > Length(rvPackageIniSectionPrefix) then + if AnsiSameText(Copy(S, 1, Length(rvPackageIniSectionPrefix)), rvPackageIniSectionPrefix) then + begin + Entry := TSpComponentPackage.Create; + Entry.Name := F.ReadString(S, rvName, ''); + Entry.ZipFile := F.ReadString(S, rvZip, ''); + Entry.Git := F.ReadString(S, rvGit, ''); + Entry.Destination := F.ReadString(S, rvFolder, ''); + Entry.SearchPath := F.ReadString(S, rvSearchPath, ''); + Entry.GroupIndex := F.ReadInteger(S, rvGroupIndex, 0); + Aux := F.ReadInteger(S, rvInstallable, 1); + if Aux < 0 then + Aux := 0; + if Aux > Ord(High(TSpInstallType)) then + Aux := 1; + Entry.Installable := TSpInstallType(Aux); + Entry.Includes := F.ReadString(S, rvIncludes, ''); // [IDE-Change] - if Entry.Installable = sitInstallable then begin - for A := FMinimumIDE to High(TSpIDEType) do - Entry.PackageList[A] := F.ReadString(S, IDETypes[A].IDEVersion, ''); - end; - - Entry.ExecuteList.LoadFromIni(Filename, S); - Add(Entry); - end; - end; + if Entry.Installable = sitInstallable then + begin + for A := FMinimumIDE to High(TSpIDEType) do + Entry.PackageList[A] := F.ReadString(S, IDETypes[A].IDEVersion, ''); + end; + + Entry.ExecuteList.LoadFromIni(Filename, S); + Add(Entry); + end; + end; finally LSections.Free; F.Free; @@ -1443,70 +1515,83 @@ function TSpComponentPackageList.ExtractAllZips(Source, Destination: string; Log: TStrings): Boolean; var GitChecked: Boolean; - I: integer; - Item: TSpComponentPackage; + I : integer; + Item : TSpComponentPackage; begin GitChecked := False; Result := False; SpWriteLog(Log, SLogStartUnzip, ''); // Check if the files exist - if not TDirectory.Exists(Destination) then begin - SpWriteLog(Log, SLogInvalidPath, Destination); - Exit; - end; - for I := 0 to Count - 1 do begin - Item := Items[I]; + if not TDirectory.Exists(Destination) then + begin + SpWriteLog(Log, SLogInvalidPath, Destination); + Exit; + end; + for I := 0 to Count - 1 do + begin + Item := Items[I]; // Expand ZipFile - if Item.ZipFile <> '' then - Item.ZipFile := TPath.Combine(Source, Item.ZipFile); + if Item.ZipFile <> '' then + Item.ZipFile := TPath.Combine(Source, Item.ZipFile); // Expand Destination - if Item.Destination <> '' then - Item.Destination := TPath.Combine(Destination, Item.Destination); - if TFile.Exists(Item.ZipFile) then begin - if not AnsiSameText(TPath.GetExtension(Item.ZipFile), '.ZIP') then begin - SpWriteLog(Log, SLogNotAZip, Item.ZipFile); - Exit; - end; - end - else - if Item.Git <> '' then begin - if not AnsiSameText(TPath.GetExtension(Item.Git), '.GIT') then begin - SpWriteLog(Log, SLogNotAGit, Item.Git); - Exit; + if Item.Destination <> '' then + Item.Destination := TPath.Combine(Destination, Item.Destination); + if TFile.Exists(Item.ZipFile) then + begin + if not AnsiSameText(TPath.GetExtension(Item.ZipFile), '.ZIP') then + begin + SpWriteLog(Log, SLogNotAZip, Item.ZipFile); + Exit; + end; + end + else + if Item.Git <> '' then + begin + if not AnsiSameText(TPath.GetExtension(Item.Git), '.GIT') then + begin + SpWriteLog(Log, SLogNotAGit, Item.Git); + Exit; + end; end; - end; - end; + end; // Unzip - Git Clone - for I := 0 to Count - 1 do begin - Item := Items[I]; + for I := 0 to Count - 1 do + begin + Item := Items[I]; - if Item.ZipFile <> '' then begin - SpWriteLog(Log, SLogExtracting, Item.ZipFile, Item.Destination); - if not SpExtractZip(Item.ZipFile, Item.Destination) then begin - SpWriteLog(Log, SLogCorruptedZip, Item.ZipFile); - Exit; - end; - end - else - if Item.Git <> '' then begin - if not GitChecked then begin - GitChecked := True; - if not SpIsGitInstalled(Log) then begin - SpWriteLog(Log, SLogGitCloneFailed, ''); - Exit; - end; - end; - SpWriteLog(Log, SLogGitCloning, Item.Git, Item.Destination); - if not SpGitClone(Item.Git, Item.Destination, Log) then begin - SpWriteLog(Log, SLogGitCloneFailed, Item.Git); - Exit; - end; - end + if Item.ZipFile <> '' then + begin + SpWriteLog(Log, SLogExtracting, Item.ZipFile, Item.Destination); + if not SpExtractZip(Item.ZipFile, Item.Destination) then + begin + SpWriteLog(Log, SLogCorruptedZip, Item.ZipFile); + Exit; + end; + end + else + if Item.Git <> '' then + begin + if not GitChecked then + begin + GitChecked := True; + if not SpIsGitInstalled(Log) then + begin + SpWriteLog(Log, SLogGitCloneFailed, ''); + Exit; + end; + end; + SpWriteLog(Log, SLogGitCloning, Item.Git, Item.Destination); + if not SpGitClone(Item.Git, Item.Destination, Log) then + begin + SpWriteLog(Log, SLogGitCloneFailed, Item.Git); + Exit; + end; + end else SpWriteLog(Log, SLogNotInstallable, Item.Name); // Not a Zip nor a Git, keep going - end; + end; Result := True; end; @@ -1515,31 +1600,36 @@ function TSpComponentPackageList.ExecuteAll(BaseFolder: string; Log: TStrings): I: Integer; begin Result := True; - if Count > 0 then begin - SpWriteLog(Log, SLogStartExecute, ''); - for I := 0 to Count - 1 do begin - Result := Items[I].ExecuteList.ExecuteAll(BaseFolder, Log); - if not Result then Exit; - Application.ProcessMessages; + if Count > 0 then + begin + SpWriteLog(Log, SLogStartExecute, ''); + for I := 0 to Count - 1 do + begin + Result := Items[I].ExecuteList.ExecuteAll(BaseFolder, Log); + if not Result then + Exit; + Application.ProcessMessages; + end; end; - end; end; function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; Log: TStrings): Boolean; var - DCC, TempDir: string; - I, J: integer; - Item: TSpComponentPackage; + DCC, TempDir : string; + I, J : integer; + Item : TSpComponentPackage; SourcesL, CompileL, IncludesL: TStringList; - DPKList: TSpDelphiDPKFilesList; + DPKList : TSpDelphiDPKFilesList; begin Result := False; - if IDE = ideNone then begin - Result := True; - Exit; - end + if IDE = ideNone then + begin + Result := True; + Exit; + end else - if not TSpDelphiIDE.Installed(IDE) then begin + if not TSpDelphiIDE.Installed(IDE) then + begin SpWriteLog(Log, SLogInvalidIDE, IDETypes[IDE].IDEName); Exit; end; @@ -1551,59 +1641,62 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; DCC := TSpDelphiIDE.GetDCC32Filename(IDE); SourcesL := TStringList.Create; try - for I := 0 to Count - 1 do begin - Item := Items[I]; - SpWriteLog(Log, SLogStartCompile, Item.Name); + for I := 0 to Count - 1 do + begin + Item := Items[I]; + SpWriteLog(Log, SLogStartCompile, Item.Name); // Expand Search Path - if Item.SearchPath <> '' then begin - SourcesL.CommaText := Item.SearchPath; + if Item.SearchPath <> '' then + begin + SourcesL.CommaText := Item.SearchPath; // Add the destination search path - for J := 0 to SourcesL.Count - 1 do - SourcesL[J] := TPath.GetFullPath(TPath.Combine(Item.Destination, SourcesL[J])); - end - else - SourcesL.Add(Item.Destination); - Item.SearchPath := SourcesL.CommaText; + for J := 0 to SourcesL.Count - 1 do + SourcesL[J] := TPath.GetFullPath(TPath.Combine(Item.Destination, SourcesL[J])); + end + else + SourcesL.Add(Item.Destination); + Item.SearchPath := SourcesL.CommaText; - case Item.Installable of - sitNotInstallable: ; // do nothing - sitSearchPathOnly: + case Item.Installable of + sitNotInstallable: + ; // do nothing + sitSearchPathOnly: // If the package is not installable add the SearchPath to the registry // This is useful when installing utility libraries that doesn't have // components to install, for example GraphicEx, GDI+, DirectX, etc - TSpDelphiIDE.AddToSearchPath(SourcesL, IDE); - sitInstallable: - begin - IncludesL := TStringList.Create; - DPKList := TSpDelphiDPKFilesList.Create; - try - // Expand Packages - CompileL := TStringList.Create; + TSpDelphiIDE.AddToSearchPath(SourcesL, IDE); + sitInstallable: + begin + IncludesL := TStringList.Create; + DPKList := TSpDelphiDPKFilesList.Create; try - CompileL.CommaText := Item.PackageList[IDE]; - for J := 0 to CompileL.Count - 1 do - DPKList.Add(TSpDelphiDPKFile.Create(TPath.Combine(Item.Destination, CompileL[J]), IDE)); - finally - CompileL.Free; - end; + // Expand Packages + CompileL := TStringList.Create; + try + CompileL.CommaText := Item.PackageList[IDE]; + for J := 0 to CompileL.Count - 1 do + DPKList.Add(TSpDelphiDPKFile.Create(TPath.Combine(Item.Destination, CompileL[J]), IDE)); + finally + CompileL.Free; + end; // Runtime packages must be compiled first - DPKList.Sort; + DPKList.Sort; // Expand Includes - IncludesL.CommaText := StringReplace(Item.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); + IncludesL.CommaText := StringReplace(Item.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); // Compile and Install - for J := 0 to DPKList.Count - 1 do - if not DPKList[J].CompilePackage(DCC, SourcesL, IncludesL, Log, TempDir) then - Exit; - finally - IncludesL.Free; - DPKList.Free; + for J := 0 to DPKList.Count - 1 do + if not DPKList[J].CompilePackage(DCC, SourcesL, IncludesL, Log, TempDir) then + Exit; + finally + IncludesL.Free; + DPKList.Free; + end; end; - end; - end; + end; - Application.ProcessMessages; - end; + Application.ProcessMessages; + end; Result := True; finally SourcesL.Free; @@ -1616,10 +1709,10 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; procedure TSpExecuteList.LoadFromIni(Filename, Section: string); var - L, V: TStringList; + L, V : TStringList; ExecuteEntry: TSpExecuteEntry; - Action: TSpActionType; - I: integer; + Action : TSpActionType; + I : integer; begin L := TStringList.Create; V := TStringList.Create; @@ -1627,16 +1720,18 @@ procedure TSpExecuteList.LoadFromIni(Filename, Section: string); Clear; SpIniLoadStringList(L, Filename, Section, rvExecuteIniPrefix); for I := 0 to L.Count - 1 do - if SpParseEntryValue(L[I], V, 3) then begin - Action := SpStringToActionType(V[0]); - if Action <> satNone then begin - ExecuteEntry := TSpExecuteEntry.Create; - ExecuteEntry.Action := Action; - ExecuteEntry.Origin := V[1]; - ExecuteEntry.Destination := V[2]; - Add(ExecuteEntry); + if SpParseEntryValue(L[I], V, 3) then + begin + Action := SpStringToActionType(V[0]); + if Action <> satNone then + begin + ExecuteEntry := TSpExecuteEntry.Create; + ExecuteEntry.Action := Action; + ExecuteEntry.Origin := V[1]; + ExecuteEntry.Destination := V[2]; + Add(ExecuteEntry); + end; end; - end; finally L.Free; V.Free; @@ -1645,7 +1740,7 @@ procedure TSpExecuteList.LoadFromIni(Filename, Section: string); function TSpExecuteList.ExecuteAll(BaseFolder: string; Log: TStrings): Boolean; var - I: Integer; + I : Integer; Item: TSpExecuteEntry; function ExecuteRun: Boolean; @@ -1655,52 +1750,59 @@ function TSpExecuteList.ExecuteAll(BaseFolder: string; Log: TStrings): Boolean; // Run it if it's a valid file Result := False; S := TPath.GetFileName(Item.Origin); - if S <> '' then begin - S := TPath.Combine(Item.Destination, S); - SpWriteLog(Log, SLogExecuting, S); - if SpExecuteDosCommand(S, Item.Destination, DosOutput) = 0 then begin - Log.Text := Log.Text + DosOutput + #13#10; - Result := True; - end - else - SpWriteLog(Log, SLogErrorExecuting, S, ''); - end; + if S <> '' then + begin + S := TPath.Combine(Item.Destination, S); + SpWriteLog(Log, SLogExecuting, S); + if SpExecuteDosCommand(S, Item.Destination, DosOutput) = 0 then + begin + Log.Text := Log.Text + DosOutput + #13#10; + Result := True; + end + else + SpWriteLog(Log, SLogErrorExecuting, S, ''); + end; end; begin Result := False; // Check if the files exist - for I := 0 to Count - 1 do begin - Item := Items[I]; - Item.Origin := StringReplace(Item.Origin, rvBaseFolder, BaseFolder, [rfReplaceAll, rfIgnoreCase]); - Item.Destination := StringReplace(Item.Destination, rvBaseFolder, BaseFolder, [rfReplaceAll, rfIgnoreCase]); - if not TFile.Exists(Item.Origin) then begin - SpWriteLog(Log, SLogInvalidPath, Item.Origin); - Exit; + for I := 0 to Count - 1 do + begin + Item := Items[I]; + Item.Origin := StringReplace(Item.Origin, rvBaseFolder, BaseFolder, [rfReplaceAll, rfIgnoreCase]); + Item.Destination := StringReplace(Item.Destination, rvBaseFolder, BaseFolder, [rfReplaceAll, rfIgnoreCase]); + if not TFile.Exists(Item.Origin) then + begin + SpWriteLog(Log, SLogInvalidPath, Item.Origin); + Exit; + end; end; - end; // Execute - for I := 0 to Count - 1 do begin - Item := Items[I]; - case Item.Action of - satRun: - if not ExecuteRun then - Exit; - satCopy, satCopyRun: - if SpFileOperation(Item.Origin, Item.Destination, FO_COPY) then begin - SpWriteLog(Log, SLogCopying, Item.Origin, Item.Destination); - if Item.Action = satCopyRun then - if not ExecuteRun then + for I := 0 to Count - 1 do + begin + Item := Items[I]; + case Item.Action of + satRun: + if not ExecuteRun then + Exit; + satCopy, satCopyRun: + if SpFileOperation(Item.Origin, Item.Destination, FO_COPY) then + begin + SpWriteLog(Log, SLogCopying, Item.Origin, Item.Destination); + if Item.Action = satCopyRun then + if not ExecuteRun then + Exit; + end + else + begin + SpWriteLog(Log, SLogErrorCopying, Item.Origin, Item.Destination); Exit; - end - else begin - SpWriteLog(Log, SLogErrorCopying, Item.Origin, Item.Destination); - Exit; - end; + end; + end; end; - end; Result := True; end; @@ -1731,13 +1833,15 @@ function TSpMultiInstaller.Install(ZipPath, BaseFolder: string; IDE: TSpIDEType; N := GetTickCount; if ComponentPackages.ExtractAllZips(ZipPath, BaseFolder, Log) then if ComponentPackages.ExecuteAll(BaseFolder, Log) then - if ComponentPackages.CompileAll(BaseFolder, IDE, Log) then begin - Secs := (GetTickCount - N) / 1000; - SpWriteLog(Log, SLogEnd, ''); - Log.Add(Format(SLogFinished, [Secs])); + if ComponentPackages.CompileAll(BaseFolder, IDE, Log) then + begin + Secs := (GetTickCount - N) / 1000; + SpWriteLog(Log, SLogEnd, ''); + Log.Add(Format(SLogFinished, [Secs])); // [IDE-Change] - if IDE >= ideDelphi2007 then begin + if IDE >= ideDelphi2007 then + begin // From the Delphi 2007 readme: // http://edn.embarcadero.com/article/36648 // If you your component installer updates paths in Delphi's registry to include paths @@ -1751,11 +1855,11 @@ function TSpMultiInstaller.Install(ZipPath, BaseFolder: string; IDE: TSpIDEType; // The EnvOptions.proj file is in: // Vista/7/8: C:\Users\...\AppData\Roaming\Borland\BDS\5.0 // C:\Users\...\AppData\Roaming\Embarcadero\BDS\15.0 - SpWriteRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'ForceEnvOptionsUpdate', '1'); - end; + SpWriteRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'ForceEnvOptionsUpdate', '1'); + end; - Result := True; - end; + Result := True; + end; finally FInstalling := False; end; From bf5a6381dc1b80a170c27e414a06a955776ac7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Thu, 9 Oct 2025 14:18:08 +0200 Subject: [PATCH 09/19] Make the form resizable, adjust components --- Source/Form.Installer.dfm | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Source/Form.Installer.dfm b/Source/Form.Installer.dfm index da8356b..9a01e1e 100644 --- a/Source/Form.Installer.dfm +++ b/Source/Form.Installer.dfm @@ -1,7 +1,6 @@ object FormInstall: TFormInstall Left = 293 Top = 145 - BorderStyle = bsDialog Caption = 'Silverpoint MultiInstaller' ClientHeight = 378 ClientWidth = 495 @@ -21,18 +20,22 @@ object FormInstall: TFormInstall Top = 60 Width = 495 Height = 265 - ActivePage = tshSelectComponents + ActivePage = tshInstallation Align = alClient Style = tsFlatButtons TabOrder = 0 object tshSelectComponents: TTabSheet Caption = 'tshSelectComponents' TabVisible = False + DesignSize = ( + 487 + 255) object lblSelectComponents: TLabel Left = 8 Top = 8 Width = 276 Height = 13 + Anchors = [akLeft, akTop, akRight] Caption = 'You'#39're about to install the following component packages:' end object clbSelectComponents: TCheckListBox @@ -40,6 +43,7 @@ object FormInstall: TFormInstall Top = 24 Width = 473 Height = 201 + Anchors = [akLeft, akTop, akRight, akBottom] Style = lbOwnerDrawVariable TabOrder = 0 OnClickCheck = clbSelectComponentsClickCheck @@ -51,6 +55,7 @@ object FormInstall: TFormInstall Top = 231 Width = 249 Height = 17 + Anchors = [akLeft, akBottom] Caption = 'Get files from GIT repository when available' Enabled = False TabOrder = 1 @@ -60,11 +65,15 @@ object FormInstall: TFormInstall Caption = 'tshSelectIde' ImageIndex = 1 TabVisible = False + DesignSize = ( + 487 + 255) object lblInstallfolder: TLabel Left = 8 Top = 16 Width = 358 Height = 13 + Anchors = [akLeft, akTop, akRight] Caption = 'Select a destination directory to install all the component pack' + 'age sources:' @@ -74,6 +83,7 @@ object FormInstall: TFormInstall Top = 42 Width = 393 Height = 21 + Anchors = [akLeft, akTop, akRight] TabOrder = 0 end object btnInstallFolder: TButton @@ -82,6 +92,7 @@ object FormInstall: TFormInstall Width = 75 Height = 25 Action = aBrowse + Anchors = [akTop, akRight] TabOrder = 1 end object rgSelectIde: TRadioGroup @@ -89,6 +100,7 @@ object FormInstall: TFormInstall Top = 80 Width = 473 Height = 171 + Anchors = [akLeft, akTop, akRight, akBottom] Caption = ' ' Columns = 2 Enabled = False @@ -108,11 +120,15 @@ object FormInstall: TFormInstall Caption = 'tshInstallation' ImageIndex = 2 TabVisible = False + DesignSize = ( + 487 + 255) object lblInstallation: TLabel Left = 8 Top = 8 Width = 74 Height = 13 + Anchors = [akLeft, akTop, akRight] Caption = 'Installation log:' end object lblInstallationFinished: TLabel @@ -120,6 +136,7 @@ object FormInstall: TFormInstall Top = 238 Width = 427 Height = 13 + Anchors = [akLeft, akRight, akBottom] Caption = 'Setup has finished installing the components on your computer. C' + 'lick Finish to exit Setup.' @@ -130,6 +147,7 @@ object FormInstall: TFormInstall Top = 32 Width = 473 Height = 193 + Anchors = [akLeft, akTop, akRight, akBottom] ReadOnly = True ScrollBars = ssBoth TabOrder = 0 @@ -154,6 +172,7 @@ object FormInstall: TFormInstall Top = 0 Width = 322 Height = 9 + Anchors = [akLeft, akRight, akBottom] Shape = bsBottomLine end object pbxVersionInfo: TPaintBox @@ -161,6 +180,7 @@ object FormInstall: TFormInstall Top = 0 Width = 150 Height = 14 + Anchors = [akLeft, akBottom] OnClick = pbxVersionInfoClick OnPaint = pbxVersionInfoPaint end @@ -170,6 +190,7 @@ object FormInstall: TFormInstall Width = 75 Height = 25 Action = aSaveLog + Anchors = [akRight, akBottom] TabOrder = 4 end object btnFinish: TButton @@ -178,10 +199,11 @@ object FormInstall: TFormInstall Width = 75 Height = 25 Action = aFinish + Anchors = [akRight, akBottom] TabOrder = 3 end object btnNext: TButton - Left = 311 + Left = 315 Top = 18 Width = 75 Height = 25 @@ -195,6 +217,7 @@ object FormInstall: TFormInstall Width = 75 Height = 25 Action = aBack + Anchors = [akRight, akBottom] Enabled = False TabOrder = 1 end @@ -204,6 +227,7 @@ object FormInstall: TFormInstall Width = 75 Height = 25 Action = aCancel + Anchors = [akRight, akBottom] TabOrder = 2 end end @@ -217,11 +241,15 @@ object FormInstall: TFormInstall Color = clWhite ParentBackground = False TabOrder = 2 + DesignSize = ( + 495 + 60) object lblTitle: TLabel Left = 8 Top = 15 Width = 425 Height = 29 + Anchors = [akLeft, akTop, akRight] AutoSize = False Caption = 'Title' Font.Charset = ANSI_CHARSET @@ -246,6 +274,7 @@ object FormInstall: TFormInstall Top = 5 Width = 48 Height = 48 + Anchors = [akTop, akRight] AutoSize = True Picture.Data = { 07544269746D6170361B0000424D361B00000000000036000000280000003000 From 0f36d89b95c029da56df500c4fa272b7d8ba6f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Thu, 9 Oct 2025 15:19:38 +0200 Subject: [PATCH 10/19] Add Support for RAD Studio 13 Florence Remove Support for Delphi XE1 and older --- Source/SpComponentInstaller.pas | 382 ++++++++++++++------------------ 1 file changed, 169 insertions(+), 213 deletions(-) diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index cc4123c..748d79d 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -43,18 +43,22 @@ interface Windows, Messages, SysUtils, Classes, Forms, Contnrs, Generics.Collections; resourcestring - SLogStartUnzip = '=========================================' + #13#10 + - 'Unzipping - Cloning' + #13#10 + + SLogStartUnzip = + '=========================================' + sLineBreak + + 'Unzipping - Cloning' + sLineBreak + '========================================='; - SLogStartExecute = '=========================================' + #13#10 + - 'Executing patches' + #13#10 + + SLogStartExecute = + '=========================================' + sLineBreak + + 'Executing patches' + sLineBreak + '========================================='; - SLogStartCompile = '=========================================' + #13#10 + - 'Compiling and installing:' + #13#10 + - '%s' + #13#10 + + SLogStartCompile = + '=========================================' + sLineBreak + + 'Compiling and installing:' + sLineBreak + + '%s' + sLineBreak + '========================================='; - SLogEnd = '=========================================' + #13#10 + - 'Finished' + #13#10 + + SLogEnd = + '=========================================' + sLineBreak + + 'Finished' + sLineBreak + '========================================='; SLogInvalidPath = 'Error: %s doesn''t exist.'; @@ -72,27 +76,20 @@ interface SLogErrorCompiling = 'Error compiling %s'; SLogErrorRegistering = 'Error registering %s'; - SLogCopying = 'Copying:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; - SLogExecuting = 'Executing:' + #13#10 + ' %s'; - SLogExtracting = 'Extracting:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; - SLogGitCloning = 'Git cloning:' + #13#10 + ' %s' + #13#10 + 'To:' + #13#10 + ' %s'; + SLogCopying = 'Copying:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; + SLogExecuting = 'Executing:' + sLineBreak + ' %s'; + SLogExtracting = 'Extracting:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; + SLogGitCloning = 'Git cloning:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; SLogCompiling = 'Compiling Package: %s'; SLogInstalling = 'Installing Package: %s'; - SLogFinished = 'All the component packages have been successfully installed.' + #13#10 + 'Elapsed time: %f secs.'; + SLogFinished = 'All the component packages have been successfully installed.' + sLineBreak + 'Elapsed time: %f secs.'; - SGitCloneCommand = 'GIT.EXE clone --verbose --progress %s %s'; + SGitCloneCommand = 'GIT.EXE clone --verbose --progress "%s" "%s"'; SGitIsInstalledCommand = 'GIT.EXE --version'; type TSpIDEType = ( // [IDE-Change-Update] ideNone, // - ideDelphi7, // D7 - ideDelphi2005, // D9 - ideDelphi2006, // D10 - ideDelphi2007, // D11 - ideDelphi2009, // D12 - ideDelphi2010, // D14 - ideDelphiXE, // D15 ideDelphiXE2, // D16 ideDelphiXE3, // D17 ideDelphiXE4, // D18 @@ -106,7 +103,13 @@ interface ideDelphiRio, // D26 ideDelphiSydney, // D27 ideDelphiAlexandria, // D28 - ideDelphiAthens // D29 + ideDelphiAthens, // D29 + ideDelphiFlorence // D37 + ); + + TSpPlatform = ( + pltWin32, + pltWin64 ); TSpIDETypeRec = record @@ -120,13 +123,6 @@ TSpIDETypeRec = record // [IDE-Change-Update] IDETypes: array [TSpIDEType] of TSpIDETypeRec = ( (IDEVersion: 'None'; IDEName: 'None'; IDERegistryPath: 'None'; IDERADStudioVersion: ''), - (IDEVersion: 'D7'; IDEName: 'Delphi 7'; IDERegistryPath: 'SOFTWARE\Borland\Delphi\7.0'; IDERADStudioVersion: ''), - (IDEVersion: 'D9'; IDEName: 'Delphi 2005'; IDERegistryPath: 'SOFTWARE\Borland\BDS\3.0'; IDERADStudioVersion: '3.0'), - (IDEVersion: 'D10'; IDEName: 'Developer Studio 2006'; IDERegistryPath: 'SOFTWARE\Borland\BDS\4.0'; IDERADStudioVersion: '4.0'), - (IDEVersion: 'D11'; IDEName: 'RAD Studio 2007'; IDERegistryPath: 'SOFTWARE\Borland\BDS\5.0'; IDERADStudioVersion: '5.0'), - (IDEVersion: 'D12'; IDEName: 'RAD Studio 2009'; IDERegistryPath: 'SOFTWARE\CodeGear\BDS\6.0'; IDERADStudioVersion: '6.0'), - (IDEVersion: 'D14'; IDEName: 'RAD Studio 2010'; IDERegistryPath: 'SOFTWARE\CodeGear\BDS\7.0'; IDERADStudioVersion: '7.0'), - (IDEVersion: 'D15'; IDEName: 'RAD Studio XE'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\8.0'; IDERADStudioVersion: '8.0'), (IDEVersion: 'D16'; IDEName: 'RAD Studio XE2'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\9.0'; IDERADStudioVersion: '9.0'), (IDEVersion: 'D17'; IDEName: 'RAD Studio XE3'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\10.0'; IDERADStudioVersion: '10.0'), (IDEVersion: 'D18'; IDEName: 'RAD Studio XE4'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\11.0'; IDERADStudioVersion: '11.0'), @@ -140,7 +136,8 @@ TSpIDETypeRec = record (IDEVersion: 'D26'; IDEName: 'RAD Studio 10.3 Rio'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\20.0'; IDERADStudioVersion: '20.0'), (IDEVersion: 'D27'; IDEName: 'RAD Studio 10.4 Sydney'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\21.0'; IDERADStudioVersion: '21.0'), (IDEVersion: 'D28'; IDEName: 'RAD Studio 11 Alexandria'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\22.0'; IDERADStudioVersion: '22.0'), - (IDEVersion: 'D29'; IDEName: 'RAD Studio 12 Athens'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\23.0'; IDERADStudioVersion: '23.0') + (IDEVersion: 'D29'; IDEName: 'RAD Studio 12 Athens'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\23.0'; IDERADStudioVersion: '23.0'), + (IDEVersion: 'D37'; IDEName: 'RAD Studio 13 Florence'; IDERegistryPath: 'SOFTWARE\Embarcadero\BDS\37.0'; IDERADStudioVersion: '37.0') ); type @@ -384,7 +381,7 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str BufferSize = 255; NativeLineFeed = Char(#10); NativeCarriageReturn = Char(#13); - NativeCrLf = string(#13#10); + NativeCrLf = string(sLineBreak); var Buffer : array [0 .. BufferSize] of AnsiChar; TempOutput : string; @@ -551,7 +548,7 @@ function SpGitClone(AGit, DestinationPath: string; Log: TStrings): Boolean; CommandLine := Format(SGitCloneCommand, [AGit, DestinationPath]); Result := SpExecuteDosCommand(CommandLine, '', DosOutput) = 0; if Assigned(Log) then - Log.Text := Log.Text + DosOutput + #13#10; + Log.Text := Log.Text + DosOutput + sLineBreak; end; function SpIsGitInstalled(Log: TStrings): Boolean; @@ -560,7 +557,7 @@ function SpIsGitInstalled(Log: TStrings): Boolean; begin Result := SpExecuteDosCommand(SGitIsInstalledCommand, '', DosOutput) = 0; if Assigned(Log) then - Log.Text := Log.Text + DosOutput + #13#10; + Log.Text := Log.Text + DosOutput + sLineBreak; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -702,6 +699,16 @@ function SpParseEntryValue(S: string; ValueList: TStringList; MinimumCount: Inte //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { IDE } +function SpGetPlatform(APlatform: TSpPlatform): string; +begin + if APlatform = pltWin32 then + Result := '\Win32' + else if APlatform = pltWin64 then + Result := '\Win64' + else + Result := ''; +end; + function SpActionTypeToString(A: TSpActionType): string; begin Result := ActionTypes[A]; @@ -721,7 +728,7 @@ function SpStringToActionType(S: string): TSpActionType; end; end; -procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuilderPath: Boolean); +procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuilderPath: Boolean; APlatform: TSpPlatform); begin Key := ''; Name := ''; @@ -730,31 +737,17 @@ procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuild // [IDE-Change] Key := IDETypes[IDE].IDERegistryPath; - if CPPBuilderPath and (IDE >= ideDelphi2006) then + if CPPBuilderPath then begin - if IDE = ideDelphi2006 then - begin - // '\CppPaths\SearchPath' with no space in the middle for C++Builder 2006 - Key := Key + '\CppPaths'; - Name := 'SearchPath'; - end - else - begin - Name := 'LibraryPath'; - if IDE >= ideDelphiXE2 then - Key := Key + '\C++\Paths\Win32' // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above - else - Key := Key + '\C++\Paths'; // '\C++\Paths\LibraryPath' with no space in the middle for C++Builder 2009 and above - end; + Name := 'LibraryPath'; + Key := Key + '\C++\Paths' // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above end else begin Name := 'Search Path'; - if IDE >= ideDelphiXE2 then - Key := Key + '\Library\Win32' - else - Key := Key + '\Library'; + Key := Key + '\Library' end; + Key := Key + SpGetPlatform(APlatform); end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -777,13 +770,10 @@ class function TSpDelphiIDE.PersonalityInstalled(IDE: TSpIDEType; if IDE = ideNone then Exit; - if IDE >= ideDelphi2006 then - begin - IDEPersonalityTypeToString(IDEPersonality, PersReg); - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Personalities', PersReg, S); - if S <> '' then - Result := True; - end; + IDEPersonalityTypeToString(IDEPersonality, PersReg); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Personalities', PersReg, S); + if S <> '' then + Result := True; end; class function TSpDelphiIDE.StringToIDEType(S: string): TSpIDEType; @@ -826,27 +816,21 @@ class function TSpDelphiIDE.GetDCC32Filename(IDE: TSpIDEType): string; class function TSpDelphiIDE.GetBPLOutputDir(IDE: TSpIDEType): string; begin // BPL Output Dir - if IDE >= ideDelphiXE2 then - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library\Win32', 'Package DPL Output', Result) - else - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library', 'Package DPL Output', Result); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library\Win32', 'Package DPL Output', Result); Result := TSpDelphiIDE.ExpandMacros(Result, IDE); end; class function TSpDelphiIDE.GetDCPOutputDir(IDE: TSpIDEType): string; begin // DCP Output Dir - if IDE >= ideDelphiXE2 then - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library\Win32', 'Package DCP Output', Result) - else - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library', 'Package DCP Output', Result); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library\Win32', 'Package DCP Output', Result); Result := TSpDelphiIDE.ExpandMacros(Result, IDE); end; class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: TStringList): Boolean; // Reads environment.proj file. // In newer versions of RAD Studio (2007 and up) the macros are stored in: -// C:\Users\x\AppData\Roaming\Embarcadero\BDS\19.0\environment.proj +// C:\Users\\AppData\Roaming\Embarcadero\BDS\19.0\environment.proj // This file is used by MSBuild // https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-environment-variables-in-a-build?view=vs-2017 var @@ -856,7 +840,7 @@ class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: Node, Root: IXMLNode; begin Result := False; - if not Assigned(NamesAndValues) or (IDE < ideDelphi2007) then + if not Assigned(NamesAndValues) then Exit; NamesAndValues.Clear; @@ -873,8 +857,8 @@ class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: Root := Root.ChildNodes.FindNode('PropertyGroup'); if Root <> nil then begin - // Add $(Delphi), $(BDS), $(BDSPROJECTSDIR), $(BDSCOMMONDIR), - // $(BDSUSERDIR), $(BDSLIB) macros + // Add $(Delphi), $(BDS), $(BDSPROJECTSDIR), $(BDSCOMMONDIR), + // $(BDSUSERDIR), $(BDSLIB) macros Node := Root.ChildNodes.FindNode('Delphi'); if Node <> nil then NamesAndValues.AddPair('Delphi', Node.Text); @@ -934,7 +918,7 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL DefaultL : TStringList; begin // In newer versions of RAD Studio (2007 and up) the macros are stored in: - // C:\Users\x\AppData\Roaming\Embarcadero\BDS\19.0\environment.proj + // C:\Users\\AppData\Roaming\Embarcadero\BDS\19.0\environment.proj // // When the IDE is opened it reads environment.proj and sets the macros as // system Environment Variables. @@ -959,81 +943,62 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL NamesAndValues.Values['Delphi'] := GetIDEDir(IDE); // $(BDS) - if IDE >= ideDelphi2005 then - if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDS') then - NamesAndValues.Values['BDS'] := GetIDEDir(IDE); + if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDS') then + NamesAndValues.Values['BDS'] := GetIDEDir(IDE); // $(BDSCOMMONDIR) // It points to a different directory according to how you install Delphi: // If you choose All Users during installation: - // C:\Users\Public\Documents\Embarcadero\Studio\19.0 + // C:\Users\Public\Documents\Embarcadero\Studio\ // If you choose Just Me during installation: - // C:\Users\x\Documents\Embarcadero\Studio\19.0 - if IDE >= ideDelphi2007 then - ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSCOMMONDIR'); + // C:\Users\\Documents\Embarcadero\Studio\ + ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSCOMMONDIR'); // $(BDSPROJECTSDIR) - // Example: C:\Users\x\Documents\Embarcadero\Studio\Projects - if IDE >= ideDelphi2005 then - begin - // This macro can be overrided by adding a string value called - // 'DefaultProjectsDirectory' containing a different directory to: - // HKCU\Software\Borland\BDS\4.0\Globals - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'DefaultProjectsDirectory', R); - if not TDirectory.Exists(R) then - if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSPROJECTSDIR') then - begin + // Example: C:\Users\\Documents\Embarcadero\Studio\Projects + // This macro can be overridden by adding a string value called + // 'DefaultProjectsDirectory' containing a different directory to: + // HKCU\Software\Borland\BDS\4.0\Globals + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'DefaultProjectsDirectory', R); + if not TDirectory.Exists(R) then + if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSPROJECTSDIR') then + begin // Try to guess it // Since BDSPROJECTSDIR is not defined in the registry we have to find it // manually, looking for all the localized dir names in MyDocuments folder - MyDocs := TPath.GetDocumentsPath; - if IDE in [ideDelphi2005, ideDelphi2006] then - begin - // For older BDS check if it's My Documents\Borland Studio Projects - for I := 0 to High(DirArrayBDS) do - begin - R := TPath.Combine(MyDocs, DirArrayBDS[I]); - if TDirectory.Exists(R) then - Break; - end; - end + MyDocs := TPath.GetDocumentsPath; + // For newer versions check if it's C:\Users\\Documents\Embarcadero\Studio\Projects + // or C:\Users\\Documents\RAD Studio\Projects + for I := 0 to High(DirArrayRAD) do + begin + if IDE >= ideDelphiXE6 then + R := TPath.Combine(MyDocs, 'Embarcadero\Studio\' + DirArrayRAD[I]) else - begin - // For newer versions check if it's C:\Users\x\Documents\Embarcadero\Studio\Projects - // or C:\Users\x\Documents\RAD Studio\Projects - for I := 0 to High(DirArrayRAD) do - begin - if IDE >= ideDelphiXE6 then - R := TPath.Combine(MyDocs, 'Embarcadero\Studio\' + DirArrayRAD[I]) - else - R := TPath.Combine(MyDocs, 'RAD Studio\' + DirArrayRAD[I]); - if TDirectory.Exists(R) then - Break; - end; - end; + R := TPath.Combine(MyDocs, 'RAD Studio\' + DirArrayRAD[I]); if TDirectory.Exists(R) then - NamesAndValues.Values['BDSPROJECTSDIR'] := R; + Break; end; - end; + if TDirectory.Exists(R) then + NamesAndValues.Values['BDSPROJECTSDIR'] := R; + end; // $(BDSUSERDIR) - // Example: C:\Users\x\Documents\Embarcadero\Studio\19.0 - if IDE >= ideDelphi2007 then - if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSUSERDIR') then - begin + // Example: C:\Users\\Documents\Embarcadero\Studio\ + if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSUSERDIR') then + begin // Try to guess it // Get BDSPROJECTSDIR and add IDE version - R := NamesAndValues.Values['BDSPROJECTSDIR']; - if TDirectory.Exists(R) then - begin - R := TPath.Combine(ExtractFilePath(R), IDETypes[IDE].IDERADStudioVersion); - if TDirectory.Exists(R) then - NamesAndValues.Values['BDSUSERDIR'] := R; - end; - end; + R := NamesAndValues.Values['BDSPROJECTSDIR']; + if TDirectory.Exists(R) then + begin + R := TPath.Combine(ExtractFilePath(R), IDETypes[IDE].IDERADStudioVersion); + if TDirectory.Exists(R) then + NamesAndValues.Values['BDSUSERDIR'] := R; + end; + end; // $(BDSLIB) - // Example: C:\Program Files\Embarcadero\Studio\19.0\lib + // Example: C:\Program Files\Embarcadero\Studio\\lib if not ReplaceWithDefault(NamesAndValues, DefaultL, 'BDSLIB') then NamesAndValues.Values['BDSLIB'] := TPath.Combine(GetIDEDir(IDE), 'lib'); @@ -1084,7 +1049,7 @@ class function TSpDelphiIDE.GetSearchPath(IDE: TSpIDEType; Result := ''; if IDE <> ideNone then begin - SpIDESearchPathRegKey(IDE, Key, Name, CPPBuilderPath); + SpIDESearchPathRegKey(IDE, Key, Name, CPPBuilderPath, pltWin32); //##LO Add Win64 Support later SpReadRegValue(Key, Name, Result); end; end; @@ -1098,7 +1063,7 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType begin SourcesL[I] := ExpandMacros(ExcludeTrailingPathDelimiter(SourcesL[I]), IDE); - // Add the directory to the Delphi Win32 search path registry entry + // Add the directory to the Delphi Win32 search path registry entry S := GetSearchPath(IDE, False); if (S <> '') and (SourcesL[I] <> '') then if not SpStringSearch(S, SourcesL[I]) then @@ -1106,24 +1071,21 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType if S[Length(S)] <> ';' then S := S + ';'; S := S + SourcesL[I]; - SpIDESearchPathRegKey(IDE, Key, Name, False); + SpIDESearchPathRegKey(IDE, Key, Name, False, pltWin32); //##LO Add Win64 Support later SpWriteRegValue(Key, Name, S) end; - // Add the directory to the C++Builder search path registry entry - if IDE >= ideDelphi2006 then - begin - S := GetSearchPath(IDE, True); - if (S <> '') and (SourcesL[I] <> '') then - if not SpStringSearch(S, SourcesL[I]) then - begin - if S[Length(S)] <> ';' then - S := S + ';'; - S := S + SourcesL[I]; - SpIDESearchPathRegKey(IDE, Key, Name, True); - SpWriteRegValue(Key, Name, S) - end; - end; + // Add the directory to the C++Builder search path registry entry + S := GetSearchPath(IDE, True); + if (S <> '') and (SourcesL[I] <> '') then + if not SpStringSearch(S, SourcesL[I]) then + begin + if S[Length(S)] <> ';' then + S := S + ';'; + S := S + SourcesL[I]; + SpIDESearchPathRegKey(IDE, Key, Name, True, pltWin32); //##LO Add Win64 Support later + SpWriteRegValue(Key, Name, S) + end; end; end; @@ -1248,47 +1210,47 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, end else begin - // [IDE Bug]: dcc32.exe won't execute if -Q option is not used - // But it works fine without -Q if ShellExecute is used: - // ShellExecute(Application.Handle, 'open', DCC, ExtractFileName(FDPKFilename), ExtractFilePath(FDPKFilename), SW_SHOWNORMAL); - // There must be something wrong with SpExecuteDosCommand - // Example: dcc32.exe -Q sptbxlib.dpk + // [IDE Bug]: dcc32.exe won't execute if -Q option is not used + // But it works fine without -Q if ShellExecute is used: + // ShellExecute(Application.Handle, 'open', DCC, ExtractFileName(FDPKFilename), ExtractFilePath(FDPKFilename), SW_SHOWNORMAL); + // There must be something wrong with SpExecuteDosCommand + // Example: dcc32.exe -Q sptbxlib.dpk CommandLine := DCC + ' -Q ' + TPath.GetFileName(FDPKFilename); WorkDir := TPath.GetDirectoryName(FDPKFilename); - // Create and save DCC32.CFG file on the Package directory - // Example of cfg file: - // -U"$(BDSLIB)\$(Platform)\release";"C:\TB2K\Source";"C:\SpTBXLib\Source" - // -R"C:\SpTBXLib\Source" - // -LE"C:\Users\Public\Documents\Embarcadero\Studio\19.0\Bpl" - // -LN"C:\Users\Public\Documents\Embarcadero\Studio\19.0\Dcp" - // -NB"C:\Users\Public\Documents\Embarcadero\Studio\19.0\Dcp" - // -NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi - // -N"C:\Users\x\AppData\Local\Temp\SpMultiInstall" - // -JL + // Create and save DCC32.CFG file on the Package directory + // Example of cfg file: + // -U"$(BDSLIB)\$(Platform)\release";"C:\TB2K\Source";"C:\SpTBXLib\Source" + // -R"C:\SpTBXLib\Source" + // -LE"C:\Users\Public\Documents\Embarcadero\Studio\\Bpl" + // -LN"C:\Users\Public\Documents\Embarcadero\Studio\\Dcp" + // -NB"C:\Users\Public\Documents\Embarcadero\Studio\\Dcp" + // -NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi + // -N"C:\Users\\AppData\Local\Temp\SpMultiInstall" + // -JL L := TStringList.Create; try - // Add the SourcesL directories to the registry + // Add the SourcesL directories to the registry TSpDelphiIDE.AddToSearchPath(SourcesL, FIDEVersion); - // Expand SearchPath, replace $(Delphi) and $(BDS) with real directories - // and enclose the paths with " " to transform it to a valid - // comma delimited string for the -U switch. + // Expand SearchPath, replace $(Delphi) and $(BDS) with real directories + // and enclose the paths with " " to transform it to a valid + // comma delimited string for the -U switch. L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, False), FIDEVersion); - L.Text := StringReplace(L.Text, ';', #13#10, [rfReplaceAll, rfIgnoreCase]); + L.Text := StringReplace(L.Text, ';', sLineBreak, [rfReplaceAll, rfIgnoreCase]); for I := 0 to L.Count - 1 do L[I] := '"' + L[I] + '"'; - S := StringReplace(L.Text, #13#10, ';', [rfReplaceAll, rfIgnoreCase]); + S := StringReplace(L.Text, sLineBreak, ';', [rfReplaceAll, rfIgnoreCase]); if S[Length(S)] = ';' then Delete(S, Length(S), 1); - // Save the DCC32.CFG file on the Package directory + // Save the DCC32.CFG file on the Package directory DCCConfig := TPath.Combine(WorkDir, 'DCC32.CFG'); R := IDETypes[FIDEVersion].IDERegistryPath; L.Clear; - // SearchPath + // SearchPath L.Add('-U' + S); - // Resource directories, add the source folder as the default *.dcr search folder + // Resource directories, add the source folder as the default *.dcr search folder S := ''; for I := 0 to SourcesL.Count - 1 do S := S + ';' + SourcesL[I]; @@ -1298,21 +1260,19 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, S := '"' + S + '"'; L.Add('-R' + S); end; - // BPL Output + // BPL Output S := TSpDelphiIDE.GetBPLOutputDir(FIDEVersion); L.Add('-LE"' + S + '"'); - // DCP Output + // DCP Output S := TSpDelphiIDE.GetDCPOutputDir(FIDEVersion); L.Add('-LN"' + S + '"'); - // BPI Output for the compiled packages, required for C++Builder 2006 and above, - // same as DCP Output - if FIDEVersion >= ideDelphi2006 then - L.Add('-NB"' + S + '"'); - // Unit namespaces for Delphi XE2: - if FIDEVersion >= ideDelphiXE2 then - L.Add('-NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi'); - // Includes, dcc32.exe accepts Includes as a semicolon separated string - // enclosed by double quotes, e.g. "C:\dir1;C:\dir2;C:\dir3" + // BPI Output for the compiled packages, required for C++Builder 2006 and above, + // same as DCP Output + L.Add('-NB"' + S + '"'); + // Unit namespaces for Delphi XE2 and up: + L.Add('-NSSystem.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi'); + // Includes, dcc32.exe accepts Includes as a semicolon separated string + // enclosed by double quotes, e.g. "C:\dir1;C:\dir2;C:\dir3" S := ''; for I := 0 to IncludesL.Count - 1 do S := S + ';' + IncludesL[I]; @@ -1322,31 +1282,30 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, S := '"' + S + '"'; L.Add('-I' + S); end; - // DCU Output for the compiled packages + // DCU Output for the compiled packages if TempDir <> '' then L.Add('-N"' + TempDir + '"'); - // Add -JL compiler switch to make Hpp files required for C++Builder 2006 and above - // This switch is undocumented: - // http://groups.google.com/group/borland.public.cppbuilder.ide/browse_thread/thread/456bece4c5665459/0c4c61ecec179ca8 - if FIDEVersion >= ideDelphi2006 then - if TSpDelphiIDE.PersonalityInstalled(FIDEVersion, persCPPBuilder) then - L.Add('-JL'); + // Add -JL compiler switch to make Hpp files required for C++Builder 2006 and above + // This switch is undocumented: + // http://groups.google.com/group/borland.public.cppbuilder.ide/browse_thread/thread/456bece4c5665459/0c4c61ecec179ca8 + if TSpDelphiIDE.PersonalityInstalled(FIDEVersion, persCPPBuilder) then + L.Add('-JL'); L.SaveToFile(DCCConfig); finally L.Free; end; - // Create and copy an empty res file if needed. - // Some component libraries like VirtualTreeView don't include .res files. + // Create and copy an empty res file if needed. + // Some component libraries like VirtualTreeView don't include .res files. CreateAndCopyEmptyResIfNeeded; - // Compile + // Compile SpWriteLog(Log, SLogCompiling, FDPKFilename); try Result := SpExecuteDosCommand(CommandLine, WorkDir, DOSOutput) = 0; if Assigned(Log) then - Log.Text := Log.Text + DosOutput + #13#10; + Log.Text := Log.Text + DosOutput + sLineBreak; if Result then begin Result := RegisterPackage(Log); @@ -1511,7 +1470,8 @@ procedure TSpComponentPackageList.LoadFromIni(Filename: string); end; end; -function TSpComponentPackageList.ExtractAllZips(Source, Destination: string; +function TSpComponentPackageList.ExtractAllZips( + Source, Destination: string; Log: TStrings): Boolean; var GitChecked: Boolean; @@ -1531,10 +1491,10 @@ function TSpComponentPackageList.ExtractAllZips(Source, Destination: string; for I := 0 to Count - 1 do begin Item := Items[I]; - // Expand ZipFile + // Expand ZipFile if Item.ZipFile <> '' then Item.ZipFile := TPath.Combine(Source, Item.ZipFile); - // Expand Destination + // Expand Destination if Item.Destination <> '' then Item.Destination := TPath.Combine(Destination, Item.Destination); if TFile.Exists(Item.ZipFile) then @@ -1627,8 +1587,7 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; Result := True; Exit; end - else - if not TSpDelphiIDE.Installed(IDE) then + else if not TSpDelphiIDE.Installed(IDE) then begin SpWriteLog(Log, SLogInvalidIDE, IDETypes[IDE].IDEName); Exit; @@ -1646,11 +1605,11 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; Item := Items[I]; SpWriteLog(Log, SLogStartCompile, Item.Name); - // Expand Search Path + // Expand Search Path if Item.SearchPath <> '' then begin SourcesL.CommaText := Item.SearchPath; - // Add the destination search path + // Add the destination search path for J := 0 to SourcesL.Count - 1 do SourcesL[J] := TPath.GetFullPath(TPath.Combine(Item.Destination, SourcesL[J])); end @@ -1662,16 +1621,16 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; sitNotInstallable: ; // do nothing sitSearchPathOnly: - // If the package is not installable add the SearchPath to the registry - // This is useful when installing utility libraries that doesn't have - // components to install, for example GraphicEx, GDI+, DirectX, etc + // If the package is not installable add the SearchPath to the registry + // This is useful when installing utility libraries that doesn't have + // components to install, for example GraphicEx, GDI+, DirectX, etc TSpDelphiIDE.AddToSearchPath(SourcesL, IDE); sitInstallable: begin IncludesL := TStringList.Create; DPKList := TSpDelphiDPKFilesList.Create; try - // Expand Packages + // Expand Packages CompileL := TStringList.Create; try CompileL.CommaText := Item.PackageList[IDE]; @@ -1680,11 +1639,11 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; finally CompileL.Free; end; - // Runtime packages must be compiled first + // Runtime packages must be compiled first DPKList.Sort; - // Expand Includes + // Expand Includes IncludesL.CommaText := StringReplace(Item.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); - // Compile and Install + // Compile and Install for J := 0 to DPKList.Count - 1 do if not DPKList[J].CompilePackage(DCC, SourcesL, IncludesL, Log, TempDir) then Exit; @@ -1756,7 +1715,7 @@ function TSpExecuteList.ExecuteAll(BaseFolder: string; Log: TStrings): Boolean; SpWriteLog(Log, SLogExecuting, S); if SpExecuteDosCommand(S, Item.Destination, DosOutput) = 0 then begin - Log.Text := Log.Text + DosOutput + #13#10; + Log.Text := Log.Text + DosOutput + sLineBreak; Result := True; end else @@ -1839,9 +1798,7 @@ function TSpMultiInstaller.Install(ZipPath, BaseFolder: string; IDE: TSpIDEType; SpWriteLog(Log, SLogEnd, ''); Log.Add(Format(SLogFinished, [Secs])); - // [IDE-Change] - if IDE >= ideDelphi2007 then - begin + // [IDE-Change] // From the Delphi 2007 readme: // http://edn.embarcadero.com/article/36648 // If you your component installer updates paths in Delphi's registry to include paths @@ -1855,8 +1812,7 @@ function TSpMultiInstaller.Install(ZipPath, BaseFolder: string; IDE: TSpIDEType; // The EnvOptions.proj file is in: // Vista/7/8: C:\Users\...\AppData\Roaming\Borland\BDS\5.0 // C:\Users\...\AppData\Roaming\Embarcadero\BDS\15.0 - SpWriteRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'ForceEnvOptionsUpdate', '1'); - end; + SpWriteRegValue(IDETypes[IDE].IDERegistryPath + '\Globals', 'ForceEnvOptionsUpdate', '1'); Result := True; end; From 446fcd1071aef3ffe370e30bb2a4587677058f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Thu, 9 Oct 2025 15:45:00 +0200 Subject: [PATCH 11/19] Fix some warnings suggested by DelphiLint Move declaration of TSpDelphiDPKFile to the implementation section --- Source/SpComponentInstaller.pas | 122 +++++++++++++++++--------------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index 748d79d..5642dbc 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -33,14 +33,13 @@ interface -{$WARN SYMBOL_PLATFORM OFF} -{$WARN UNIT_PLATFORM OFF} {$BOOLEVAL OFF} // Unit depends on short-circuit boolean evaluation {$R 'SpComponentInstallerRes.res'} // Has EmptyResourceFile.res file as a resource used by TSpDelphiDPKFile.CreateAndCopyEmptyResIfNeeded uses - Windows, Messages, SysUtils, Classes, Forms, Contnrs, Generics.Collections; + System.Classes, + System.Generics.Collections; resourcestring SLogStartUnzip = @@ -107,11 +106,6 @@ interface ideDelphiFlorence // D37 ); - TSpPlatform = ( - pltWin32, - pltWin64 - ); - TSpIDETypeRec = record IDEVersion: string; IDEName: string; @@ -142,6 +136,7 @@ TSpIDETypeRec = record type TSpIDEPersonality = (persDelphiWin32, persDelphiNET, persCPPBuilder); + TSpPlatform = (pltWin32, pltWin64); TSpDelphiIDE = class private @@ -171,36 +166,6 @@ TSpDelphiIDE = class class procedure AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType); end; - TSpDelphiDPKFile = class - private - FDPKFilename : string; - FBPLFilename : string; - FExists : Boolean; - FOnlyRuntime : Boolean; - FOnlyDesigntime: Boolean; - FDescription : string; - FLibSuffix : string; - FIDEVersion : TSpIDEType; - procedure CreateAndCopyEmptyResIfNeeded; - function RegisterPackage(Log: TStrings): Boolean; - public - property DPKFilename : string read FDPKFilename; - property BPLFilename : string read FBPLFilename; - property Exists : Boolean read FExists; - property OnlyRuntime : Boolean read FOnlyRuntime; - property OnlyDesigntime: Boolean read FOnlyDesigntime; - property Description : string read FDescription; - property LibSuffix : string read FLibSuffix; - property IDEVersion : TSpIDEType read FIDEVersion; - constructor Create(const Filename: string; IDE: TSpIDEType); virtual; - function CompilePackage(DCC: string; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; - end; - - TSpDelphiDPKFilesList = class(TObjectList) - public - procedure Sort; reintroduce; - end; - TSpActionType = (satNone, satCopy, satCopyRun, satRun); TSpInstallType = (sitNotInstallable, sitInstallable, sitSearchPathOnly); @@ -296,10 +261,20 @@ function SpStringToActionType(S: string): TSpActionType; implementation uses - ActiveX, ShellApi, ShlObj, IniFiles, Registry, + Winapi.ShellAPI, + Winapi.ShlObj, + Winapi.Windows, + System.IniFiles, + System.Win.Registry, + System.IOUtils, + System.StrUtils, + System.SysUtils, System.Zip, // Abbrevia is not needed anymore - Vcl.FileCtrl, System.IOUtils, StrUtils, Generics.Defaults, - Xml.XMLIntf, Xml.XMLDoc, themes; + System.Generics.Defaults, + Vcl.FileCtrl, + Vcl.Forms, + Xml.XMLIntf, + Xml.XMLDoc; const rvCount = 'Count'; @@ -321,6 +296,37 @@ implementation ActionTypes: array [TSpActionType] of string = ('none', 'copy', 'copyandrun', 'run'); IDEPersonalityRegNameTypes: array [TSpIDEPersonality] of string = ('Delphi.Win32', 'Delphi.NET', 'BCB'); +type + TSpDelphiDPKFile = class + private + FDPKFilename : string; + FBPLFilename : string; + FExists : Boolean; + FOnlyRuntime : Boolean; + FOnlyDesigntime: Boolean; + FDescription : string; + FLibSuffix : string; + FIDEVersion : TSpIDEType; + procedure CreateAndCopyEmptyResIfNeeded; + function RegisterPackage(Log: TStrings): Boolean; + public + property DPKFilename : string read FDPKFilename; + property BPLFilename : string read FBPLFilename; + property Exists : Boolean read FExists; + property OnlyRuntime : Boolean read FOnlyRuntime; + property OnlyDesigntime: Boolean read FOnlyDesigntime; + property Description : string read FDescription; + property LibSuffix : string read FLibSuffix; + property IDEVersion : TSpIDEType read FIDEVersion; + constructor Create(const Filename: string; IDE: TSpIDEType); virtual; + function CompilePackage(DCC: string; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; + end; + + TSpDelphiDPKFilesList = class(TObjectList) + public + procedure Sort; reintroduce; + end; + //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { Helpers } @@ -340,7 +346,7 @@ function SpStringSearch(S, SubStr: string; Delimiter: Char): Boolean; L.DelimitedText := S; Result := L.IndexOf(SubStr) > -1; finally - L.free; + L.Free; end; end; @@ -498,7 +504,7 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str function SpFileOperation(Origin, Destination: string; Operation: Cardinal): Boolean; var - F: TShFileOpStruct; + F: TSHFileOpStruct; begin Result := False; // Operation can be: FO_COPY, FO_MOVE, FO_DELETE, FO_RENAME @@ -649,7 +655,7 @@ function SpWriteRegValue(Key, Name, Value: string): Boolean; procedure SpIniLoadStringList(L: TStringList; IniFilename, Section: string; NamePrefix: string = ''); var F : TMemIniFile; - I, C: integer; + I, C: Integer; begin if not Assigned(L) then Exit; @@ -658,7 +664,7 @@ procedure SpIniLoadStringList(L: TStringList; IniFilename, Section: string; Name L.Clear; C := F.ReadInteger(Section, NamePrefix + rvCount, -1); for I := 0 to C - 1 do - L.Add(F.ReadString(Section, NamePrefix + inttostr(I), '')); + L.Add(F.ReadString(Section, NamePrefix + IntToStr(I), '')); finally F.Free; end; @@ -667,7 +673,7 @@ procedure SpIniLoadStringList(L: TStringList; IniFilename, Section: string; Name procedure SpIniSaveStringList(L: TStringList; IniFilename, Section: string; NamePrefix: string = ''); var F: TMemIniFile; - I: integer; + I: Integer; begin if not Assigned(L) then Exit; @@ -740,12 +746,12 @@ procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuild if CPPBuilderPath then begin Name := 'LibraryPath'; - Key := Key + '\C++\Paths' // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above + Key := Key + '\C++\Paths'; // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above end else begin Name := 'Search Path'; - Key := Key + '\Library' + Key := Key + '\Library'; end; Key := Key + SpGetPlatform(APlatform); end; @@ -1072,7 +1078,7 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType S := S + ';'; S := S + SourcesL[I]; SpIDESearchPathRegKey(IDE, Key, Name, False, pltWin32); //##LO Add Win64 Support later - SpWriteRegValue(Key, Name, S) + SpWriteRegValue(Key, Name, S); end; // Add the directory to the C++Builder search path registry entry @@ -1084,7 +1090,7 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType S := S + ';'; S := S + SourcesL[I]; SpIDESearchPathRegKey(IDE, Key, Name, True, pltWin32); //##LO Add Win64 Support later - SpWriteRegValue(Key, Name, S) + SpWriteRegValue(Key, Name, S); end; end; end; @@ -1305,7 +1311,7 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, try Result := SpExecuteDosCommand(CommandLine, WorkDir, DOSOutput) = 0; if Assigned(Log) then - Log.Text := Log.Text + DosOutput + sLineBreak; + Log.Text := Log.Text + DOSOutput + sLineBreak; if Result then begin Result := RegisterPackage(Log); @@ -1315,7 +1321,7 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, else LError := SLogErrorCompiling; finally - DeleteFile(DCCConfig); + System.SysUtils.DeleteFile(DCCConfig); end; end; @@ -1339,7 +1345,7 @@ function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; if FOnlyRuntime then begin SpDeleteRegValue(RegKey, BPL); - Result := True + Result := True; end else if FOnlyDesigntime and TFile.Exists(BPL) then @@ -1399,7 +1405,7 @@ procedure TSpComponentPackageList.LoadFromIni(Filename: string); // Allow to specify the installation path relative to the .ini file if TPath.IsRelativePath(APath) then begin - LPath := TPath.GetDirectoryName(FileName); + LPath := TPath.GetDirectoryName(Filename); LPath := TPath.Combine([LPath, APath]); Result := TPath.GetFullPath(LPath); end @@ -1411,7 +1417,7 @@ procedure TSpComponentPackageList.LoadFromIni(Filename: string); F : TMemIniFile; LSections: TStringList; Entry : TSpComponentPackage; - I, Aux : integer; + I, Aux : Integer; S : string; A : TSpIDEType; begin @@ -1475,7 +1481,7 @@ function TSpComponentPackageList.ExtractAllZips( Log: TStrings): Boolean; var GitChecked: Boolean; - I : integer; + I : Integer; Item : TSpComponentPackage; begin GitChecked := False; @@ -1576,7 +1582,7 @@ function TSpComponentPackageList.ExecuteAll(BaseFolder: string; Log: TStrings): function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; Log: TStrings): Boolean; var DCC, TempDir : string; - I, J : integer; + I, J : Integer; Item : TSpComponentPackage; SourcesL, CompileL, IncludesL: TStringList; DPKList : TSpDelphiDPKFilesList; @@ -1671,7 +1677,7 @@ procedure TSpExecuteList.LoadFromIni(Filename, Section: string); L, V : TStringList; ExecuteEntry: TSpExecuteEntry; Action : TSpActionType; - I : integer; + I : Integer; begin L := TStringList.Create; V := TStringList.Create; From efc98e8576c48e07e29ebfead351f579008ba3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Fri, 10 Oct 2025 10:28:37 +0200 Subject: [PATCH 12/19] Add a select all/none checkbox to the component selection --- Source/Form.Installer.dfm | 13 +++++++++++-- Source/Form.Installer.pas | 13 ++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Source/Form.Installer.dfm b/Source/Form.Installer.dfm index 9a01e1e..3afe2c6 100644 --- a/Source/Form.Installer.dfm +++ b/Source/Form.Installer.dfm @@ -20,7 +20,7 @@ object FormInstall: TFormInstall Top = 60 Width = 495 Height = 265 - ActivePage = tshInstallation + ActivePage = tshSelectComponents Align = alClient Style = tsFlatButtons TabOrder = 0 @@ -51,7 +51,7 @@ object FormInstall: TFormInstall OnMeasureItem = clbSelectComponentsMeasureItem end object chkGetFromGit: TCheckBox - Left = 8 + Left = 231 Top = 231 Width = 249 Height = 17 @@ -60,6 +60,15 @@ object FormInstall: TFormInstall Enabled = False TabOrder = 1 end + object chkSelectAllNone: TCheckBox + Left = 8 + Top = 231 + Width = 97 + Height = 17 + Caption = 'Select all/none' + TabOrder = 2 + OnClick = chkSelectAllNoneClick + end end object tshSelectIde: TTabSheet Caption = 'tshSelectIde' diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index ee2bdc0..751fe20 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -65,6 +65,7 @@ TFormInstall = class(TForm) imgLogo: TImage; Timer1: TTimer; SaveDialog1: TSaveDialog; + chkSelectAllNone: TCheckBox; procedure aBrowseExecute(Sender: TObject); procedure aBackExecute(Sender: TObject); procedure aCancelExecute(Sender: TObject); @@ -83,6 +84,7 @@ TFormInstall = class(TForm) procedure Timer1Timer(Sender: TObject); procedure pbxVersionInfoPaint(Sender: TObject); procedure pbxVersionInfoClick(Sender: TObject); + procedure chkSelectAllNoneClick(Sender: TObject); private FAppPath : string; FAutoStart: boolean; @@ -242,6 +244,14 @@ procedure TFormInstall.chkCompileInIdeClick(Sender: TObject); rgSelectIde.Enabled := chkCompileInIde.Checked; end; +procedure TFormInstall.chkSelectAllNoneClick(Sender: TObject); +var + I: integer; +begin + for I := 0 to clbSelectComponents.Count - 1 do + clbSelectComponents.Checked[I] := chkSelectAllNone.Checked; +end; + procedure TFormInstall.CreateInstaller(const APath: string); var I: Integer; @@ -293,6 +303,7 @@ procedure TFormInstall.FillCheckListBox; 'GIT: ' + FInstaller.ComponentPackages[I].Git; end; end; + chkSelectAllNone.Checked := True; end; procedure TFormInstall.FillRadioGroup; @@ -499,7 +510,7 @@ function TFormInstall.Install: Boolean; aFinish.Visible := True; aSaveLog.Visible := True; - aBack.Visible := False; +// aBack.Visible := False; aNext.Visible := False; aCancel.Visible := False; Application.ProcessMessages; From d813070730d737f3ed099aca1dfb7418d8898a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Fri, 10 Oct 2025 10:40:19 +0200 Subject: [PATCH 13/19] Fix sorting of packages by using BubbleSort instead of Quicksort Pass the Log parameters as an open array --- Source/SpComponentInstaller.pas | 217 +++++++++++++++++++++----------- 1 file changed, 145 insertions(+), 72 deletions(-) diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index 5642dbc..8d87763 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -79,8 +79,8 @@ interface SLogExecuting = 'Executing:' + sLineBreak + ' %s'; SLogExtracting = 'Extracting:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; SLogGitCloning = 'Git cloning:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; - SLogCompiling = 'Compiling Package: %s'; - SLogInstalling = 'Installing Package: %s'; + SLogCompiling = 'Compiling for %s Package: %s'; + SLogInstalling = 'Installing for %s Package: %s'; SLogFinished = 'All the component packages have been successfully installed.' + sLineBreak + 'Elapsed time: %f secs.'; SGitCloneCommand = 'GIT.EXE clone --verbose --progress "%s" "%s"'; @@ -138,6 +138,17 @@ TSpIDETypeRec = record TSpIDEPersonality = (persDelphiWin32, persDelphiNET, persCPPBuilder); TSpPlatform = (pltWin32, pltWin64); + TSpPlatformHelper = record helper for TSpPlatform + private + function GetDccPath: string; + function GetName: string; + function GetRegKey: string; + public + property DccPath: string read GetDccPath; + property Name : string read GetName; + property RegKey : string read GetRegKey; + end; + TSpDelphiIDE = class private class var FCachedMacrosCommaDelimited: string; @@ -153,9 +164,9 @@ TSpDelphiIDE = class // Path class function GetIDEDir(IDE: TSpIDEType): string; - class function GetDCC32Filename(IDE: TSpIDEType): string; - class function GetBPLOutputDir(IDE: TSpIDEType): string; - class function GetDCPOutputDir(IDE: TSpIDEType): string; + class function GetDCCFilename(IDE: TSpIDEType; APlatform: TSpPlatform): string; + class function GetBPLOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; + class function GetDCPOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; // Macros class function ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: TStringList): Boolean; @@ -231,7 +242,7 @@ TSpMultiInstaller = class { Misc } procedure SpOpenLink(URL: string); function SpStringSearch(S, SubStr: string; Delimiter: Char = ';'): Boolean; -procedure SpWriteLog(Log: TStrings; ResourceS, Arg1: string; Arg2: string = ''); +procedure SpWriteLog(Log: TStrings; const AMessage: string; const AParams: array of TVarRec); { Files } function SpGetParameter(const ParamName: string; out ParamValue: string): Boolean; @@ -308,7 +319,7 @@ TSpDelphiDPKFile = class FLibSuffix : string; FIDEVersion : TSpIDEType; procedure CreateAndCopyEmptyResIfNeeded; - function RegisterPackage(Log: TStrings): Boolean; + function RegisterPackage(APlatform: TSpPlatform; Log: TStrings): Boolean; public property DPKFilename : string read FDPKFilename; property BPLFilename : string read FBPLFilename; @@ -319,10 +330,12 @@ TSpDelphiDPKFile = class property LibSuffix : string read FLibSuffix; property IDEVersion : TSpIDEType read FIDEVersion; constructor Create(const Filename: string; IDE: TSpIDEType); virtual; - function CompilePackage(DCC: string; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; + function CompilePackage(APlatform: TSpPlatform; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; end; TSpDelphiDPKFilesList = class(TObjectList) + private + procedure BubbleSort(const AComparer: IComparer); public procedure Sort; reintroduce; end; @@ -330,6 +343,38 @@ TSpDelphiDPKFilesList = class(TObjectList) //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { Helpers } +{ TSpPlatformHelper } + +function TSpPlatformHelper.GetDccPath: string; +begin + if Self = pltWin32 then + Result := 'dcc32.exe' + else if Self = pltWin64 then + Result := 'dcc64.exe' + else + Result := ''; +end; + +function TSpPlatformHelper.GetName: string; +begin + if Self = pltWin32 then + Result := 'Win32' + else if Self = pltWin64 then + Result := 'Win64' + else + Result := ''; +end; + +function TSpPlatformHelper.GetRegKey: string; +begin + if Self = pltWin32 then + Result := '\Win32' + else if Self = pltWin64 then + Result := '\Win64' + else + Result := ''; +end; + procedure SpOpenLink(URL: string); begin ShellExecute(Application.Handle, 'open', PChar(URL), '', '', SW_SHOWNORMAL); @@ -350,11 +395,11 @@ function SpStringSearch(S, SubStr: string; Delimiter: Char): Boolean; end; end; -procedure SpWriteLog(Log: TStrings; ResourceS, Arg1: string; Arg2: string = ''); +procedure SpWriteLog(Log: TStrings; const AMessage: string; const AParams: array of TVarRec); begin if Assigned(Log) then begin - Log.Add(Format(ResourceS, [Arg1, Arg2])); + Log.Add(Format(AMessage, AParams)); Log.Add(''); end; end; @@ -705,16 +750,6 @@ function SpParseEntryValue(S: string; ValueList: TStringList; MinimumCount: Inte //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { IDE } -function SpGetPlatform(APlatform: TSpPlatform): string; -begin - if APlatform = pltWin32 then - Result := '\Win32' - else if APlatform = pltWin64 then - Result := '\Win64' - else - Result := ''; -end; - function SpActionTypeToString(A: TSpActionType): string; begin Result := ActionTypes[A]; @@ -753,7 +788,7 @@ procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuild Name := 'Search Path'; Key := Key + '\Library'; end; - Key := Key + SpGetPlatform(APlatform); + Key := Key + APlatform.RegKey; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM @@ -764,7 +799,7 @@ class function TSpDelphiIDE.Installed(IDE: TSpIDEType): Boolean; if IDE = ideNone then Result := False else - Result := TFile.Exists(GetDCC32Filename(IDE)); + Result := TFile.Exists(GetDCCFilename(IDE, pltWin32)); // Just check for the dcc32 executable end; class function TSpDelphiIDE.PersonalityInstalled(IDE: TSpIDEType; @@ -812,24 +847,24 @@ class function TSpDelphiIDE.GetIDEDir(IDE: TSpIDEType): string; SpReadRegValue(IDETypes[IDE].IDERegistryPath, 'RootDir', Result); end; -class function TSpDelphiIDE.GetDCC32Filename(IDE: TSpIDEType): string; +class function TSpDelphiIDE.GetDCCFilename(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin SpReadRegValue(IDETypes[IDE].IDERegistryPath, 'App', Result); if Result <> '' then - Result := TPath.Combine(TPath.GetDirectoryName(Result), 'dcc32.exe'); + Result := TPath.Combine(TPath.GetDirectoryName(Result), APlatform.DccPath); end; -class function TSpDelphiIDE.GetBPLOutputDir(IDE: TSpIDEType): string; +class function TSpDelphiIDE.GetBPLOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin // BPL Output Dir - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library\Win32', 'Package DPL Output', Result); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.RegKey, 'Package DPL Output', Result); Result := TSpDelphiIDE.ExpandMacros(Result, IDE); end; -class function TSpDelphiIDE.GetDCPOutputDir(IDE: TSpIDEType): string; +class function TSpDelphiIDE.GetDCPOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin // DCP Output Dir - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library\Win32', 'Package DCP Output', Result); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.RegKey, 'Package DCP Output', Result); Result := TSpDelphiIDE.ExpandMacros(Result, IDE); end; @@ -1135,11 +1170,11 @@ constructor TSpDelphiDPKFile.Create(const Filename: string; IDE: TSpIDEType); FDescription := Copy(L.Text, P, P2 - P); end; - // Try to parse $LIBSUFFIX - // Won't work if there are nested $IFDEFs, for example: - // {$IFDEF VER340} {$LIBSUFFIX '270'} {$ENDIF} - // {$IFDEF VER350} {$LIBSUFFIX '280'} {$ENDIF} - // Delphi 10.4 Sydney added the AUTO option: {$LIBSUFFIX AUTO} + // Try to parse $LIBSUFFIX + // Won't work if there are nested $IFDEFs, for example: + // {$IFDEF VER340} {$LIBSUFFIX '270'} {$ENDIF} + // {$IFDEF VER350} {$LIBSUFFIX '280'} {$ENDIF} + // Delphi 10.4 Sydney added the AUTO option: {$LIBSUFFIX AUTO} P := Pos('{$LIBSUFFIX AUTO}', L.Text); if P > 0 then begin @@ -1189,8 +1224,11 @@ procedure TSpDelphiDPKFile.CreateAndCopyEmptyResIfNeeded; end; end; -function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, - IncludesL, Log: TStrings; TempDir: string): Boolean; +function TSpDelphiDPKFile.CompilePackage( + APlatform: TSpPlatform; + SourcesL, IncludesL, + Log: TStrings; + TempDir: string): Boolean; // DCC = full path of dcc32.exe, e.g. 'C:\Program Files\Borland\Delphi7\Bin\dcc32.exe // IDE = IDE version to compile with // SourcesL = list of source folders of the component package to add to the Library Search Path @@ -1198,6 +1236,7 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, // Log = Log strings // TempDir = Temp dir where the package dcu will be copied, e.g. 'C:\Windows\Temp\MyCompos' var + DCC : string; CommandLine, WorkDir, DOSOutput, DCCConfig: string; L : TStringList; I : Integer; @@ -1211,11 +1250,13 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, if not Exists then begin if Assigned(Log) then - SpWriteLog(Log, SLogInvalidPath, FDPKFilename); + SpWriteLog(Log, SLogInvalidPath, [FDPKFilename]); Exit; end else begin + DCC := TSpDelphiIDE.GetDCCFilename(FIDEVersion, APlatform); + // [IDE Bug]: dcc32.exe won't execute if -Q option is not used // But it works fine without -Q if ShellExecute is used: // ShellExecute(Application.Handle, 'open', DCC, ExtractFileName(FDPKFilename), ExtractFilePath(FDPKFilename), SW_SHOWNORMAL); @@ -1267,10 +1308,10 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, L.Add('-R' + S); end; // BPL Output - S := TSpDelphiIDE.GetBPLOutputDir(FIDEVersion); + S := TSpDelphiIDE.GetBPLOutputDir(FIDEVersion, APlatform); L.Add('-LE"' + S + '"'); // DCP Output - S := TSpDelphiIDE.GetDCPOutputDir(FIDEVersion); + S := TSpDelphiIDE.GetDCPOutputDir(FIDEVersion, APlatform); L.Add('-LN"' + S + '"'); // BPI Output for the compiled packages, required for C++Builder 2006 and above, // same as DCP Output @@ -1307,14 +1348,14 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, CreateAndCopyEmptyResIfNeeded; // Compile - SpWriteLog(Log, SLogCompiling, FDPKFilename); + SpWriteLog(Log, SLogCompiling, [APlatform.Name, FDPKFilename]); try Result := SpExecuteDosCommand(CommandLine, WorkDir, DOSOutput) = 0; if Assigned(Log) then Log.Text := Log.Text + DOSOutput + sLineBreak; if Result then begin - Result := RegisterPackage(Log); + Result := RegisterPackage(APlatform, Log); if not Result then LError := SLogErrorRegistering; end @@ -1326,10 +1367,10 @@ function TSpDelphiDPKFile.CompilePackage(DCC: string; SourcesL, end; if not Result and Assigned(Log) then - SpWriteLog(Log, LError, FDPKFilename, ''); + SpWriteLog(Log, LError, [FDPKFilename]); end; -function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; +function TSpDelphiDPKFile.RegisterPackage(APlatform: TSpPlatform; Log: TStrings): Boolean; var BPL, RegKey: string; begin @@ -1338,8 +1379,9 @@ function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; Exit; // BPL filename - BPL := TPath.Combine(TSpDelphiIDE.GetBPLOutputDir(FIDEVersion), FBPLFilename); + BPL := TPath.Combine(TSpDelphiIDE.GetBPLOutputDir(FIDEVersion, APlatform), FBPLFilename); + //##LO double check this for Win64 RegKey := IDETypes[FIDEVersion].IDERegistryPath + '\Known Packages'; if FOnlyRuntime then @@ -1352,7 +1394,7 @@ function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; begin if SpWriteRegValue(RegKey, BPL, FDescription) then begin - SpWriteLog(Log, SLogInstalling, FDPKFilename); + SpWriteLog(Log, SLogInstalling, [APlatform.Name, FDPKFilename]); Result := True; end; end; @@ -1361,12 +1403,33 @@ function TSpDelphiDPKFile.RegisterPackage(Log: TStrings): Boolean; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpDelphiDPKFilesList } +procedure TSpDelphiDPKFilesList.BubbleSort(const AComparer: IComparer); +var + I, J : Integer; + LWasSwapped: Boolean; +begin + for I := Pred(Count) downto 1 do + begin + LWasSwapped := False; + for J := 1 to I do + if (AComparer.Compare(Items[J - 1], Items[J]) > 0) then + begin + Exchange(J - 1, J); + LWasSwapped := True; + end; + if not LWasSwapped then + Break; + end; +end; + procedure TSpDelphiDPKFilesList.Sort; begin - inherited Sort(TComparer.Construct( + // Use BubbleSort, because the default Quicksort is unstable and may + // swap the order of "identical" items + BubbleSort(TComparer.Construct( function(const Left, Right: TSpDelphiDPKFile): Integer begin - // Runtime packages should be sorted first + // Runtime packages should be sorted first if not Left.FOnlyDesigntime and Right.FOnlyDesigntime then Result := -1 else @@ -1486,12 +1549,12 @@ function TSpComponentPackageList.ExtractAllZips( begin GitChecked := False; Result := False; - SpWriteLog(Log, SLogStartUnzip, ''); + SpWriteLog(Log, SLogStartUnzip, []); // Check if the files exist if not TDirectory.Exists(Destination) then begin - SpWriteLog(Log, SLogInvalidPath, Destination); + SpWriteLog(Log, SLogInvalidPath, [Destination]); Exit; end; for I := 0 to Count - 1 do @@ -1507,7 +1570,7 @@ function TSpComponentPackageList.ExtractAllZips( begin if not AnsiSameText(TPath.GetExtension(Item.ZipFile), '.ZIP') then begin - SpWriteLog(Log, SLogNotAZip, Item.ZipFile); + SpWriteLog(Log, SLogNotAZip, [Item.ZipFile]); Exit; end; end @@ -1516,7 +1579,7 @@ function TSpComponentPackageList.ExtractAllZips( begin if not AnsiSameText(TPath.GetExtension(Item.Git), '.GIT') then begin - SpWriteLog(Log, SLogNotAGit, Item.Git); + SpWriteLog(Log, SLogNotAGit, [Item.Git]); Exit; end; end; @@ -1529,10 +1592,10 @@ function TSpComponentPackageList.ExtractAllZips( if Item.ZipFile <> '' then begin - SpWriteLog(Log, SLogExtracting, Item.ZipFile, Item.Destination); + SpWriteLog(Log, SLogExtracting, [Item.ZipFile, Item.Destination]); if not SpExtractZip(Item.ZipFile, Item.Destination) then begin - SpWriteLog(Log, SLogCorruptedZip, Item.ZipFile); + SpWriteLog(Log, SLogCorruptedZip, [Item.ZipFile]); Exit; end; end @@ -1544,19 +1607,19 @@ function TSpComponentPackageList.ExtractAllZips( GitChecked := True; if not SpIsGitInstalled(Log) then begin - SpWriteLog(Log, SLogGitCloneFailed, ''); + SpWriteLog(Log, SLogGitCloneFailed, [Item.Git]); Exit; end; end; - SpWriteLog(Log, SLogGitCloning, Item.Git, Item.Destination); + SpWriteLog(Log, SLogGitCloning, [Item.Git, Item.Destination]); if not SpGitClone(Item.Git, Item.Destination, Log) then begin - SpWriteLog(Log, SLogGitCloneFailed, Item.Git); + SpWriteLog(Log, SLogGitCloneFailed, [Item.Git]); Exit; end; end else - SpWriteLog(Log, SLogNotInstallable, Item.Name); // Not a Zip nor a Git, keep going + SpWriteLog(Log, SLogNotInstallable, [Item.Name]); // Not a Zip nor a Git, keep going end; Result := True; end; @@ -1568,7 +1631,7 @@ function TSpComponentPackageList.ExecuteAll(BaseFolder: string; Log: TStrings): Result := True; if Count > 0 then begin - SpWriteLog(Log, SLogStartExecute, ''); + SpWriteLog(Log, SLogStartExecute, []); for I := 0 to Count - 1 do begin Result := Items[I].ExecuteList.ExecuteAll(BaseFolder, Log); @@ -1581,8 +1644,8 @@ function TSpComponentPackageList.ExecuteAll(BaseFolder: string; Log: TStrings): function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; Log: TStrings): Boolean; var - DCC, TempDir : string; - I, J : Integer; + TempDir : string; + J : Integer; Item : TSpComponentPackage; SourcesL, CompileL, IncludesL: TStringList; DPKList : TSpDelphiDPKFilesList; @@ -1595,7 +1658,7 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; end else if not TSpDelphiIDE.Installed(IDE) then begin - SpWriteLog(Log, SLogInvalidIDE, IDETypes[IDE].IDEName); + SpWriteLog(Log, SLogInvalidIDE, [IDETypes[IDE].IDEName]); Exit; end; @@ -1603,13 +1666,11 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; TempDir := TPath.Combine(TPath.GetTempPath, 'SpMultiInstall'); CreateDir(TempDir); - DCC := TSpDelphiIDE.GetDCC32Filename(IDE); SourcesL := TStringList.Create; try - for I := 0 to Count - 1 do + for Item in Self do begin - Item := Items[I]; - SpWriteLog(Log, SLogStartCompile, Item.Name); + SpWriteLog(Log, SLogStartCompile, [Item.Name]); // Expand Search Path if Item.SearchPath <> '' then @@ -1649,10 +1710,21 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; DPKList.Sort; // Expand Includes IncludesL.CommaText := StringReplace(Item.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); + // Compile and Install for J := 0 to DPKList.Count - 1 do - if not DPKList[J].CompilePackage(DCC, SourcesL, IncludesL, Log, TempDir) then - Exit; + begin + // Run- & design time packages for Win32 + if not DPKList[J].CompilePackage(pltWin32, SourcesL, IncludesL, Log, TempDir) then + Exit; + + // Compile Run time packages for Win64 + // Starting from Delphi 13 compile also design packages +//##LO if DPKList[J].OnlyRuntime or (IDE >= ideDelphiFlorence) then +// if not DPKList[J].CompilePackage(pltWin64, SourcesL, IncludesL, Log, TempDir) then +// Exit; + end; + finally IncludesL.Free; DPKList.Free; @@ -1663,6 +1735,7 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; Application.ProcessMessages; end; Result := True; + finally SourcesL.Free; SpFileOperation(TempDir, '', FO_DELETE); @@ -1718,14 +1791,14 @@ function TSpExecuteList.ExecuteAll(BaseFolder: string; Log: TStrings): Boolean; if S <> '' then begin S := TPath.Combine(Item.Destination, S); - SpWriteLog(Log, SLogExecuting, S); + SpWriteLog(Log, SLogExecuting, [S]); if SpExecuteDosCommand(S, Item.Destination, DosOutput) = 0 then begin Log.Text := Log.Text + DosOutput + sLineBreak; Result := True; end else - SpWriteLog(Log, SLogErrorExecuting, S, ''); + SpWriteLog(Log, SLogErrorExecuting, [S]); end; end; @@ -1740,7 +1813,7 @@ function TSpExecuteList.ExecuteAll(BaseFolder: string; Log: TStrings): Boolean; Item.Destination := StringReplace(Item.Destination, rvBaseFolder, BaseFolder, [rfReplaceAll, rfIgnoreCase]); if not TFile.Exists(Item.Origin) then begin - SpWriteLog(Log, SLogInvalidPath, Item.Origin); + SpWriteLog(Log, SLogInvalidPath, [Item.Origin]); Exit; end; end; @@ -1756,14 +1829,14 @@ function TSpExecuteList.ExecuteAll(BaseFolder: string; Log: TStrings): Boolean; satCopy, satCopyRun: if SpFileOperation(Item.Origin, Item.Destination, FO_COPY) then begin - SpWriteLog(Log, SLogCopying, Item.Origin, Item.Destination); + SpWriteLog(Log, SLogCopying, [Item.Origin, Item.Destination]); if Item.Action = satCopyRun then if not ExecuteRun then Exit; end else begin - SpWriteLog(Log, SLogErrorCopying, Item.Origin, Item.Destination); + SpWriteLog(Log, SLogErrorCopying, [Item.Origin, Item.Destination]); Exit; end; end; @@ -1801,7 +1874,7 @@ function TSpMultiInstaller.Install(ZipPath, BaseFolder: string; IDE: TSpIDEType; if ComponentPackages.CompileAll(BaseFolder, IDE, Log) then begin Secs := (GetTickCount - N) / 1000; - SpWriteLog(Log, SLogEnd, ''); + SpWriteLog(Log, SLogEnd, []); Log.Add(Format(SLogFinished, [Secs])); // [IDE-Change] From 34cd72bf3226a52953fe1f0afb6892c1c280d015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Fri, 10 Oct 2025 10:53:21 +0200 Subject: [PATCH 14/19] Fix a few DelphiLint warnings in the form Enable the back button when the process is finished, to allow starting over --- Source/Form.Installer.pas | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index 751fe20..a78fca0 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -2,8 +2,6 @@ interface -{$WARN SYMBOL_PLATFORM OFF} -{$WARN UNIT_PLATFORM OFF} {$BOOLEVAL OFF} // Unit depends on short-circuit boolean evaluation {$IFDEF DEBUG} @@ -87,7 +85,7 @@ TFormInstall = class(TForm) procedure chkSelectAllNoneClick(Sender: TObject); private FAppPath : string; - FAutoStart: boolean; + FAutoStart: Boolean; FInstaller: TSpMultiInstaller; function ChangePage(Next: Boolean): Boolean; @@ -150,13 +148,13 @@ procedure TFormInstall.FormCreate(Sender: TObject); SaveDialog1.InitialDir := FAppPath; // Allow to turn the autostart off via command line. Default:on - if FindCmdLineswitch('A', LAutoStart) then - FAutoStart := MatchText(LautoStart, ['Yes', 'True', '1']) + if FindCmdLineSwitch('A', LAutoStart) then + FAutoStart := MatchText(LAutoStart, ['Yes', 'True', '1']) else - FAutoStart := true; + FAutoStart := True; // Allow to pass the ini file via command line - if FindCmdLineswitch('I', LSetupIni) then + if FindCmdLineSwitch('I', LSetupIni) then CreateInstaller(LSetupIni) else CreateInstaller(FAppPath + rvSetupIni); @@ -246,7 +244,7 @@ procedure TFormInstall.chkCompileInIdeClick(Sender: TObject); procedure TFormInstall.chkSelectAllNoneClick(Sender: TObject); var - I: integer; + I: Integer; begin for I := 0 to clbSelectComponents.Count - 1 do clbSelectComponents.Checked[I] := chkSelectAllNone.Checked; @@ -267,9 +265,9 @@ procedure TFormInstall.CreateInstaller(const APath: string); for I := 0 to FInstaller.ComponentPackages.Count - 1 do if not FInstaller.ComponentPackages[I].Git.IsEmpty then begin - chkGetFromGit.Enabled := true; - chkGetFromGit.Checked := true; - break; + chkGetFromGit.Enabled := True; + chkGetFromGit.Checked := True; + Break; end; if DirectoryExists(FInstaller.ComponentPackages.DefaultInstallFolder) then @@ -291,7 +289,8 @@ procedure TFormInstall.FillCheckListBox; begin P := clbSelectComponents.Items.IndexOfObject(Pointer(G)); if P > -1 then - clbSelectComponents.Items[P] := clbSelectComponents.Items[P] + #13#10 + FInstaller.ComponentPackages[I].Name; + clbSelectComponents.Items[P] := clbSelectComponents.Items[P] + sLineBreak + + FInstaller.ComponentPackages[I].Name; end; if P = -1 then @@ -299,7 +298,7 @@ procedure TFormInstall.FillCheckListBox; P := clbSelectComponents.Items.AddObject(FInstaller.ComponentPackages[I].Name, Pointer(G)); clbSelectComponents.Checked[P] := True; if FInstaller.ComponentPackages[I].Git <> '' then - clbSelectComponents.Items[P] := clbSelectComponents.Items[P] + #13#10 + + clbSelectComponents.Items[P] := clbSelectComponents.Items[P] + sLineBreak + 'GIT: ' + FInstaller.ComponentPackages[I].Git; end; end; @@ -510,7 +509,7 @@ function TFormInstall.Install: Boolean; aFinish.Visible := True; aSaveLog.Visible := True; -// aBack.Visible := False; + aBack.Enabled := False; aNext.Visible := False; aCancel.Visible := False; Application.ProcessMessages; @@ -520,6 +519,7 @@ function TFormInstall.Install: Boolean; Result := True; finally lblTitle.Caption := SFinishTitle; + aBack.Enabled := True; aFinish.Enabled := True; aSaveLog.Enabled := True; if not Result then From 53b6557ec08a4e711f1a01510bfd1ec2ae07d91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Fri, 10 Oct 2025 11:15:25 +0200 Subject: [PATCH 15/19] Fix enabling of actions when moving back after a failed install --- Source/Form.Installer.pas | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index a78fca0..559a4bd 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -94,6 +94,7 @@ TFormInstall = class(TForm) procedure CloseDelphi; procedure CreateInstaller(const APath: string); + procedure EnableNavigationActons(AEnable: Boolean); procedure FillCheckListBox; procedure FillRadioGroup; procedure WMDROPFILES(var Msg: TWMDropFiles); message WM_DROPFILES; @@ -274,6 +275,15 @@ procedure TFormInstall.CreateInstaller(const APath: string); edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; end; +procedure TFormInstall.EnableNavigationActons(AEnable: Boolean); +begin + aFinish.Visible := not AEnable; + aSaveLog.Visible := not AEnable; + aBack.Enabled := AEnable; + aNext.Visible := AEnable; + aCancel.Visible := AEnable; +end; + procedure TFormInstall.FillCheckListBox; var I, G, P: Integer; @@ -421,6 +431,7 @@ procedure TFormInstall.pbxVersionInfoClick(Sender: TObject); procedure TFormInstall.aBackExecute(Sender: TObject); begin ChangePage(False); + EnableNavigationActons(True); end; procedure TFormInstall.aNextExecute(Sender: TObject); @@ -507,11 +518,7 @@ function TFormInstall.Install: Boolean; FInstaller.ComponentPackages[J].ZipFile := ''; end; - aFinish.Visible := True; - aSaveLog.Visible := True; - aBack.Enabled := False; - aNext.Visible := False; - aCancel.Visible := False; + EnableNavigationActons(False); Application.ProcessMessages; try // Check, Unzip, Patch, Compile, Install From 2e93a9232ca5c084e796fc8900a1c94dd53313bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Fri, 10 Oct 2025 11:57:50 +0200 Subject: [PATCH 16/19] Progress towards 64-Bit component installation --- Source/SpComponentInstaller.pas | 130 ++++++++++++++++---------------- 1 file changed, 66 insertions(+), 64 deletions(-) diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index 8d87763..b7c5420 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -79,8 +79,8 @@ interface SLogExecuting = 'Executing:' + sLineBreak + ' %s'; SLogExtracting = 'Extracting:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; SLogGitCloning = 'Git cloning:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; - SLogCompiling = 'Compiling for %s Package: %s'; - SLogInstalling = 'Installing for %s Package: %s'; + SLogCompiling = 'Compiling for %s' + sLineBreak + 'Package: %s'; + SLogInstalling = 'Installing for %s' + sLineBreak + 'Package: %s'; SLogFinished = 'All the component packages have been successfully installed.' + sLineBreak + 'Elapsed time: %f secs.'; SGitCloneCommand = 'GIT.EXE clone --verbose --progress "%s" "%s"'; @@ -141,12 +141,16 @@ TSpIDETypeRec = record TSpPlatformHelper = record helper for TSpPlatform private function GetDccPath: string; + function GetKnownPackages: string; function GetName: string; + function GetOutputDir: string; function GetRegKey: string; public - property DccPath: string read GetDccPath; - property Name : string read GetName; - property RegKey : string read GetRegKey; + property DccPath : string read GetDccPath; + property KnownPackages: string read GetKnownPackages; + property Name : string read GetName; + property OutputDir : string read GetOutputDir; + property RegKey : string read GetRegKey; end; TSpDelphiIDE = class @@ -173,8 +177,8 @@ TSpDelphiIDE = class class function ExpandMacros(S: string; IDE: TSpIDEType): string; // SearchPath - class function GetSearchPath(IDE: TSpIDEType; CPPBuilderPath: Boolean): string; - class procedure AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType); + class function GetSearchPath(IDE: TSpIDEType; APlatform: TSpPlatform; CPPBuilderPath: Boolean): string; + class procedure AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType; APlatform: TSpPlatform); end; TSpActionType = (satNone, satCopy, satCopyRun, satRun); @@ -347,32 +351,27 @@ TSpDelphiDPKFilesList = class(TObjectList) function TSpPlatformHelper.GetDccPath: string; begin - if Self = pltWin32 then - Result := 'dcc32.exe' - else if Self = pltWin64 then - Result := 'dcc64.exe' - else - Result := ''; + Result := IfThen(Self = pltWin32, 'dcc32.exe', 'dcc64.exe'); +end; + +function TSpPlatformHelper.GetKnownPackages: string; +begin + Result := '\Known Packages' + IfThen(Self = pltWin32, '', ' x64'); end; function TSpPlatformHelper.GetName: string; begin - if Self = pltWin32 then - Result := 'Win32' - else if Self = pltWin64 then - Result := 'Win64' - else - Result := ''; + Result := IfThen(Self = pltWin32, 'Win32', 'Win64'); +end; + +function TSpPlatformHelper.GetOutputDir: string; +begin + Result := IfThen(Self = pltWin32, '', 'Win64'); end; function TSpPlatformHelper.GetRegKey: string; begin - if Self = pltWin32 then - Result := '\Win32' - else if Self = pltWin64 then - Result := '\Win64' - else - Result := ''; + Result := '\' + GetName; end; procedure SpOpenLink(URL: string); @@ -857,14 +856,14 @@ class function TSpDelphiIDE.GetDCCFilename(IDE: TSpIDEType; APlatform: TSpPlatfo class function TSpDelphiIDE.GetBPLOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin // BPL Output Dir - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.RegKey, 'Package DPL Output', Result); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.OutputDir, 'Package DPL Output', Result); Result := TSpDelphiIDE.ExpandMacros(Result, IDE); end; class function TSpDelphiIDE.GetDCPOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin // DCP Output Dir - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.RegKey, 'Package DCP Output', Result); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.OutputDir, 'Package DCP Output', Result); Result := TSpDelphiIDE.ExpandMacros(Result, IDE); end; @@ -1082,20 +1081,19 @@ class function TSpDelphiIDE.ExpandMacros(S: string; IDE: TSpIDEType): string; end; end; -class function TSpDelphiIDE.GetSearchPath(IDE: TSpIDEType; - CPPBuilderPath: Boolean): string; +class function TSpDelphiIDE.GetSearchPath(IDE: TSpIDEType; APlatform: TSpPlatform; CPPBuilderPath: Boolean): string; var Key, Name: string; begin Result := ''; if IDE <> ideNone then begin - SpIDESearchPathRegKey(IDE, Key, Name, CPPBuilderPath, pltWin32); //##LO Add Win64 Support later + SpIDESearchPathRegKey(IDE, Key, Name, CPPBuilderPath, APlatform); SpReadRegValue(Key, Name, Result); end; end; -class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType); +class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType; APlatform: TSpPlatform); var I : Integer; S, Key, Name: string; @@ -1105,26 +1103,26 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType SourcesL[I] := ExpandMacros(ExcludeTrailingPathDelimiter(SourcesL[I]), IDE); // Add the directory to the Delphi Win32 search path registry entry - S := GetSearchPath(IDE, False); + S := GetSearchPath(IDE, APlatform, False); if (S <> '') and (SourcesL[I] <> '') then if not SpStringSearch(S, SourcesL[I]) then begin if S[Length(S)] <> ';' then S := S + ';'; S := S + SourcesL[I]; - SpIDESearchPathRegKey(IDE, Key, Name, False, pltWin32); //##LO Add Win64 Support later + SpIDESearchPathRegKey(IDE, Key, Name, False, APlatform); SpWriteRegValue(Key, Name, S); end; // Add the directory to the C++Builder search path registry entry - S := GetSearchPath(IDE, True); + S := GetSearchPath(IDE, APlatform, True); if (S <> '') and (SourcesL[I] <> '') then if not SpStringSearch(S, SourcesL[I]) then begin if S[Length(S)] <> ';' then S := S + ';'; S := S + SourcesL[I]; - SpIDESearchPathRegKey(IDE, Key, Name, True, pltWin32); //##LO Add Win64 Support later + SpIDESearchPathRegKey(IDE, Key, Name, True, APlatform); SpWriteRegValue(Key, Name, S); end; end; @@ -1278,12 +1276,12 @@ function TSpDelphiDPKFile.CompilePackage( L := TStringList.Create; try // Add the SourcesL directories to the registry - TSpDelphiIDE.AddToSearchPath(SourcesL, FIDEVersion); + TSpDelphiIDE.AddToSearchPath(SourcesL, FIDEVersion, APlatform); // Expand SearchPath, replace $(Delphi) and $(BDS) with real directories // and enclose the paths with " " to transform it to a valid // comma delimited string for the -U switch. - L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, False), FIDEVersion); + L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, APlatform, False), FIDEVersion); L.Text := StringReplace(L.Text, ';', sLineBreak, [rfReplaceAll, rfIgnoreCase]); for I := 0 to L.Count - 1 do L[I] := '"' + L[I] + '"'; @@ -1381,8 +1379,7 @@ function TSpDelphiDPKFile.RegisterPackage(APlatform: TSpPlatform; Log: TStrings) // BPL filename BPL := TPath.Combine(TSpDelphiIDE.GetBPLOutputDir(FIDEVersion, APlatform), FBPLFilename); - //##LO double check this for Win64 - RegKey := IDETypes[FIDEVersion].IDERegistryPath + '\Known Packages'; + RegKey := IDETypes[FIDEVersion].IDERegistryPath + APlatform.KnownPackages; if FOnlyRuntime then begin @@ -1646,9 +1643,10 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; var TempDir : string; J : Integer; - Item : TSpComponentPackage; + LComponent : TSpComponentPackage; SourcesL, CompileL, IncludesL: TStringList; - DPKList : TSpDelphiDPKFilesList; + LPackageList : TSpDelphiDPKFilesList; + LPackage : TSpDelphiDPKFile; begin Result := False; if IDE = ideNone then @@ -1668,66 +1666,70 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; SourcesL := TStringList.Create; try - for Item in Self do + for LComponent in Self do begin - SpWriteLog(Log, SLogStartCompile, [Item.Name]); + SpWriteLog(Log, SLogStartCompile, [LComponent.Name]); // Expand Search Path - if Item.SearchPath <> '' then + if LComponent.SearchPath <> '' then begin - SourcesL.CommaText := Item.SearchPath; + SourcesL.CommaText := LComponent.SearchPath; // Add the destination search path for J := 0 to SourcesL.Count - 1 do - SourcesL[J] := TPath.GetFullPath(TPath.Combine(Item.Destination, SourcesL[J])); + SourcesL[J] := TPath.GetFullPath(TPath.Combine(LComponent.Destination, SourcesL[J])); end else - SourcesL.Add(Item.Destination); - Item.SearchPath := SourcesL.CommaText; + SourcesL.Add(LComponent.Destination); + LComponent.SearchPath := SourcesL.CommaText; - case Item.Installable of + case LComponent.Installable of sitNotInstallable: ; // do nothing sitSearchPathOnly: - // If the package is not installable add the SearchPath to the registry - // This is useful when installing utility libraries that doesn't have - // components to install, for example GraphicEx, GDI+, DirectX, etc - TSpDelphiIDE.AddToSearchPath(SourcesL, IDE); + begin + // If the package is not installable add the SearchPath to the registry + // This is useful when installing utility libraries that doesn't have + // components to install, for example GraphicEx, GDI+, DirectX, etc + TSpDelphiIDE.AddToSearchPath(SourcesL, IDE, pltWin32); + TSpDelphiIDE.AddToSearchPath(SourcesL, IDE, pltWin64); + end; sitInstallable: begin IncludesL := TStringList.Create; - DPKList := TSpDelphiDPKFilesList.Create; + LPackageList := TSpDelphiDPKFilesList.Create; try // Expand Packages CompileL := TStringList.Create; try - CompileL.CommaText := Item.PackageList[IDE]; + CompileL.CommaText := LComponent.PackageList[IDE]; for J := 0 to CompileL.Count - 1 do - DPKList.Add(TSpDelphiDPKFile.Create(TPath.Combine(Item.Destination, CompileL[J]), IDE)); + LPackageList.Add(TSpDelphiDPKFile.Create(TPath.Combine(LComponent.Destination, CompileL[J]), IDE)); finally CompileL.Free; end; // Runtime packages must be compiled first - DPKList.Sort; + LPackageList.Sort; + // Expand Includes - IncludesL.CommaText := StringReplace(Item.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); + IncludesL.CommaText := StringReplace(LComponent.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); // Compile and Install - for J := 0 to DPKList.Count - 1 do + for LPackage in LPackageList do begin // Run- & design time packages for Win32 - if not DPKList[J].CompilePackage(pltWin32, SourcesL, IncludesL, Log, TempDir) then + if not LPackage.CompilePackage(pltWin32, SourcesL, IncludesL, Log, TempDir) then Exit; // Compile Run time packages for Win64 // Starting from Delphi 13 compile also design packages -//##LO if DPKList[J].OnlyRuntime or (IDE >= ideDelphiFlorence) then -// if not DPKList[J].CompilePackage(pltWin64, SourcesL, IncludesL, Log, TempDir) then -// Exit; + if LPackage.OnlyRuntime or (IDE >= ideDelphiFlorence) then + if not LPackage.CompilePackage(pltWin64, SourcesL, IncludesL, Log, TempDir) then + Exit; end; finally IncludesL.Free; - DPKList.Free; + LPackageList.Free; end; end; end; From c85a99ab8739cbe5cee88286069beac0c1435b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Fri, 10 Oct 2025 14:03:47 +0200 Subject: [PATCH 17/19] Get Win64 platform compile and install up and running Bump version number Update Readme.md and Release History.txt Code Cleanup --- Readme.md | 2 +- Release History.txt | 54 ++++++++++++---------- Source/Form.Installer.pas | 2 +- Source/SpComponentInstaller.pas | 79 +++++++++++++++++---------------- 4 files changed, 73 insertions(+), 64 deletions(-) diff --git a/Readme.md b/Readme.md index 4ef636a..608ee98 100644 --- a/Readme.md +++ b/Readme.md @@ -40,7 +40,7 @@ The initial developer of this package is Robert Lee. Requirements: -- RAD Studio XE or newer +- RAD Studio XE2 or newer ## Getting Started diff --git a/Release History.txt b/Release History.txt index 1a818eb..adb123f 100644 --- a/Release History.txt +++ b/Release History.txt @@ -1,3 +1,11 @@ +10 October 2025 - version 3.6.0 + - Added RAD Studio 13 Florence support. +..- Starting from RAD Studio Florence compile and install the 64-Bit IDE packages as well + - Removed support for Delphi versions before XE2 + - The setup .ini file can now be passed on the command line or dragged onto the window. + - Made Installer window resizable. + - Code cleanup + 28 November 2023 - version 3.5.10 - Added RAD Studio 12 Athens support. - Improved IDE macros parsing speed. @@ -12,47 +20,47 @@ 24 December 2020 - version 3.5.7 - Added RAD Studio Sydney support. - + 22 January 2020 - version 3.5.6 - Code cleanup - + 26 November 2018 - version 3.5.5 - Added RAD Studio 10.3 Rio support. - Added GIT support, thanks to PyScripter 21 September 2018 - version 3.5.4 - Added RAD Studio 10.2 Tokyo support. - + 21 May 2016 - version 2.5.3 - Added support for RAD Studio XE8, RAD Studio 10 Seattle and RAD Studio 10.1 Berlin - + 28 October 2014 - version 3.5.2 - Added RAD Studio XE7 support. - + 28 May 2014 - version 3.5.1 - Added RAD Studio XE6 support. - + 18 March 2014 - version 3.5 - Added RAD Studio XE4 and XE5 support. - + 20 April 2013 - version 3.4.8 - Added Delphi XE3 and C++ Builder XE3 support. - + 7 February 2012 - version 3.4.7 - Added Delphi XE2 and C++ Builder XE2 support. - + 25 June 2011 - version 3.4.6 - Added Delphi XE and C++ Builder XE support. - + 13 September 2009 - version 3.4.5 - Added Delphi 2010 and C++ Builder 2010 support. - + 15 March 2009 - version 3.4.4 - MultiInstaller is now tri-licensed, you can choose between MPL, GPL and LGPL. - + 1 March 2009 - version 3.4.3 - - Stéphane Wierzbicki improved the SpExecuteDosCommand utility + - Stéphane Wierzbicki improved the SpExecuteDosCommand utility function and added multiple SearchPaths handling, like the Includes parameter, the SearchPath parameter should either contain one source directory or multiple ones. For the later, @@ -60,27 +68,27 @@ 17 January 2009 - version 3.4.2 - Fixed incorrect French translation of the RAD Studio Project - directory, thanks to Stéphane Wierzbicki for reporting it. - + directory, thanks to Stéphane Wierzbicki for reporting it. + 26 September 2008 - version 3.4.1 - Added Delphi 2009 and C++ Builder 2009 support. - + 4 September 2007 - version 3.4 - Added Delphi 2007 and C++ Builder 2007 support. - + 24 November 2006 - version 3.3.1 - Added extra check to use -JL compiler switch, it will be used only if the C++Builder personality is installed. - + 27 August 2006 - version 3.3 - New Logo. - Exe compressed with UPX. - Minor fixes. - + 27 June 2006 - version 3.2 - Added multilanguage support for Delphi and C++Builder, it now supports English, French, German and Japanese IDEs. - + 15 June 2006 - version 3.1 - Added Environment Variables Overrides support, thanks to Wyk for implementing this. @@ -90,15 +98,15 @@ - Improved the "Intallable" directive, it is now possible to install a package that doesn't have components, this is useful when installing utility libraries, for example GraphicEx, GDI+, DirectX, etc. - + 27 February 2006 - version 3.0 - Added support for C++Builder 2006. - + 10 February 2006 - version 2.0 - Added support for BDS 2006. - Added support for $LIBSUFFIX package compiler directive. - Added DefaultInstallFolder and DefaultInstallIDE Ini key options. - Replaced the zip library for Abbrevia. - + 18 August 2005 - version 1.0 - Initial release. \ No newline at end of file diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index 559a4bd..e6bce04 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -115,7 +115,7 @@ implementation System.UITypes; const - rvMultiInstallerVersion = 'Silverpoint MultiInstaller 3.5.10'; + rvMultiInstallerVersion = 'Silverpoint MultiInstaller 3.6.0'; rvMultiInstallerLink = 'http://www.silverpointdevelopment.com'; rvSetupIni = 'Setup.Ini'; crIDC_HAND = 32649; diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index b7c5420..f0dc937 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -140,16 +140,16 @@ TSpIDETypeRec = record TSpPlatformHelper = record helper for TSpPlatform private + function GetDccConfig: string; function GetDccPath: string; function GetKnownPackages: string; function GetName: string; - function GetOutputDir: string; function GetRegKey: string; public + property DccConfig : string read GetDccConfig; property DccPath : string read GetDccPath; property KnownPackages: string read GetKnownPackages; property Name : string read GetName; - property OutputDir : string read GetOutputDir; property RegKey : string read GetRegKey; end; @@ -157,7 +157,8 @@ TSpDelphiIDE = class private class var FCachedMacrosCommaDelimited: string; class var FCachedMacrosIDE : TSpIDEType; - class procedure GetMacros(IDE: TSpIDEType; NamesAndValues: TStringList); + class var FCachedMacrosPlatform : TSpPlatform; + class procedure GetMacros(IDE: TSpIDEType; APlatform: TSpPlatform; NamesAndValues: TStringList); public // IDE class function Installed(IDE: TSpIDEType): Boolean; @@ -174,7 +175,7 @@ TSpDelphiIDE = class // Macros class function ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: TStringList): Boolean; - class function ExpandMacros(S: string; IDE: TSpIDEType): string; + class function ExpandMacros(S: string; IDE: TSpIDEType; APlatform: TSpPlatform): string; // SearchPath class function GetSearchPath(IDE: TSpIDEType; APlatform: TSpPlatform; CPPBuilderPath: Boolean): string; @@ -325,6 +326,8 @@ TSpDelphiDPKFile = class procedure CreateAndCopyEmptyResIfNeeded; function RegisterPackage(APlatform: TSpPlatform; Log: TStrings): Boolean; public + constructor Create(const Filename: string; IDE: TSpIDEType); virtual; + function CompilePackage(APlatform: TSpPlatform; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; property DPKFilename : string read FDPKFilename; property BPLFilename : string read FBPLFilename; property Exists : Boolean read FExists; @@ -333,8 +336,6 @@ TSpDelphiDPKFile = class property Description : string read FDescription; property LibSuffix : string read FLibSuffix; property IDEVersion : TSpIDEType read FIDEVersion; - constructor Create(const Filename: string; IDE: TSpIDEType); virtual; - function CompilePackage(APlatform: TSpPlatform; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; end; TSpDelphiDPKFilesList = class(TObjectList) @@ -349,6 +350,11 @@ TSpDelphiDPKFilesList = class(TObjectList) { TSpPlatformHelper } +function TSpPlatformHelper.GetDccConfig: string; +begin + Result := IfThen(Self = pltWin32, 'dcc32.cfg', 'dcc64.cfg'); +end; + function TSpPlatformHelper.GetDccPath: string; begin Result := IfThen(Self = pltWin32, 'dcc32.exe', 'dcc64.exe'); @@ -364,11 +370,6 @@ function TSpPlatformHelper.GetName: string; Result := IfThen(Self = pltWin32, 'Win32', 'Win64'); end; -function TSpPlatformHelper.GetOutputDir: string; -begin - Result := IfThen(Self = pltWin32, '', 'Win64'); -end; - function TSpPlatformHelper.GetRegKey: string; begin Result := '\' + GetName; @@ -542,8 +543,7 @@ function SpExecuteDosCommand(CommandLine, WorkDir: string; out OutputString: str CloseHandle(PipeWrite); CloseHandle(PipeRead); - if TempOutput <> '' then - OutputString := OutputString + MuteCRTerminatedLines(TempOutput); + OutputString := MuteCRTerminatedLines(TempOutput); end; function SpFileOperation(Origin, Destination: string; Operation: Cardinal): Boolean; @@ -780,7 +780,7 @@ procedure SpIDESearchPathRegKey(IDE: TSpIDEType; out Key, Name: string; CPPBuild if CPPBuilderPath then begin Name := 'LibraryPath'; - Key := Key + '\C++\Paths'; // '\C++\Paths\Win32\LibraryPath' with no space in the middle for C++Builder XE2 and above + Key := Key + '\C++\Paths'; // '\C++\Paths\\LibraryPath' with no space in the middle for C++Builder XE2 and above end else begin @@ -856,15 +856,15 @@ class function TSpDelphiIDE.GetDCCFilename(IDE: TSpIDEType; APlatform: TSpPlatfo class function TSpDelphiIDE.GetBPLOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin // BPL Output Dir - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.OutputDir, 'Package DPL Output', Result); - Result := TSpDelphiIDE.ExpandMacros(Result, IDE); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.RegKey, 'Package DPL Output', Result); + Result := TSpDelphiIDE.ExpandMacros(Result, IDE, APlatform); end; class function TSpDelphiIDE.GetDCPOutputDir(IDE: TSpIDEType; APlatform: TSpPlatform): string; begin // DCP Output Dir - SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.OutputDir, 'Package DCP Output', Result); - Result := TSpDelphiIDE.ExpandMacros(Result, IDE); + SpReadRegValue(IDETypes[IDE].IDERegistryPath + '\Library' + APlatform.RegKey, 'Package DCP Output', Result); + Result := TSpDelphiIDE.ExpandMacros(Result, IDE, APlatform); end; class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: TStringList): Boolean; @@ -892,30 +892,30 @@ class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: begin Doc := TXMLDocument.Create(Filename); Root := Doc.ChildNodes.FindNode('Project'); - if Root <> nil then + if Assigned(Root) then begin Root := Root.ChildNodes.FindNode('PropertyGroup'); - if Root <> nil then + if Assigned(Root) then begin // Add $(Delphi), $(BDS), $(BDSPROJECTSDIR), $(BDSCOMMONDIR), // $(BDSUSERDIR), $(BDSLIB) macros Node := Root.ChildNodes.FindNode('Delphi'); - if Node <> nil then + if Assigned(Node) then NamesAndValues.AddPair('Delphi', Node.Text); Node := Root.ChildNodes.FindNode('BDS'); - if Node <> nil then + if Assigned(Node) then NamesAndValues.AddPair('BDS', Node.Text); Node := Root.ChildNodes.FindNode('BDSPROJECTSDIR'); - if Node <> nil then + if Assigned(Node) then NamesAndValues.AddPair('BDSPROJECTSDIR', Node.Text); Node := Root.ChildNodes.FindNode('BDSCOMMONDIR'); - if Node <> nil then + if Assigned(Node) then NamesAndValues.AddPair('BDSCOMMONDIR', Node.Text); Node := Root.ChildNodes.FindNode('BDSUSERDIR'); - if Node <> nil then + if Assigned(Node) then NamesAndValues.AddPair('BDSUSERDIR', Node.Text); Node := Root.ChildNodes.FindNode('BDSLIB'); - if Node <> nil then + if Assigned(Node) then NamesAndValues.AddPair('BDSLIB', Node.Text); Result := True; end; @@ -924,7 +924,7 @@ class function TSpDelphiIDE.ReadEnvironmentProj(IDE: TSpIDEType; NamesAndValues: end; end; -class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringList); +class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; APlatform: TSpPlatform; NamesAndValues: TStringList); // Get $(Delphi), $(BDS), $(BDSPROJECTSDIR), $(BDSCOMMONDIR), // $(BDSUSERDIR), $(BDSLIB) macros and IDE Environment Variables Overrides // with full directory paths. @@ -940,7 +940,7 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL I := DefaultL.IndexOfName(Macro); if I >= 0 then begin - // No override found, use default value + // No override found, use default value OverrideL.Values[Macro] := DefaultL.ValueFromIndex[I]; Result := True; end; @@ -1044,17 +1044,18 @@ class procedure TSpDelphiIDE.GetMacros(IDE: TSpIDEType; NamesAndValues: TStringL // $(PLATFORM) // Not sure were to find this macro - // Since we're using DCC32 to compile assume Win32 - NamesAndValues.Values['PLATFORM'] := 'Win32'; + // Assume the platform name + NamesAndValues.Values['PLATFORM'] := APlatform.Name; FCachedMacrosCommaDelimited := NamesAndValues.CommaText; FCachedMacrosIDE := IDE; + FCachedMacrosPlatform := APlatform; finally DefaultL.Free; end; end; -class function TSpDelphiIDE.ExpandMacros(S: string; IDE: TSpIDEType): string; +class function TSpDelphiIDE.ExpandMacros(S: string; IDE: TSpIDEType; APlatform: TSpPlatform): string; // Replace $(Delphi), $(BDS), $(BDSPROJECTSDIR), $(BDSCOMMONDIR), // $(BDSUSERDIR), $(BDSLIB) macros and IDE Environment Variables Overrides // with full directory paths. @@ -1069,10 +1070,10 @@ class function TSpDelphiIDE.ExpandMacros(S: string; IDE: TSpIDEType): string; L := TStringList.Create; try - if (FCachedMacrosIDE = IDE) and not FCachedMacrosCommaDelimited.IsEmpty then + if (FCachedMacrosIDE = IDE) and (FCachedMacrosPlatform = APlatform) and not FCachedMacrosCommaDelimited.IsEmpty then L.CommaText := FCachedMacrosCommaDelimited // use the cached macros else - GetMacros(IDE, L); + GetMacros(IDE, APlatform, L); // Replace all for I := 0 to L.Count - 1 do Result := StringReplace(Result, '$(' + L.Names[I] + ')', ExcludeTrailingPathDelimiter(L.ValueFromIndex[I]), [rfReplaceAll, rfIgnoreCase]); @@ -1100,9 +1101,9 @@ class procedure TSpDelphiIDE.AddToSearchPath(SourcesL: TStrings; IDE: TSpIDEType begin for I := 0 to SourcesL.Count - 1 do begin - SourcesL[I] := ExpandMacros(ExcludeTrailingPathDelimiter(SourcesL[I]), IDE); + SourcesL[I] := ExpandMacros(ExcludeTrailingPathDelimiter(SourcesL[I]), IDE, APlatform); - // Add the directory to the Delphi Win32 search path registry entry + // Add the directory to the Delphi Win32/Win64 search path registry entry S := GetSearchPath(IDE, APlatform, False); if (S <> '') and (SourcesL[I] <> '') then if not SpStringSearch(S, SourcesL[I]) then @@ -1263,7 +1264,7 @@ function TSpDelphiDPKFile.CompilePackage( CommandLine := DCC + ' -Q ' + TPath.GetFileName(FDPKFilename); WorkDir := TPath.GetDirectoryName(FDPKFilename); - // Create and save DCC32.CFG file on the Package directory + // Create and save DCC32/64.CFG file on the Package directory // Example of cfg file: // -U"$(BDSLIB)\$(Platform)\release";"C:\TB2K\Source";"C:\SpTBXLib\Source" // -R"C:\SpTBXLib\Source" @@ -1281,7 +1282,7 @@ function TSpDelphiDPKFile.CompilePackage( // Expand SearchPath, replace $(Delphi) and $(BDS) with real directories // and enclose the paths with " " to transform it to a valid // comma delimited string for the -U switch. - L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, APlatform, False), FIDEVersion); + L.Text := TSpDelphiIDE.ExpandMacros(TSpDelphiIDE.GetSearchPath(FIDEVersion, APlatform, False), FIDEVersion, APlatform); L.Text := StringReplace(L.Text, ';', sLineBreak, [rfReplaceAll, rfIgnoreCase]); for I := 0 to L.Count - 1 do L[I] := '"' + L[I] + '"'; @@ -1289,8 +1290,8 @@ function TSpDelphiDPKFile.CompilePackage( if S[Length(S)] = ';' then Delete(S, Length(S), 1); - // Save the DCC32.CFG file on the Package directory - DCCConfig := TPath.Combine(WorkDir, 'DCC32.CFG'); + // Save the DCC32/64.CFG file on the Package directory + DCCConfig := TPath.Combine(WorkDir, APlatform.DccConfig); R := IDETypes[FIDEVersion].IDERegistryPath; L.Clear; // SearchPath From 5bb00fd8ba41e038d2b32df0e3b3ded69f104e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Tue, 4 Nov 2025 15:06:05 +0100 Subject: [PATCH 18/19] Re-Initialize the installer when stepping back to the start Log whether we are working on a run-time or a design-time package Remove the unneccessary "compile & install in IDE" checkbox --- Source/Form.Installer.dfm | 13 ++-------- Source/Form.Installer.pas | 46 ++++++++++++++++----------------- Source/SpComponentInstaller.pas | 20 +++++++++++--- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/Source/Form.Installer.dfm b/Source/Form.Installer.dfm index 3afe2c6..f15a297 100644 --- a/Source/Form.Installer.dfm +++ b/Source/Form.Installer.dfm @@ -65,6 +65,7 @@ object FormInstall: TFormInstall Top = 231 Width = 97 Height = 17 + Anchors = [akLeft, akBottom] Caption = 'Select all/none' TabOrder = 2 OnClick = chkSelectAllNoneClick @@ -110,20 +111,10 @@ object FormInstall: TFormInstall Width = 473 Height = 171 Anchors = [akLeft, akTop, akRight, akBottom] - Caption = ' ' + Caption = ' Select target IDE' Columns = 2 - Enabled = False TabOrder = 2 end - object chkCompileInIde: TCheckBox - Left = 20 - Top = 78 - Width = 195 - Height = 17 - Caption = 'Compile packages and install in IDE' - TabOrder = 3 - OnClick = chkCompileInIdeClick - end end object tshInstallation: TTabSheet Caption = 'tshInstallation' diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index e6bce04..ff9bae8 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -53,7 +53,6 @@ TFormInstall = class(TForm) aSaveLog: TAction; aFinish: TAction; rgSelectIde: TRadioGroup; - chkCompileInIde: TCheckBox; lblInstallation: TLabel; lblInstallationFinished: TLabel; bvlTop: TBevel; @@ -73,7 +72,6 @@ TFormInstall = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); - procedure chkCompileInIdeClick(Sender: TObject); procedure clbSelectComponentsDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); procedure clbSelectComponentsMeasureItem(Control: TWinControl; @@ -85,6 +83,7 @@ TFormInstall = class(TForm) procedure chkSelectAllNoneClick(Sender: TObject); private FAppPath : string; + FIniPath : string; FAutoStart: Boolean; FInstaller: TSpMultiInstaller; @@ -93,8 +92,8 @@ TFormInstall = class(TForm) function ValidateCheckListBox: Boolean; procedure CloseDelphi; - procedure CreateInstaller(const APath: string); - procedure EnableNavigationActons(AEnable: Boolean); + procedure CreateInstaller; + procedure EnableNavigationActions(AEnable: Boolean); procedure FillCheckListBox; procedure FillRadioGroup; procedure WMDROPFILES(var Msg: TWMDropFiles); message WM_DROPFILES; @@ -156,9 +155,10 @@ procedure TFormInstall.FormCreate(Sender: TObject); // Allow to pass the ini file via command line if FindCmdLineSwitch('I', LSetupIni) then - CreateInstaller(LSetupIni) + FIniPath := LSetupIni else - CreateInstaller(FAppPath + rvSetupIni); + FIniPath := FAppPath + rvSetupIni; + CreateInstaller; {$IFDEF SPDEBUGMODE} ReportMemoryLeaksOnShutdown := True; @@ -177,7 +177,7 @@ procedure TFormInstall.FormShow(Sender: TObject); if DirectoryExists(FInstaller.ComponentPackages.DefaultInstallFolder) then begin edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; - if FAutoStart and chkCompileInIde.Checked then + if FAutoStart then begin PageControl1.ActivePageIndex := PageControl1.PageCount - 1; Timer1.Enabled := True; // Delay it a little for UI responsiveness @@ -225,7 +225,10 @@ function TFormInstall.ChangePage(Next: Boolean): Boolean; btnBack.Enabled := I > 0; case I of 0: - lblTitle.Caption := SWelcomeTitle; + begin + lblTitle.Caption := SWelcomeTitle; + CreateInstaller; + end; 1: lblTitle.Caption := SDestinationTitle; 2: @@ -238,11 +241,6 @@ function TFormInstall.ChangePage(Next: Boolean): Boolean; end; end; -procedure TFormInstall.chkCompileInIdeClick(Sender: TObject); -begin - rgSelectIde.Enabled := chkCompileInIde.Checked; -end; - procedure TFormInstall.chkSelectAllNoneClick(Sender: TObject); var I: Integer; @@ -251,13 +249,13 @@ procedure TFormInstall.chkSelectAllNoneClick(Sender: TObject); clbSelectComponents.Checked[I] := chkSelectAllNone.Checked; end; -procedure TFormInstall.CreateInstaller(const APath: string); +procedure TFormInstall.CreateInstaller; var I: Integer; begin FreeAndNil(FInstaller); - FInstaller := TSpMultiInstaller.Create(APath); + FInstaller := TSpMultiInstaller.Create(FIniPath); FillCheckListBox; FillRadioGroup; ValidateCheckListBox; @@ -275,7 +273,7 @@ procedure TFormInstall.CreateInstaller(const APath: string); edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; end; -procedure TFormInstall.EnableNavigationActons(AEnable: Boolean); +procedure TFormInstall.EnableNavigationActions(AEnable: Boolean); begin aFinish.Visible := not AEnable; aSaveLog.Visible := not AEnable; @@ -332,9 +330,7 @@ procedure TFormInstall.FillRadioGroup; end; if rgSelectIde.ItemIndex = -1 then - rgSelectIde.ItemIndex := rgSelectIde.Items.Count - 1 - else - chkCompileInIde.Checked := True; + rgSelectIde.ItemIndex := rgSelectIde.Items.Count - 1; end; function TFormInstall.ValidateCheckListBox: Boolean; @@ -373,7 +369,10 @@ procedure TFormInstall.WMDROPFILES(var Msg: TWMDropFiles); DragQueryFile(LDropHandle, 0, PChar(LFileName), FileNameLength + 1); LFileExt := ExtractFileExt(LFileName); if SameText(LFileExt, '.ini') then - CreateInstaller(LFileName); + begin + FIniPath := LFileName; + CreateInstaller; + end; end; finally @@ -431,7 +430,8 @@ procedure TFormInstall.pbxVersionInfoClick(Sender: TObject); procedure TFormInstall.aBackExecute(Sender: TObject); begin ChangePage(False); - EnableNavigationActons(True); + EnableNavigationActions(True); + lblInstallationFinished.Visible := False; end; procedure TFormInstall.aNextExecute(Sender: TObject); @@ -494,7 +494,7 @@ function TFormInstall.Install: Boolean; // Get IDE version IDE := ideNone; I := rgSelectIde.ItemIndex; - if chkCompileInIde.Checked and (I > -1) and Assigned(rgSelectIde.Items.Objects[I]) then + if (I > -1) and Assigned(rgSelectIde.Items.Objects[I]) then IDE := TSpIDEType(rgSelectIde.Items.Objects[I]); // Delete unchecked components from the ComponentPackages list @@ -518,7 +518,7 @@ function TFormInstall.Install: Boolean; FInstaller.ComponentPackages[J].ZipFile := ''; end; - EnableNavigationActons(False); + EnableNavigationActions(False); Application.ProcessMessages; try // Check, Unzip, Patch, Compile, Install diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index f0dc937..9a36e43 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -79,8 +79,8 @@ interface SLogExecuting = 'Executing:' + sLineBreak + ' %s'; SLogExtracting = 'Extracting:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; SLogGitCloning = 'Git cloning:' + sLineBreak + ' %s' + sLineBreak + 'To:' + sLineBreak + ' %s'; - SLogCompiling = 'Compiling for %s' + sLineBreak + 'Package: %s'; - SLogInstalling = 'Installing for %s' + sLineBreak + 'Package: %s'; + SLogCompiling = 'Compiling %s package for %s' + sLineBreak + 'Package: %s'; + SLogInstalling = 'Installing %s package for %s' + sLineBreak + 'Package: %s'; SLogFinished = 'All the component packages have been successfully installed.' + sLineBreak + 'Elapsed time: %f secs.'; SGitCloneCommand = 'GIT.EXE clone --verbose --progress "%s" "%s"'; @@ -323,8 +323,10 @@ TSpDelphiDPKFile = class FDescription : string; FLibSuffix : string; FIDEVersion : TSpIDEType; + function GetPackageType: string; procedure CreateAndCopyEmptyResIfNeeded; function RegisterPackage(APlatform: TSpPlatform; Log: TStrings): Boolean; + property PackageType: string read GetPackageType; public constructor Create(const Filename: string; IDE: TSpIDEType); virtual; function CompilePackage(APlatform: TSpPlatform; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; @@ -1223,6 +1225,16 @@ procedure TSpDelphiDPKFile.CreateAndCopyEmptyResIfNeeded; end; end; +function TSpDelphiDPKFile.GetPackageType: string; +begin + if OnlyRuntime then + Result := 'run time' + else if OnlyDesigntime then + Result := 'design time' + else + Result := 'unknown' +end; + function TSpDelphiDPKFile.CompilePackage( APlatform: TSpPlatform; SourcesL, IncludesL, @@ -1347,7 +1359,7 @@ function TSpDelphiDPKFile.CompilePackage( CreateAndCopyEmptyResIfNeeded; // Compile - SpWriteLog(Log, SLogCompiling, [APlatform.Name, FDPKFilename]); + SpWriteLog(Log, SLogCompiling, [PackageType, APlatform.Name, FDPKFilename]); try Result := SpExecuteDosCommand(CommandLine, WorkDir, DOSOutput) = 0; if Assigned(Log) then @@ -1392,7 +1404,7 @@ function TSpDelphiDPKFile.RegisterPackage(APlatform: TSpPlatform; Log: TStrings) begin if SpWriteRegValue(RegKey, BPL, FDescription) then begin - SpWriteLog(Log, SLogInstalling, [APlatform.Name, FDPKFilename]); + SpWriteLog(Log, SLogInstalling, [PackageType, APlatform.Name, FDPKFilename]); Result := True; end; end; From 81a6e91e391658e10a3483a0947c92e22b63d895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCbbe=20Onken?= Date: Tue, 4 Nov 2025 15:39:28 +0100 Subject: [PATCH 19/19] Improve en-/disabling of navigation actions Emit an error when no package is defined for the selected IDE --- Source/Form.Installer.pas | 38 +++++++++++++++++------------- Source/SpComponentInstaller.pas | 41 +++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/Source/Form.Installer.pas b/Source/Form.Installer.pas index ff9bae8..0c3f2d7 100644 --- a/Source/Form.Installer.pas +++ b/Source/Form.Installer.pas @@ -93,9 +93,9 @@ TFormInstall = class(TForm) procedure CloseDelphi; procedure CreateInstaller; - procedure EnableNavigationActions(AEnable: Boolean); procedure FillCheckListBox; procedure FillRadioGroup; + procedure ShowNavigationActions(AFinalStep: Boolean); procedure WMDROPFILES(var Msg: TWMDropFiles); message WM_DROPFILES; end; @@ -273,15 +273,6 @@ procedure TFormInstall.CreateInstaller; edtInstallFolder.Text := FInstaller.ComponentPackages.DefaultInstallFolder; end; -procedure TFormInstall.EnableNavigationActions(AEnable: Boolean); -begin - aFinish.Visible := not AEnable; - aSaveLog.Visible := not AEnable; - aBack.Enabled := AEnable; - aNext.Visible := AEnable; - aCancel.Visible := AEnable; -end; - procedure TFormInstall.FillCheckListBox; var I, G, P: Integer; @@ -369,10 +360,10 @@ procedure TFormInstall.WMDROPFILES(var Msg: TWMDropFiles); DragQueryFile(LDropHandle, 0, PChar(LFileName), FileNameLength + 1); LFileExt := ExtractFileExt(LFileName); if SameText(LFileExt, '.ini') then - begin - FIniPath := LFileName; - CreateInstaller; - end; + begin + FIniPath := LFileName; + CreateInstaller; + end; end; finally @@ -423,6 +414,15 @@ procedure TFormInstall.pbxVersionInfoClick(Sender: TObject); SpOpenLink(rvMultiInstallerLink); end; +procedure TFormInstall.ShowNavigationActions(AFinalStep: Boolean); +begin + aFinish.Visible := AFinalStep; + aSaveLog.Visible := AFinalStep; + aNext.Visible := not AFinalStep; + aCancel.Visible := not AFinalStep; +end; + + //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM {$REGION 'Actions'} @@ -430,7 +430,7 @@ procedure TFormInstall.pbxVersionInfoClick(Sender: TObject); procedure TFormInstall.aBackExecute(Sender: TObject); begin ChangePage(False); - EnableNavigationActions(True); + ShowNavigationActions(False); lblInstallationFinished.Visible := False; end; @@ -518,7 +518,12 @@ function TFormInstall.Install: Boolean; FInstaller.ComponentPackages[J].ZipFile := ''; end; - EnableNavigationActions(False); + ShowNavigationActions(True); + aBack.Enabled := False; + aFinish.Enabled := False; + aSaveLog.Enabled := False; + lblInstallationFinished.Visible := False; + Application.ProcessMessages; try // Check, Unzip, Patch, Compile, Install @@ -529,6 +534,7 @@ function TFormInstall.Install: Boolean; aBack.Enabled := True; aFinish.Enabled := True; aSaveLog.Enabled := True; + lblInstallationFinished.Visible := True; if not Result then begin lblInstallationFinished.Font.Color := clRed; diff --git a/Source/SpComponentInstaller.pas b/Source/SpComponentInstaller.pas index 9a36e43..8e577c6 100644 --- a/Source/SpComponentInstaller.pas +++ b/Source/SpComponentInstaller.pas @@ -68,6 +68,7 @@ interface SLogCorruptedZip = 'Error: %s is corrupted.'; SLogGitCloneFailed = 'Error: in Git clone %s'; SLogGitNotInstalled = 'Error: Git not installed'; + SLogErrorNoPackage = 'Error: No package defined for %s'; SLogErrorCopying = 'Error copying %s to %s'; SLogErrorDeleting = 'Error deleting %s'; @@ -330,14 +331,14 @@ TSpDelphiDPKFile = class public constructor Create(const Filename: string; IDE: TSpIDEType); virtual; function CompilePackage(APlatform: TSpPlatform; SourcesL, IncludesL, Log: TStrings; TempDir: string = ''): Boolean; - property DPKFilename : string read FDPKFilename; - property BPLFilename : string read FBPLFilename; - property Exists : Boolean read FExists; - property OnlyRuntime : Boolean read FOnlyRuntime; + property DPKFilename: string read FDPKFilename; + property BPLFilename: string read FBPLFilename; + property Exists: Boolean read FExists; + property OnlyRuntime: Boolean read FOnlyRuntime; property OnlyDesigntime: Boolean read FOnlyDesigntime; - property Description : string read FDescription; - property LibSuffix : string read FLibSuffix; - property IDEVersion : TSpIDEType read FIDEVersion; + property Description: string read FDescription; + property LibSuffix: string read FLibSuffix; + property IDEVersion: TSpIDEType read FIDEVersion; end; TSpDelphiDPKFilesList = class(TObjectList) @@ -1727,18 +1728,24 @@ function TSpComponentPackageList.CompileAll(BaseFolder: string; IDE: TSpIDEType; IncludesL.CommaText := StringReplace(LComponent.Includes, rvBaseFolder, ExcludeTrailingPathDelimiter(BaseFolder), [rfReplaceAll, rfIgnoreCase]); // Compile and Install - for LPackage in LPackageList do + if LPackageList.Count = 0 then begin - // Run- & design time packages for Win32 - if not LPackage.CompilePackage(pltWin32, SourcesL, IncludesL, Log, TempDir) then - Exit; - - // Compile Run time packages for Win64 - // Starting from Delphi 13 compile also design packages - if LPackage.OnlyRuntime or (IDE >= ideDelphiFlorence) then - if not LPackage.CompilePackage(pltWin64, SourcesL, IncludesL, Log, TempDir) then + SpWriteLog(Log, SLogErrorNoPackage, [IDETypes[IDE].IDEName]); + Exit; + end + else + for LPackage in LPackageList do + begin + // Run- & design time packages for Win32 + if not LPackage.CompilePackage(pltWin32, SourcesL, IncludesL, Log, TempDir) then Exit; - end; + + // Compile Run time packages for Win64 + // Starting from Delphi 13 compile also design packages + if LPackage.OnlyRuntime or (IDE >= ideDelphiFlorence) then + if not LPackage.CompilePackage(pltWin64, SourcesL, IncludesL, Log, TempDir) then + Exit; + end; finally IncludesL.Free;