DelphiDabbler Wiki

Console Application Runner Classes FAQ

This page has some frequently asked questions about the DelphiDabbler Console Application Runner Classes. You can also try the class' documentation.

If you still can't find an answer to your question then you should submit it via the website's contact page. Any answer it will be posted here.


1: Why am I getting an access violation when running code that uses TPJConsoleApp compiled with with Delphi 2009 (and later)?

This is because Delphi 2009 and later (the "Unicode Delphis") use the Unicode Windows API (earlier versions used the ANSI API). It is a peculiarity of the Unicode implementation of the CreateProcess API function (which TPJConsoleApp uses) that causes this access violation. This peculiarity wasn't present in the ANSI version of the function.

Check this post for an explanation of the issue.

The classes have been updated to work round this problem. You need to update to release 1.0.2 or later.

2: Does TPJConsoleApp handle Unicode output from console applications correctly?

There is no straightforward answer to this. Because TPJConsoleApp can run any console app it can know nothing about the output of programs it is used to run.

In the case where the program's output is displayed in the console window the question is irrelevant.

If the output is being redirected to a file then the output is a faithful byte by byte copy of the console program output. If the program writes Unicode text then that's what the file will contain.

If output is redirected to the pipe then, again, the actual bytes output by the program are written to the pipe. The programmer is responsible for reading the pipe and must make sure that any structured data is re-assembled correctly. Each time the pipe is read it is possible it may contain an odd number of bytes, which is not valid Unicode. But I stress, it is up to the programmer to handle this - it is not a function of TPJConsoleApp.

New in release 2.0 of the classes are some pipe filter classes, one of which can read Unicode from a pipe correctly. See this example.

As of release 3.0 the pipe filter classes were moved from this project into the I/O Utility Classes project.

3: In the command shell running "MyApp.exe >out.txt" redirects MyApp's output to out.txt. Why doesn't this command redirect when run with TPJConsoleApp?

The ">" redirection operator in MyApp.exe >out.txt is special to the command shell. The shell interprets it by making MayApp.exe write its standard output to out.txt instead of the console.

The operator has no meaning outside the command shell. To see this try executing a command line containing the ">" operator via the Windows Run dialog box [Windows Key + R]. It won't work. Using the Windows API to execute such a command also fails: this is what TPJConsoleApp does.

TPJConsoleApp can do redirection, but you have to do a lot of the work yourself that the command shell does behind the scenes. To understand this let's take a look at what the command shell does when it encounters the ">" operator.

First the shell creates a new empty file named out.txt. The file is created with an inheritable handle to permit it to be used by a child process. MyApp.exe is now executed as a child process of the shell and has its standard output handle redirected to the file handle so that anything written to standard output goes to the file.

We have to do the same to use TPJConsoleApp for redirection. First create the file ensuring its handle is inheritable (FAQ 5 explains how). Assign the file handle to TPJConsoleApp's StdOut property. Finally call Execute with a command line parameter of MyApp.exe, leaving off the redirection operator part.

Redirection using the "2>" (redirect standard error output) and "<" (redirect standard input) operators is similar. Open the required files for output (standard error) or input (standard input) and assign the (inheritable) handles to TPJConsoleApp's StdErr or StdIn properties respectively.

4: In the command shell I can pipe data between applications. How can I do this with TPJConsoleApp?

The only way I have found to do this is to run each application in sequence, capturing output via a pipe to a memory stream an feeding that data into the next application, again via a pipe. It's cruder than threads, because it just runs each application in turn and buffers output before feeding to the next application, but I suspect (but don't know) that is what Windows cmd.exe does when you use the pipe (|) operator. Regardless, I haven't found a way to do this successfully using a separate thread for each application.

To help handle the housekeeping you can use the following class, which needs both the PJConsoleApp and PJPipe units. Enter the code in a unit named UConsoleAppChain.

unit UConsoleAppChain;


  PJConsoleApp, PJPipe;

  TConsoleAppArray = array of TPJConsoleApp;

  // Chains together two or more apps represented by TPJConsoleApp instances
  // passing intermediate data via pipes and memory streams.
  TConsoleAppChain = class(TObject)
    fIntermediateStream: TStream;
    fOutPipe: TPJPipe;
    fInPipe: TPJPipe;
    procedure SourceWork(Sender: TObject);
    constructor Create;
    destructor Destroy; override;
    procedure Execute(const Apps: TConsoleAppArray);



{ TConsoleAppChain }

constructor TConsoleAppChain.Create;
  inherited Create;
  fIntermediateStream := TMemoryStream.Create;

destructor TConsoleAppChain.Destroy;

procedure TConsoleAppChain.Execute(const Apps: TConsoleAppArray);
  Idx: Integer;
  FirstAppIdx: Integer;
  LastAppIdx: Integer;
  Assert(Length(Apps) >= 2);

  FirstAppIdx := Low(Apps);
  LastAppIdx := High(Apps);

  fIntermediateStream.Size := 0;

  for Idx := FirstAppIdx to LastAppIdx do
      if Idx > FirstAppIdx then
        fIntermediateStream.Position := 0;
        fInPipe := TPJPipe.Create(fIntermediateStream.Size);
        Apps[Idx].StdIn := fInPipe.ReadHandle;

      if Idx < LastAppIdx then
        fOutPipe := TPJPipe.Create;
        Apps[Idx].StdOut := fOutPipe.WriteHandle;
        Apps[Idx].OnWork := SourceWork;

      fIntermediateStream.Size := 0;

      if not Apps[Idx].Execute then
        raise Exception.CreateFmt(
          'Error executing "%0:s": %1:s',
          [Apps[Idx].CommandLine, Apps[Idx].ErrorMessage]

procedure TConsoleAppChain.SourceWork(Sender: TObject);


To use, pass an array of TPJConsoleApp instances to the Execute method, in the order you want them executed. The output of the first instance is used as input to the second and so on. There must be at least two TPJConsoleApp instances in the array.

You must set the StdIn property of the first app to get the initial data unless it is supplied in any other way. You must also set the StdOut property of the last app if you want final output redirected in any way. TConsoleAppChain overwrites the remaining StdIn and StdOut properties, so don't set them. It also sets the OnWork event handler of all except the last TPJConsoleApp instance to copy output from the pipe to a memory stream.

Each console application except the first must be capable of taking input from standard input. Similarly and each application except the last must write output to standard output.

5: How do I create or open a file with an inheritable handle?

This question is answered in Appendix 1 of the Console Application Runner Classes documentation.

Page last modified on June 08, 2013, at 01:19 AM