Welcome to the new DelphiDabbler Code Library Documentation.

This is a new site that's currently running on alpha code. There are going to be bugs. If you discover any, please report them on the site's issues page (GitHub account required). Thanks.

Warning: Many URLs are going to change. Refer to the README file to discover which library project's documentation has been completed.

Console Application Runner Classes Example 5: Terminating an application

Applies to: ~>3.0

In Example 4 we learned how to set a maximum time to run for a console application and how to forcibly terminate it if it timed out. Unfortunately it’s not always possible to second guess how long an application will need to run, and so we may be forced to set the MaxExecTime property to INFINITE. In these cases it may be appropriate to give the user the choice to terminate the process.

TPJConsoleApp provides the Terminate method for just this purpose. Calling Terminate causes the Execute method to return False, the ErrorCode property to have value $20000002 (cAppErrorTerminated) and the ErrorMessage property to store a suitable message. If the KillTimedOutProcess property is False the process is actually left executing, just the link between TPJConsoleApp and the process is broken. However when KillTimedOutProcess is True the application is forcibly terminated.

To check this out, start a new Delphi GUI application and drop two buttons and a checkbox on the form. The first button will be used to execute a console application and the second button will be used to terminate it. Set the second button’s Enabled property to False - we will enable it when the console application starts. The check box state will determine the value of the KillTimedOutProcess property.

It should come as no surprise we need a private work handler method of the form class:

procedure WorkHandler(Sender: TObject);

This time we simply need to keep the GUI interactive while the console application is running, so the implementation is simply:

procedure TForm1.WorkHandler(Sender: TObject);
begin
  Application.ProcessMessages;
end;

Now add this OnClick event handler for Button1 (the button we use to execute the console application):

procedure TForm1.Button1Click(Sender: TObject);
begin
  fApp := TPJConsoleApp.Create;
  try
    Button2.Enabled := True;
    fApp.MaxExecTime := INFINITE;
    fApp.KillTimedOutProcess := Checkbox1.Checked;
    fApp.TimeSlice := 200;
    fApp.Visible := True;
    fApp.OnWork := WorkHandler;
    if fApp.Execute('Timed 5') then
      ShowMessage('Application completed normally')
    else
      ShowMessageFmt('Error %X: %s', [fApp.ErrorCode, fApp.ErrorMessage]);
  finally
    Button2.Enabled := False;
    FreeAndNil(fApp);
  end;
end;

We’re using Timed.exe from Appendix 2 again as the long-running console application.

Finally, add the following OnClick event handler for Button2 (that we will use to terminate the application):

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(fApp) then
    fApp.Terminate;
end;

Compile and run the application. Leave the check box clear and click the first button to start the console application. Press the terminate button while the the console application is running. You should get a message box showing the error code $20000002 and a message noting the application has been terminated. The console application should continue to run, but the link to TPJConsoleApp will have been broken.

Now check the check box and run the console application again, pressing the terminate button. This time the same message should be displayed and the console application should be terminated.

Warning: Windows may not clean up normally after forcible termination of an application. This is what happens when an application times out when KillTimedOutProcess is True. Look up TerminateProcess in the Windows API documentation for further information.