Link to home
Start Free TrialLog in
Avatar of paulb1989
paulb1989

asked on

Exception in ntdll.dll when clearing form

I am trying to free all objects on a form inside a DLL. I have written some code but get the following exception (I'm using XP Pro, not tested on other platforms).

Access Violation at address 7C918FEA in module 'ntdll.dll'. Write of address 00000010.

My code works after displaying this exception numerous times. Here is the code I have.

procedure TotalClearPage;
var
  i: Integer;
  o: TComponent;
begin
  try
    for i:=0 to Objects.Count-1 do
    begin
      o:=TheForm.Form.FindComponent(Objects.Strings[i]);
      if o<>nil then
      begin
        TheForm.Form.RemoveComponent(o);
        o.Free;
        o:=nil;
      end;
    end;
  finally
    Objects.Clear;
  end;
end;

Objects does contain a valid list of the components on the form.
Avatar of sokpas
sokpas

You should remove the components like this:

procedure TotalClearPage;
var
  i: Integer;
  o: TComponent;
begin
  try
    for i:=Objects.Count-1 downto 0 do  <=============== HERE IS THE RIGHT WAY
    begin
      o:=TheForm.Form.FindComponent(Objects.Strings[i]);
      if o<>nil then
      begin
        TheForm.Form.RemoveComponent(o);
        o.Free;
        o:=nil;
      end;
    end;
  finally
    Objects.Clear;
  end;
end;
Hi,

I'm not sure I understand why you need such code and where you're calling that routine. You are manually freeing components owned by a form and that same thing will de executed if you simply call  TheForm.Form.Release;

Regards, Geo
i do not see any problem with your code

only thing may be

TheForm
or
TheForm.Form

already not valid when you call your function
Avatar of Wim ten Brink
@Sokpas, it doesn't matter in which order he is freeing the components because he uses his own object list to store just the names of the component to delete. He is not deleting any items from the list itself. He just uses the list to find components on the form and then frees those components.

However, I do think this is weird:

    for i:=0 to Objects.Count-1 do <<<<<<<<<<
    begin
      o:=TheForm.Form.FindComponent(Objects.Strings[i]); <<<<<<<<<<

Apparantly, Objects has a stringlist connected to itself so I would have expected Objects.Strings.Count to be used instead of Objects.Count. But okay, this might be handled by the code correctly. (But it could cause problems if the count has an invalid value...)

@Geobul, I think he's just clearing the form of unnneeded components, not closing it...

@paulb1989, I think you should try stepping through this code and see which line actually causes the exception. Either turn "break on exception" on or put a breakpoint at the first "begin" of this procedure, then check what might be wrong here. And like vadim_ti I don't see anything in your code that is wrong, unless TheForm is not initialized correctly...
ASKER CERTIFIED SOLUTION
Avatar of geobul
geobul

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ops, I had OWNER in mind not parent when speaking about the order of freeing. Some components may have owner different than the form when created by code, you know.
Geo, it doesn't matter if he uses
  for i:=0 to Objects.Count-1 do
or
  for i:=Objects.Count-1 downto 0 do
since he NEVER seems to remove items from the list. He just removes components from his form where their names exist in this list... Don't act like a robot by providing default answers, please. ;-)

But maybe he should use:
  O.Owner.RemoveComponent(O);
instead. You need to remove them from their owner, not from the form. ;-)

Then again, I also wonder why you just can't free them directly. That should remove them from their owner too.
Alex, at first I thought that it does matter if the owner of a component has already been freed when you get to that component in the list. Again, for instance, on the loop 3 you are freeing a panel which owns other components listed later in Objects. When you reach these components and try to free them you'll get an AV because PanelX.Free has also freed them already. But in this case FindComponent won't find them, so you are right :-)
BTW, I think that
O.Owner.RemoveComponent(O);
is the same as
TheForm.Form.RemoveComponent(o);
in that case because FindComponent returns components owned by the form only.
Of course I'm right! ;-) I knew it couldn't find a component when it's owner has been freed, thus it works quite nice. :-)
But if these components are created without any owner being assigned to them...?
Avatar of paulb1989

ASKER

Thanks all for trying, but geobuls worked, but I had to check if the component was a control then typecast it to get the parent property. Then it worked fine.

if o is TControl then
  TControl(o).Parent:=nil;

Objects didnt just have a stringlist inside it, but is a TStringList.

All components had their owner as TheForm.Form, so freeing backwards didnt matter. Its TheForm.Form because I am using the SUIPack skinning components and Form is my TSUIForm on which all components are placed.

I couldnt free them directly, as I dont know their names at design time, they are created at runtime.

This may seem like a strange thing to be doing at runtime, but its because I'm making a Multimedia Authoring tool that is based on pages, so when I load a new page I have to clear the current one first, or both pages objects would be shown.
Oh, I see... You're not using Objects[i] but the longer version Objects.Strings[i]... Well, okay... My mistake. ;-)

But if you have to check if it's a control then it seems your list is "contaminated" with names of items that are not controls. Maybe you should do it easier and use FindChildControl instead... Same syntax, but it returns controls, not components. Saves you a little typecasting. ;-)

(Advise free of charge, btw.)
Some of the names in the list are TComponents and not TControls, so I still need to free these. There are also some components on the form that I have to leave there, so I can't use FindChildControl either.

The Object list is working fine now anyway, thanks :)