performancedelphidelphi-xe2

Why ‘form close’ event is not happening when a huge for loop is running in Delphi?


I am trying out the following code. However, if I click on the form’s close button while this code is running, nothing happens. How can I correct this? I need to close the form even when this loop is executing.

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 9999999 do
  begin
    Memo1.Lines.Add('hi');
    Application.ProcessMessages;
  end;
end;

Solution

  • Have a look at what's going on inside Application.ProcessMessages.

    When you close the main form, windows sends a WM_QUIT message to the program. The relevant part of TApplication.ProcessMessages looks like this:

        if Msg.Message <> WM_QUIT then
        begin
          //skipped
        end
        else
        begin
    {$IF DEFINED(CLR)}
          if Assigned(FOnShutDown) then FOnShutDown(self);
          DoneApplication;
    {$IFEND}
          FTerminate := True;
        end;
    

    I assume this is not a CLR program, so the only thing that happens at this point is setting FTerminate := True on Application. This is reflected in the Application.Terminated property.

    When the application shuts down, one of the things it does in order to shut down safely is wait for all threads to finish. This code happens to be running in the main thread, but the principle would be the same in any thread: If you're doing a long-running task that might have to finish early, you have to explicitly check for early termination.

    Knowing this, it's easy to figure out how to fix your code:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      i: Integer;
    begin
      for i := 0 to 9999999 do
      begin
        Memo1.Lines.Add('hi');
        Application.ProcessMessages;
        if Application.Terminated then
          Break;
      end;
    end;
    

    Also, beware of using Application.ProcessMessages in the first place, as it will process all messages for the application. For a simple idea of what might go wrong, try adding IntToStr(i) instead of 'hi' to Memo1.Lines, knock a couple of orders of magnitude off the counter, and then click the button two or three times in rapid succession and watch the output...