2

I have a problem with error message "Invalid Floating Point operation." The popup menu is a design time control and it is named NavPop. It has no menu items assigned. It is assigned as popupmenu for Panel1.

I then create the menu items dynamically from a listbox, and assign the caption and on click events. Everything works 100% in terms of what I am trying to accomplish. Ie it works.

Only when i close the program, do I get

Invalid floating point operation

or otherwise:

Access Violation Address 000007355. Read of Addrss 0000007355.

Please note that everything works perfectly, except that the error when I close the program. I would appreciate any help.

 //  I declare the Array of TMenuItems
 private
    { Private declarations }
    ItemArray : array of TMenuItem;

...    

procedure TMainForm.Button1Click(Sender: TObject);
begin
  CreateNavPop;
end;

//  Create the menu items from listbox(Navlist) items and Link them 
//  to events on a navigation bar.
procedure TMainForm.CreateNavPop;
var
  I:  Integer;
  NavIndex:  Integer;
begin
  SetLength(ItemArray, NavList.Items.Count);
  NavIndex:=0;
  For I:=0 to NavList.Items.Count-1 do
  begin
    NavIndex:=NavBar1.Items.ItemByCaption(NavList.Items.Strings[i]).Index;
    ItemArray[i]:=TMenuItem.create(Nil);
    ItemArray[i].Caption:=NavList.Items.Strings[i];
    ItemArray[i].OnClick:=NavBar1.Items.Items[Navindex].OnClick;
    NavPop.Items.Add(ItemArray[i]);
  end;
end;

//  Call the Items free on program close
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FreeItems(ItemArray);
end;

//  Free Dynamically created Menu Items on Form Close
procedure TMainForm.FreeItems(MItems : array of TMenuItem);
var
  cnt : integer;
begin
  for cnt := High(MItems) downto Low(MItems) do
  begin
    MItems[cnt].Free;
    MItems[cnt] := nil;
  end;
end;
NGLN
  • 43,011
  • 8
  • 105
  • 200
Nico Steyn
  • 83
  • 3
  • 7
  • Shouldn't you assign the owner of a `TMenuItem` in the constructor? You are setting it to `nil` right now. – Pateman May 20 '12 at 12:44
  • Is there a point in keeping a list of TMenuItems? Just assigning an owner in the constructor (navpop) as Pateman says is enough. – LU RD May 20 '12 at 12:57
  • 2
    See [How to Dynamically Add Items (Holding Custom Properties) to a TPopUp Menu](http://delphi.about.com/od/kbcurt/a/dynamicmenuitem.htm) for an example. To debug your program, use FastMM with debug options as suggested here: [How do I turn on/off FastMM memory leak reporting under Delphi XE?](http://stackoverflow.com/q/6075554/576719) or here: [How to enable full debug mode in FastMM4?](http://stackoverflow.com/a/8601505/576719). – LU RD May 20 '12 at 15:02
  • When you add the menu item to NavPop (`NavPop.Items.Add(ItemArray[i])`), the parent property of the item itself is set to the NavPop, check from the Menus.pas:TMenuItem.Insert. In the Forms.pas file, when main windows is closing, every component in Form.Components list gets freed and NavPop is one of 'em. So NavPop.free gets called. You can observe from Menus.pas that when menu.free called, it removes the items in it. So your dynamically created object ItemArray[i] will be freed automatically when you set a parent to it and a parent to that parent and so on as long as the most parent is the... – Hasan Manzak May 21 '12 at 02:09
  • 1
    ...form itself. Long story short, you should not call `FreeItems(MItems : array of TMenuItem)` method to free the items. This causes the form.free method to access the NavPop's unreferenced items. – Hasan Manzak May 21 '12 at 02:09

1 Answers1

2

This happens because the TPopupMenu already free the items, and you are freeing it again.

This code causes an "Invalid pointer operation":

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to 3 do
    PopupMenu1.Items.Add(TMenuItem.Create(nil));
end;

destructor TForm1.Destroy;
var
  I: Integer;
begin
  for I := 3 downto 0 do
    PopupMenu1.Items.Free;
  inherited;
end;

The Items property is a TMenuItem instance, and if you look at it's destructor, it already free all the items you added.

destructor TMenuItem.Destroy;
begin
...
  while Count > 0 do Items[0].Free;
...

Keeping it short, you don't need to do it again in the FreeItems method.

I tested with ReportMemoryLeaksOnShutdown := True and no memory leaks occur.

Fabio Gomes
  • 5,914
  • 11
  • 61
  • 77
  • While correct, there's a similar *deleted* answer which OP has commented *"..I still get the same error"*. There's also probably some other problem which is not evident from the question. +1 anyway.. – Sertac Akyuz May 22 '12 at 17:32
  • 1
    Thanks for pointing that, but in that case he should have updated his question with more details and the call stack showing where the AV occurs. Thanks for the +1 :) – Fabio Gomes May 22 '12 at 17:36