Recent

Author Topic: How can you control a console application from a Lazarus application?  (Read 20215 times)

HappyLarry

  • Full Member
  • ***
  • Posts: 155
How can I write a Lazarus application (with Forma and Buttons) to control a console program (black screen + text) that has already been written? The program outputs to the screen. How do I catch the output and show it in Lazarus instead? The program gets input from the keyboard. How do I make it accept input from my Lazarus program?

Thanks
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.


HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #2 on: January 08, 2012, 01:15:50 pm »
Use TProcess.

Thanks
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #3 on: January 09, 2012, 02:46:32 pm »
I am using the wiki directly.

I have created a Pascal program called Hello.exe in my project folder. It runs. all it does is write 'Hello' to the screen.

I have a Lazarus app with just a button on the form.

I tried exactly the wiki code:
 var
   AProcess:TProcess;
   AStringList:TStringList;

 procedure TForm1.Button1Click(Sender: TObject);
 begin
    AStringList.Create;
    AProcess := TProcess.create(nil);
    AProcess.Commandline :='Hello.exe';
    AProcess.Options:=AProcess.Options+[poWaitOnExit,  poUsePipes];
    AProcess.Execute;
    AStringList.LoadFromStream(AProcess.Output);
    AStringList.SaveToFile('output.txt');
    AStringList.Free;
    AProcess.Free;
 end;

The code compiles. The program runs. Hello.exe starts but does not show 'Hello' on the screen (the screen is completely black) or accept keyboard input. When I close it I get a SigSegV error for the application.
The line
    AStringList.LoadFromStream(AProcess.Output);
is highlighted.

Any ideas what is wrong?
« Last Edit: January 09, 2012, 02:52:01 pm by HappyLarry »
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How can you control a console application from a Lazarus application?
« Reply #4 on: January 09, 2012, 04:41:25 pm »
Quote
The code compiles. The program runs. Hello.exe starts but does not show 'Hello' on the screen (the screen is completely black) or accept keyboard input. When I close it I get a SigSegV error for the application.
The line
    AStringList.LoadFromStream(AProcess.Output);
is highlighted.

Any ideas what is wrong?
poWaitOnExit would block your app until the executed program is finished, this implies no input could be given to the program.

poUsePipes redirects the program's stream (i.e. I/O) to pipes where you can read/write to give input/read output. The side effect is that the program output won't be visible unless you explicitly read from the program to a buffer and write that buffer to the console or wherever you want.

Your app waits for the program to finish, but it never finishes since it expects some kind of input. When you close it, you get SIGSEGV because the program's output can no longer be read (the process is dead already).

Using pipes is OK, as long as you know the program's output is not very big. Read further the article if you have big output. Don't use poWaitOnExit. The interaction between your app and the program should be done within a while loop, e.g.:
Code: [Select]
AProcess.Execute;
while AProcess.Running do begin
  ... // read output, write input, etc.
end;
Use AProcess.Input property to give input, and AProcess.Output to read output respectively.

eny

  • Hero Member
  • *****
  • Posts: 1657
Re: How can you control a console application from a Lazarus application?
« Reply #5 on: January 09, 2012, 07:50:31 pm »
Change:
Code: Pascal  [Select][+][-]
  1.  procedure TForm1.Button1Click(Sender: TObject);
  2.  begin
  3.     AStringList.Create;
to
Code: Pascal  [Select][+][-]
  1.  procedure TForm1.Button1Click(Sender: TObject);
  2.  begin
  3.     AStringList := TStringList.Create;

I tried it with a simple console 'Hello World' program and it seems to work.

BTW: if you use variables locally, it's safer to define them as local variables.
All posts based on: Win11; Lazarus 4_4  (x64) 12-02-2026 (unless specified otherwise...)

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #6 on: January 10, 2012, 03:25:10 pm »
@eny
Thanks for spotting that error. I've corrected it.

@Leledumbo
My mistake was just as you pointed out - the program never finished.

This was because 'Hello.exe' was:

 program Hello;
 begin
   writeln('Hello');
   readln;
 end.
 
The final readln requires user input. If you remove that then the whole thing is fine.
Thanks.
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #7 on: January 10, 2012, 04:29:28 pm »
The output from the program will not be large. Leledumbo also suggested
  • removing poWaitOnExit
  • using while AProcess.Running do
but before that I would like to have a simple input working.

I have added a simple input to Hello.exe:

program Hello;
var
  TheirName:string;
begin
  writeln('Hello');;
  Writeln('What is your name?');
  Readln(TheirName);
  Writeln('Your Name is ',TheirName);

end.

There is no final readln for the reason given above.

I have modified my Lazarus procedure with:

procedure TForm1.Button1Click(Sender: TObject);
begin
   AStringList:=TStringList.Create;
   AProcess := TProcess.create(nil);
   AProcess.Commandline :='Hello.exe';
   AProcess.Options:=AProcess.Options+[poWaitOnExit, poUsePipes];
   AProcess.Execute;
   AStringList.LoadFromStream(AProcess.Output);
   AStringList.SaveToFile('output.txt');

   BStringList:=TStringList.Create;
   BStringList.Add('Fred');
   BStringList.SaveToStream(AProcess.Input);


   AStringList.Free;
   BStringList.Free;
   AProcess.Free;
