From ab94abe6d83a27a8005b5f84781302c50ebe8ad7 Mon Sep 17 00:00:00 2001 From: juha Date: Mon, 14 Nov 2011 09:32:50 +0000 Subject: [PATCH] IDE / Designer: fix access violation when switching designer / lfm source. Issue #18506 git-svn-id: trunk@33522 - --- designer/designer.pp | 21 ++++++++++++++++----- ide/main.pp | 29 ++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/designer/designer.pp b/designer/designer.pp index d4885308bc..441974431b 100644 --- a/designer/designer.pp +++ b/designer/designer.pp @@ -92,6 +92,8 @@ type FGridColor: TColor; FLookupRoot: TComponent; FMediator: TDesignerMediator; + FFreeComponent: boolean; + FProcessingDesignerEvent: Integer; FOnActivated: TNotifyEvent; FOnCloseQuery: TNotifyEvent; FOnShowObjectInspector: TNotifyEvent; @@ -250,7 +252,8 @@ type constructor Create(TheDesignerForm: TCustomForm; AControlSelection: TControlSelection); - procedure FreeDesigner(FreeComponent: boolean); + procedure PrepareFreeDesigner(AFreeComponent: boolean); + procedure FinalizeFreeDesigner; destructor Destroy; override; procedure Modified; override; @@ -312,6 +315,7 @@ type property IsControl: Boolean read GetIsControl write SetIsControl; property LookupRoot: TComponent read FLookupRoot; property Mediator: TDesignerMediator read FMediator write SetMediator; + property ProcessingDesignerEvent: Integer read FProcessingDesignerEvent; property OnActivated: TNotifyEvent read FOnActivated write FOnActivated; property OnCloseQuery: TNotifyEvent read FOnCloseQuery write FOnCloseQuery; property OnPersistentDeleted: TOnPersistentDeleted @@ -618,7 +622,12 @@ begin FPopupMenuComponentEditor := nil; end; -procedure TDesigner.FreeDesigner(FreeComponent: boolean); +procedure TDesigner.PrepareFreeDesigner(AFreeComponent: boolean); +begin + FFreeComponent:=AFreeComponent; +end; + +procedure TDesigner.FinalizeFreeDesigner; var i: Integer; begin @@ -634,7 +643,7 @@ begin end; if GlobalDesignHook.LookupRoot = FLookupRoot then GlobalDesignHook.LookupRoot := nil; - if FreeComponent then + if FFreeComponent then begin // tell hooks about deleting for i := FLookupRoot.ComponentCount - 1 downto 0 do @@ -647,7 +656,7 @@ begin if Mediator<>nil then Mediator.Designer:=nil; // free or hide the form - TheFormEditor.DeleteComponent(FLookupRoot,FreeComponent); + TheFormEditor.DeleteComponent(FLookupRoot,FFreeComponent); FMediator:=nil; end; Free; @@ -2199,7 +2208,7 @@ begin MouseDownComponent:=nil; MouseDownSender:=nil; {$IFDEF VerboseDesigner} - DebugLn('[TDesigner.MouseLeftUpOnControl] END'); + DebugLn('[TDesigner.MouseUpOnControl] END'); {$ENDIF} end; @@ -2612,6 +2621,7 @@ begin Result := false; if csDesigning in Sender.ComponentState then begin Result:=true; + Inc(FProcessingDesignerEvent); case TheMessage.Msg of LM_PAINT: Result := PaintControl(Sender, TLMPaint(TheMessage)); CN_KEYDOWN,CN_SYSKEYDOWN: KeyDown(Sender,TLMKey(TheMessage)); @@ -2631,6 +2641,7 @@ begin else Result:=false; end; + Dec(FProcessingDesignerEvent); end else begin if (TheMessage.Msg=LM_PAINT) or (TheMessage.Msg=CN_KEYDOWN) diff --git a/ide/main.pp b/ide/main.pp index 6df0c2758f..773a769bd2 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -633,6 +633,7 @@ type out aBounds: TRect; out DockSibling: string; out DockAlign: TAlign); private FUserInputSinceLastIdle: boolean; + FDesignerToBeFreed: TDesigner; // Will be freed in OnIdle. FDisplayState: TDisplayState; FLastFormActivated: TCustomForm;// used to find the last form so you can // display the correct tab @@ -752,6 +753,8 @@ type var ComponentUnitInfo: TUnitInfo): TModalResult; // methods for 'close unit' + procedure FreeDesigner(AnUnitInfo: TUnitInfo; ADesigner: TDesigner; + AFreeComponent: boolean); function CloseUnitComponent(AnUnitInfo: TUnitInfo; Flags: TCloseFlags ): TModalResult; function CloseDependingUnitComponents(AnUnitInfo: TUnitInfo; @@ -3747,7 +3750,9 @@ end; procedure TMainIDE.UpdateIDEComponentPalette; begin IDEComponentPalette.HideControls:=(FLastFormActivated<>nil) - and (not (TDesigner(FLastFormActivated.Designer).LookupRoot is TControl)); + and (FLastFormActivated.Designer<>nil) + and (TDesigner(FLastFormActivated.Designer).LookupRoot<>nil) + and not ((FLastFormActivated.Designer as TDesigner).LookupRoot is TControl); IDEComponentPalette.UpdateVisible; TComponentPalette(IDEComponentPalette).OnClassSelected := @ComponentPaletteClassSelected; SetupHints; @@ -6775,6 +6780,7 @@ begin AnUnitInfo.ComponentName:=NewComponent.Name; AnUnitInfo.ComponentResourceName:=AnUnitInfo.ComponentName; DesignerForm := nil; + FLastFormActivated := nil; if not (ofLoadHiddenResource in OpenFlags) then begin DesignerForm := FormEditor1.GetDesignerForm(NewComponent); @@ -7483,6 +7489,17 @@ begin end; end; +procedure TMainIDE.FreeDesigner(AnUnitInfo: TUnitInfo; ADesigner: TDesigner; + AFreeComponent: boolean); +begin + AnUnitInfo.LoadedDesigner:=false; + ADesigner.PrepareFreeDesigner(AFreeComponent); + if ADesigner.ProcessingDesignerEvent > 0 then + FDesignerToBeFreed:=ADesigner // Free it later on idle time. + else + ADesigner.FinalizeFreeDesigner; // Free it now. +end; + {------------------------------------------------------------------------------- function TMainIDE.CloseUnitComponent @@ -7588,16 +7605,14 @@ begin {$IFDEF VerboseIDEMultiForm} DebugLn(['TMainIDE.CloseUnitComponent hiding component and freeing designer: ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]); {$ENDIF} - AnUnitInfo.LoadedDesigner:=false; - OldDesigner.FreeDesigner(false); + FreeDesigner(AnUnitInfo, OldDesigner, false); end else begin // free designer and design form {$IFDEF VerboseIDEMultiForm} DebugLn(['TMainIDE.CloseUnitComponent freeing component and designer: ',AnUnitInfo.Filename,' ',DbgSName(AnUnitInfo.Component)]); {$ENDIF} try - AnUnitInfo.LoadedDesigner:=false; - OldDesigner.FreeDesigner(true); + FreeDesigner(AnUnitInfo, OldDesigner, true); finally AnUnitInfo.Component:=nil; end; @@ -17061,6 +17076,10 @@ begin ExternalTools.FreeStoppedProcesses; if (SplashForm<>nil) then FreeThenNil(SplashForm); + if Assigned(FDesignerToBeFreed) then begin + FDesignerToBeFreed.FinalizeFreeDesigner; + FDesignerToBeFreed:=Nil; + end; if FUserInputSinceLastIdle then begin FUserInputSinceLastIdle:=false;