From ebad154bc61a6a6b5fc97802f399eada03161cf5 Mon Sep 17 00:00:00 2001 From: Juha Date: Mon, 17 Jul 2023 20:12:07 +0300 Subject: [PATCH] DockedFormEditor: Prevent an eternal loop when an invalid LFM file causes a read error. Issue #39288. --- .../source/dockeddesignform.pas | 46 +++++++++++++++++-- .../source/dockedregister.pas | 5 +- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/components/dockedformeditor/source/dockeddesignform.pas b/components/dockedformeditor/source/dockeddesignform.pas index e120b22b4b..a67cd43a6e 100644 --- a/components/dockedformeditor/source/dockeddesignform.pas +++ b/components/dockedformeditor/source/dockeddesignform.pas @@ -23,7 +23,7 @@ uses // LCL LMessages, Forms, LCLType, LCLIntf, Controls, // IDEIntf - SrcEditorIntf, + SrcEditorIntf, LazIDEIntf, ProjectIntf, // DockedFormEditor DockedFormAccesses, DockedBasicAnchorDesigner; @@ -32,10 +32,13 @@ const WM_BOUNDTODESIGNTABSHEET = WM_USER + 1; type + TDesignForms = class; + { TDesignForm } TDesignForm = class(TDesignFormIDE) private + FContainer: TDesignForms; FHiding: Boolean; FOnAdjustPageNeeded: TNotifyEvent; FWndMethod: TWndMethod; @@ -53,14 +56,21 @@ type { TDesignForms } TDesignForms = class(specialize TFPGList) + private + FProjectOpening: Boolean; public + constructor Create; destructor Destroy; override; + function Add(const Item: TDesignForm): Integer; procedure DeleteDesignForm(AIndex: Integer); function Find(AForm: TCustomForm): TDesignForm; overload; function Find(ADesigner: TIDesigner): TDesignForm; overload; function IndexOf(AForm: TCustomForm): Integer; overload; procedure Remove(AForm: TCustomForm); overload; procedure RemoveAllAnchorDesigner; + // Project state change event handlers. + function ProjOpening(Sender: TObject; AProject: TLazProject): TModalResult; + function ProjOpened(Sender: TObject; AProject: TLazProject): TModalResult; end; var @@ -74,6 +84,11 @@ procedure TDesignForm.FixF12_ActiveEditor; var i: Integer; begin + // Don't get a form's designer while project opens. + // A read error would lead to an eternal loop. + Assert(Assigned(FContainer), 'TDesignForm.FixF12_ActiveEditor: FContainer=Nil'); + if FContainer.FProjectOpening then Exit; + // Without this, button F12 don't work. (after creating new for editor is inactive) // Just do it for new created forms or the last loaded form becomes the active // source editor after reopening a project. @@ -161,13 +176,28 @@ end; { TDesignForms } +constructor TDesignForms.Create; +begin + inherited; + LazarusIDE.AddHandlerOnProjectOpening(@ProjOpening); + LazarusIDE.AddHandlerOnProjectOpened(@ProjOpened); +end; + destructor TDesignForms.Destroy; begin + //LazarusIDE.RemoveHandlerOnProjectOpened(@ProjOpened); // Causes a crash. + //LazarusIDE.RemoveHandlerOnProjectOpening(@ProjOpening); while Count > 0 do DeleteDesignForm(0); inherited Destroy; end; +function TDesignForms.Add(const Item: TDesignForm): Integer; +begin + Item.FContainer := Self; + inherited; +end; + procedure TDesignForms.DeleteDesignForm(AIndex: Integer); var LDesignForm: TDesignForm; @@ -235,11 +265,17 @@ begin end; end; -initialization - DesignForms := TDesignForms.Create; +function TDesignForms.ProjOpening(Sender: TObject; AProject: TLazProject): TModalResult; +begin + FProjectOpening := True; + Result := mrOK; +end; -finalization - FreeAndNil(DesignForms); +function TDesignForms.ProjOpened(Sender: TObject; AProject: TLazProject): TModalResult; +begin + FProjectOpening := False; + Result := mrOK; +end; end. diff --git a/components/dockedformeditor/source/dockedregister.pas b/components/dockedformeditor/source/dockedregister.pas index 04ae8bae64..b31bfe575e 100644 --- a/components/dockedformeditor/source/dockedregister.pas +++ b/components/dockedformeditor/source/dockedregister.pas @@ -24,7 +24,7 @@ uses SrcEditorIntf, IDEWindowIntf, PropEdits, ComponentEditors, IDEOptEditorIntf, IDEOptionsIntf, // DockedFormEditor - DockedMainIDE, DockedOptionsIDE, DockedOptionsFrame; + DockedMainIDE, DockedDesignForm, DockedOptionsIDE, DockedOptionsFrame; var DockedOptionsFrameID: Integer = 1000; @@ -61,12 +61,13 @@ begin DockedOptions.LoadSafe; IDETabMaster := TDockedTabMaster.Create; + DesignForms := TDesignForms.Create; end; finalization Screen.RemoveHandlerFormAdded(TDockedMainIDE.Screen_FormAdded); Screen.RemoveHandlerRemoveForm(TDockedMainIDE.Screen_FormDel); - + FreeAndNil(DesignForms); FreeAndNil(IDETabMaster); FreeAndNil(DockedOptions); end.