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 4: Timing out

Applies to: ~>3.0

All the examples to date have allowed a console application to run for as long as it required. This was done by setting TPJConsoleApp’s MaxExecTime property to INFINITE. In this example we will look at how to set a maximum time for a console application to run and examine what happens when it times out.

The amount of time available for a console application to run is limited by setting the MaxExecTime property (in milliseconds). If this time expires before the console application completes then the Execute method returns False, the ErrorCode property is set to $20000001 (cAppErrorTimeOut) and the ErrorMessage property stores an explanatory string. However, the console application may keep running. Whether this happens depends on the value of the KillTimedOutProcess property. If it is True the timed-out process is forcibly terminated. When the property is False the process is left executing, but the link between TPJConsoleApp and the process is broken.

To see all this, start a new Delphi GUI application project and drop a TEdit, a TCheckbox, a TButton and a TMemo control on the form. Give the TMemo a vertical scroll bar. The edit control will be used to enter the maximum execution time of the program in milliseconds. The check box will set the KillTimedOutProcess property and the memo will be used to display output.

As we’ve done before add a private work handler method to the form class:

procedure WorkHandler(Sender: TObject);

and implement the method like this:

procedure TForm1.WorkHandler(Sender: TObject);
var
  App: TPJConsoleApp;
begin
  App := Sender as TPJConsoleApp;
  Memo1.Lines.Add(
    Format(
      'Elapsed time: %dms, Time to live: %dms',
      [App.ElapsedTime, App.TimeToLive]
    )
  );
  Application.ProcessMessages;  // keeps GUI interactive
end;

Now add the following OnClick event handler for the button:

procedure TForm1.Button1Click(Sender: TObject);
var
  App: TPJConsoleApp;
begin
  App := TPJConsoleApp.Create;
  try
    App.MaxExecTime := StrToInt(Edit1.Text);
    App.KillTimedOutProcess := Checkbox1.Checked;
    App.TimeSlice := 200;
    App.Visible := True;
    App.OnWork := WorkHandler;
    if App.Execute('Timed 5') then
      Memo1.Lines.Add('Application completed normally')
    else
      Memo1.Lines.Add(App.ErrorMessage)
  finally
    App.Free;
  end;
end;

Again, Timed.exe from Appendix 2 is being used as the console application, set to run for five seconds.

Run the program and enter a maximum execution time that is less than the time the console program will run for (3000 is good if using Timed). Leave the checkbox unchecked. Now click the button to execute the console application. Every 1/5th second the memo control will be updated with the time the program has been running and the maximum time left to run (“time to live”). Once the time to live value hits zero the program will time out and the resulting error message will be displayed in the memo control. Notice that the console application will continue to run.

Now check the check box and repeat the process. Once again the program should time out, but this time the console application will be terminated.

Finally, set the maximum execution time to be longer than the console application will run (6000 is good if using Timed). Click the button to run the console application. The memo will be updated as before until the console application completes. Normal completion will be reported in the memo.

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.