end;

It all looks logical to me. I will repeat the lines that catch the output stream and have the whole program captured.

HOWEVER: The program compiles but when it runs it stops on
BStringList.SaveToStream(AProcess.Input);
and complains of a stream write error.

Any suggestions?[/list]
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How can you control a console application from a Lazarus application?
« Reply #8 on: January 11, 2012, 05:07:41 am »
Quote
There is no final readln for the reason given above.
It's not the final readln that causes the program to block, but anything that makes the program expects input at any time along the pogram lifeline.
Quote
I have modified my Lazarus procedure with
That's not the way you play with input streams, you have to do it while the process is running. If you do it after, then the program is already dead. This is how the code should be:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
const
  AInput = 'Fred'#13; // as in console, it expects enter as end of line input marker
begin
   AStringList:=TStringList.Create;
   AProcess := TProcess.create(nil);
   AProcess.Commandline :='Hello.exe';
   // NO poWaitOnExit
   AProcess.Options:=AProcess.Options+[poUsePipes];
   AProcess.Execute;
   // write to program's input stream
   AProcess.Input.Write(AInput[1],Length(AInput));
   // give the program some time to process
   while AProcess.Running do Sleep(100);
   // now the program has finished executing
   AStringList.LoadFromStream(AProcess.Output);
   AStringList.SaveToFile('output.txt');
   AStringList.Free;
   AProcess.Free;
end;

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #9 on: January 11, 2012, 11:06:29 am »
Thanks for helping, Leledumbo.

I copied and pasted your code. It compiles and runs. When I click the button, a blank, black Pascal screen appears and stays. If I close the Pascal screen then the program seems to end OK.

However nothing is written to the output.txt file. It is blank.
I assume that it should contain:
What is your name?
Fred
Your name is Fred


Any ideas?
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #10 on: January 11, 2012, 11:29:26 am »
As a matter of interest:

I changed

    AProcess.Input.Write(AInput[1],Length(AInput));

to
     For k:= 1 to Length(AInput) do
     begin
           AProcess.Input.Write(AInput[k],length(AInput));
     end;


Then the program compiled and ran and when I clicked the button then the Pascal screen flashed up but then disappeared (good sign!).

When I opened the text file it had what I expected in - the full output as from the previous post.

Looks good. Thanks.
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

ludob

  • Hero Member
  • *****
  • Posts: 1173
Re: How can you control a console application from a Lazarus application?
« Reply #11 on: January 11, 2012, 11:38:58 am »
BigChimp made a nice class that encapsulates console in and output: http://www.lazarus.freepascal.org/index.php?topic=15315.0 . I suggest you take a look at that one.

Quote
When I opened the text file it had what I expected in - the full output as from the previous post.
Did you get the second line? Input echoing is only done for a real console, not a pipe.


HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #12 on: January 11, 2012, 03:55:20 pm »
@ludob
No, I didn't get the parts that were input. Thanks for the suggestion.

The suggestion by Leledumbo works with the line:

     AProcess.Input.Write(AInput[1],length(AInput) + 1);

The loop I suggested works, but it is really the wrong idea.
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #13 on: January 13, 2012, 11:52:37 am »
1. The reason that
AProcess.Input.Write(AInput[1],length(AInput));
didn't work is that the expected input is
'Fred'#13#10
not
'Fred'#13

2. ludob wrote
Quote
BigChimp made a nice class that encapsulates console in and output: http://www.lazarus.freepascal.org/index.php?topic=15315.0 . I suggest you take a look at that one.

I downloaded this class. To test it I just changed the commandline to the appropriate executable:

a)The class worked with cmd.exe as given
 
b) The class worked with the pascal executable Hello0.exe from
program Hello;
begin
   writeln('Hello');
end.


c) The class did NOT work with the pascal executable Hello1.exe from
program Hello1;
begin
   writeln('Hello');
   readln;
end.


d) The class did NOT work with the pascal executable Hello2.exe from
program Hello2;
var
   TheirName:string;
begin
   writeln('Hello');
   writeln('Enter your name');
   readln(TheirName);
   writeln('Your name is ', TheirName);
end.


When it didn't work, there was no output or input shown.

My conclusion is that the problem is with input into Pascal executables.

Any ideas?
« Last Edit: January 13, 2012, 11:54:18 am by HappyLarry »
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: How can you control a console application from a Lazarus application?
« Reply #14 on: January 13, 2012, 06:45:01 pm »
I tried this in Linux (Ubuntu) too.

The given program fdisk seemed OK but the Hello programs (above) didn't work apart from Hello0.
« Last Edit: January 13, 2012, 06:53:53 pm by HappyLarry »
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

 

TinyPortal © 2005-2018