Solved

Exception in ntdll.dll when clearing form

Posted on 2004-10-21
1,217 Views
Last Modified: 2012-05-05
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
Question by:paulb1989
    13 Comments
     
    LVL 1

    Expert Comment

    by: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;
    0
     
    LVL 17

    Expert Comment

    by:geobul
    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
     
    LVL 6

    Expert Comment

    by:vadim_ti
    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
     
    LVL 17

    Expert Comment

    by: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...
    0
     
    LVL 17

    Accepted Solution

    by:
    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
     
    LVL 17

    Expert Comment

    by:geobul
    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
     
    LVL 17

    Expert Comment

    by:Wim ten Brink
    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
     
    LVL 17

    Expert Comment

    by:geobul
    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
     
    LVL 17

    Expert Comment

    by:geobul
    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
     
    LVL 17

    Expert Comment

    by:Wim ten Brink
    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
     
    LVL 5

    Author Comment

    by:paulb1989
    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
     
    LVL 17

    Expert Comment

    by:Wim ten Brink
    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
     
    LVL 5

    Author Comment

    by:paulb1989
    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

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone. Privacy Policy Terms of Use

    Featured Post

    Lean Six Sigma Project Manager Certification

    There are many schools of thought around successful project management, but few as highly regarded as the Six Sigma and Lean methods. With 37 hours of learning, this training will explain concrete processes for increasing efficiency and limiting wasted time and effort.

    Suggested Solutions

    Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
    Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
    Need more eyes on your posted question? Go ahead and follow the quick steps in this video to learn how to Request Attention to your question. *Log into your Experts Exchange account *Find the question you want to Request Attention for *Go to the e…
    how to add IIS SMTP to handle application/Scanner relays into office 365.

    875 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    8 Experts available now in Live!

    Get 1:1 Help Now