Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1234
  • Last Modified:

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.
0
paulb1989
Asked:
paulb1989
  • 5
  • 4
  • 2
  • +2
1 Solution
 
sokpasCommented:
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;
0
 
geobulCommented:
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
0
 
vadim_tiCommented:
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
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Wim ten BrinkSelf-employed developerCommented:
@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...
0
 
geobulCommented:
Try clearing the parent first:

      if o<>nil then
      begin
        o.Parent := nil;
        TheForm.Form.RemoveComponent(o);
        o.Free;
        // setting o to nil here is redundant I think
      end;

If all the components in Objects list have the form as a parent then the order of their freeing doesn't matter. But if you have a panel (parent = form) as number 3 in the list and a button (parent = the panel N3) having number 6 in the list later on then the order of freeing should be reversed, i.e.

for i:=Objects.Count-1 downto 0 do  

as sokpas already mentioned.

Regards, Geo
0
 
geobulCommented:
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.
0
 
Wim ten BrinkSelf-employed developerCommented:
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.
0
 
geobulCommented:
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 :-)
0
 
geobulCommented:
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.
0
 
Wim ten BrinkSelf-employed developerCommented:
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...?
0
 
paulb1989Author Commented:
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.
0
 
Wim ten BrinkSelf-employed developerCommented:
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.)
0
 
paulb1989Author Commented:
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 :)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 5
  • 4
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now