MenuDesigner: BeginUpdate and EndUpdate methods to prevent AV. Related changes in menushadows.pp inside method TShadowMenu.DeleteChildlessShadowAndItem

(operation ownsIt.RemoveComponent(mi) was the starting point for many TMenuDesigner.OnDesignerSetSelection calls, especially visible with Sparta package.
During execution OnDesignerSetSelection, caller object TShadowMenu was destroyed after RemoveComponent operation, before end of DeleteChildlessShadowAndItem).
Issue #29328, from Maciej.

git-svn-id: trunk@51212 -
This commit is contained in:
juha 2016-01-06 15:16:20 +00:00
parent 8663e9c084
commit d5272def5e
2 changed files with 59 additions and 33 deletions

View File

@ -73,6 +73,7 @@ type
FTemplatesSaved: boolean;
FTotalMenuItemsCount: integer;
FVariableGlyphsInMenuBar: boolean;
FUpdateCount: integer;
function GetItemCounts(out aCaptionedItemCount, aShortcutItemCount,
anIconCount, anAccelCount: integer): integer;
function GetPopupAssignmentCount: integer;
@ -94,6 +95,8 @@ type
procedure UpdateShortcutList(includeAccelerators: boolean=False);
procedure UpdateStatistics;
procedure UpdateTemplatesCount;
procedure BeginUpdate;
procedure EndUpdate;
property AcceleratorMenuItemsCount: integer read FAcceleratorMenuItemsCount;
property EditedMenu: TMenu read FEditedMenu;
property SavedTemplatesCount: integer read FSavedTemplatesCount;
@ -203,6 +206,9 @@ var
isTMenu: boolean;
persist: TPersistent;
begin
if FUpdateCount > 0 then
Exit; // This event will be executed after all updates, look at EndUpdate
persist:=GetSelectedMenuComponent(ASelection, isTMenu, selCount);
if (persist <> nil) then
begin
@ -571,6 +577,20 @@ begin
else FSavedTemplatesCount:=GetSavedTemplatesCount;
end;
procedure TMenuDesigner.BeginUpdate;
begin
Inc(FUpdateCount);
end;
procedure TMenuDesigner.EndUpdate;
begin
if FUpdateCount<=0 then
RaiseGDBException('');
Dec(FUpdateCount);
if FUpdateCount = 0 then
OnDesignerSetSelection(FormEditingHook.GetCurrentObjectInspector.Selection);
end;
{ TMainMenuComponentEditor}
procedure TMainMenuComponentEditor.Edit;

View File

@ -5017,41 +5017,47 @@ var
box: TShadowBox;
ownsIt: TComponent;
begin
mi:=anExistingSI.RealItem;
if (mi.Count > 0) then
DeleteShadowAndItemAndChildren(anExistingSI)
else begin
HideFakes;
if (mi = FSelectedMenuItem) then
FSelectedMenuItem:=nil;
nearestMI:=GetNextNonSepItem(mi);
if (nearestMI = nil) then
nearestMI:=GetPreviousNonSepItem(mi);
if (nearestMI = nil) then
nearestMI:=mi.Parent;
box:=anExistingSI.ParentBox;
box.ParentMenuItem.Remove(mi);
ownsIt:=mi.Owner;
if (ownsIt <> nil) then
ownsIt.RemoveComponent(mi);
anExistingSI.RealItem:=nil;
box.ShadowList.Remove(anExistingSI);
anExistingSI.Parent:=nil;
box.RemoveComponent(anExistingSI);
FreeAndNil(anExistingSI);
FEditorDesigner.PropertyEditorHook.PersistentDeleting(TPersistent(mi));
FreeAndNil(mi);
FEditorDesigner.Modified;
MenuDesigner.BeginUpdate;
try
mi:=anExistingSI.RealItem;
if (mi.Count > 0) then
DeleteShadowAndItemAndChildren(anExistingSI)
else begin
HideFakes;
if (mi = FSelectedMenuItem) then
FSelectedMenuItem:=nil;
nearestMI:=GetNextNonSepItem(mi);
if (nearestMI = nil) then
nearestMI:=GetPreviousNonSepItem(mi);
if (nearestMI = nil) then
nearestMI:=mi.Parent;
box:=anExistingSI.ParentBox;
box.ParentMenuItem.Remove(mi);
ownsIt:=mi.Owner;
if (ownsIt <> nil) then
ownsIt.RemoveComponent(mi);
anExistingSI.RealItem:=nil;
box.ShadowList.Remove(anExistingSI);
anExistingSI.Parent:=nil;
box.RemoveComponent(anExistingSI);
FreeAndNil(anExistingSI);
FEditorDesigner.PropertyEditorHook.PersistentDeleting(TPersistent(mi));
FreeAndNil(mi);
FEditorDesigner.PropertyEditorHook.PersistentDeleted;
FEditorDesigner.Modified;
if (box.ShadowCount = 0) then begin
FBoxList.Remove(box);
box.Parent:=nil;
RemoveComponent(box);
FreeAndNil(box);
if (box.ShadowCount = 0) then begin
FBoxList.Remove(box);
box.Parent:=nil;
RemoveComponent(box);
FreeAndNil(box);
end;
UpdateBoxLocationsAndSizes;
SetSelectedMenuItem(nearestMI, False, True);
MenuDesigner.UpdateStatistics;
end;
UpdateBoxLocationsAndSizes;
SetSelectedMenuItem(nearestMI, False, True);
MenuDesigner.UpdateStatistics;
finally
MenuDesigner.EndUpdate;
end;
end;