* * *

Author Topic: TProcess.Output is permanently empty  (Read 3012 times)

Edson

  • Hero Member
  • *****
  • Posts: 865
Re: TProcess.Output is permanently empty
« Reply #15 on: January 04, 2018, 11:03:18 pm »
Maybe you can use my library: https://github.com/t-edson/UnTerminal

It uses events to indicate when there is output from a process.
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

TCH

  • Jr. Member
  • **
  • Posts: 75
Re: TProcess.Output is permanently empty
« Reply #16 on: January 04, 2018, 11:22:58 pm »
I see the license is LGPL. Can we use it in a closed source commercial product? If yes, then i'll try it on tomorrow, or on the weekend.

Leledumbo

  • Hero Member
  • *****
  • Posts: 7848
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: TProcess.Output is permanently empty
« Reply #17 on: January 05, 2018, 01:23:22 am »
The C program is closed, so i cannot even give the source of it. As for the Pascal, as i said, it's not mine, i cannot distribute the sources.

The external program is running fine, it communicates via serial port and i see the LED blinking. If the programs tops, the LED stops blinking. And it does not matter if i use CommandLine or the new methods, i've checked the parameters and all is fine...
You don't have to give the same source code, create yourself one that demonstrates the behavior, as simple as possible.

In that case, the program might really be running, but buffers its output. Again this is just a guess. One more thing, it could actually be writing to stderr instead of stdout, so you might want to add poStderrToOutPut to Options property.

TCH

  • Jr. Member
  • **
  • Posts: 75
Re: TProcess.Output is permanently empty
« Reply #18 on: January 05, 2018, 10:24:13 am »
You don't have to give the same source code, create yourself one that demonstrates the behavior, as simple as possible.
I already did. It's in the opening post.
In that case, the program might really be running, but buffers its output. Again this is just a guess. One more thing, it could actually be writing to stderr instead of stdout, so you might want to add poStderrToOutPut to Options property.
No, it's writing to stdout. I tried poStderrToOutPut, but no avail. I tried to redirect the program's output to a file from console and 1> did the redirect, 2> did not. What do you mean by "it buffers its output"? It's just do a lot of printf.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 6099
Re: TProcess.Output is permanently empty
« Reply #19 on: January 05, 2018, 11:12:43 am »
You don't have to give the same source code, create yourself one that demonstrates the behavior, as simple as possible.
I already did. It's in the opening post.

No, that is only a fragment, and as already mentioned misses execute or anything else that activates the tprocess instance.

TCH

  • Jr. Member
  • **
  • Posts: 75
Re: TProcess.Output is permanently empty
« Reply #20 on: January 05, 2018, 11:20:39 am »
But it contains the essential part and as i already told, i only missed the Execute from this example code; it is in the original.

Leledumbo

  • Hero Member
  • *****
  • Posts: 7848
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: TProcess.Output is permanently empty
« Reply #21 on: January 06, 2018, 01:32:47 am »
But it contains the essential part and as i already told, i only missed the Execute from this example code; it is in the original.
Uncompilable, therefore cannot be used as a base to reproduce the behavior. You first create one that all of us can compile, using your real C executable where it demonstrates the behavior that you said, where the output stream is always empty. You then rename the C executable (in the Pascal code) to whatever you wish, keeping the rest of the code intact. Then post or attach here.

Read this stackoverflow post for better explanation. In short, help us help you.

engkin

  • Hero Member
  • *****
  • Posts: 1952
Re: TProcess.Output is permanently empty
« Reply #22 on: January 06, 2018, 02:42:19 am »
@TCH
What OS/CPU and Laz/FPC version?

Does the example in this post work for you?
If yes, replace the CommandLine with yours. Does it work?

Your first post shows that the C prog takes two arguments. What type of arguments? Numbers?

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 683
Re: TProcess.Output is permanently empty
« Reply #23 on: January 06, 2018, 06:19:07 am »
hello,
i have tried my example with the option -i to 200 ms for the ping ( -i = Wait interval seconds between sending each packet ) :
Code: Pascal  [Select]
  1. Proc := TProcess.Create(nil);
  2. Proc.Options := [poUsePipes];
  3. Proc.Executable := '/bin/ping';
  4. Proc.Parameters.Add('-c 100');
  5. Proc.Parameters.Add('-i 0.2');
  6. Proc.Parameters.Add('127.0.0.1');
  7. Proc.Execute();

it still works with Output every 200 milliseconds on Ubuntu 16.04 64 bits Lazarus 1.8 !

Friendly, J.P

TCH

  • Jr. Member
  • **
  • Posts: 75
Re: TProcess.Output is permanently empty
« Reply #24 on: January 12, 2018, 03:13:07 pm »
Uncompilable, therefore cannot be used as a base to reproduce the behavior. You first create one that all of us can compile, using your real C executable where it demonstrates the behavior that you said, where the output stream is always empty. You then rename the C executable (in the Pascal code) to whatever you wish, keeping the rest of the code intact. Then post or attach here.
Okay, here is the real one:
Code: [Select]
constructor TEMP860Thread.Create(CreateSuspended : boolean);
begin
  inherited Create(CreateSuspended);
  Self.Stop := False;
end;

procedure TEMP860Thread.ErrorSet;
begin
     set_error_bits(ERROR_CASHHANDLER_DIED);
end;

procedure TEMP860Thread.ErrorClear;
begin
     set_error_bits(ERROR_CASHHANDLER_DIED);
end;

procedure TEMP860Thread.CoinDrop;
begin
     add_coin(Self.Money);
end;

procedure TEMP860Thread.FinishTransaction;
begin
     finish_transaction;
end;

procedure TEMP860Thread.ClearTransaction;
begin
     clear_transaction;
end;

procedure TEMP860Thread.Execute;
var
    bc, i, a, code, tries: longint;
    cs: array[0..3] of string;
begin
     while (not Self.Stop) do
     begin
{$IFDEF CPUARMHF}
         if (not emp860.Running) then
         begin
              if (emp860_fails < 16) then
              begin
                   emp860.Execute;
                   writeln('EMP860 executed.');
                   inc(emp860_fails);
              end
              else
      begin
         Synchronize(@ErrorSet);
              end;
         end
         else
         begin
              writeln('READ');
              if (emp860_fails > 15) then
              begin
         Synchronize(@ErrorClear);
              end;
              emp860_fails := 0;
              bc := 0;
              tries := 0;
              while ((bc = 0) and (tries < 20)) do
              begin
                   sleep(10);
                 bc := emp860.Output.NumBytesAvailable;
                   inc(tries);
              end;
              writeln('bc = ' + inttostr(bc));
              if (bc = 0) then
              begin
                   inc(emp860_nosignal);
                   if (emp860_nosignal > 15) then
                   begin
                        emp860_nosignal := 0;
                emp860.Terminate(0);
                        writeln('EMP860 terminated.');
                   end;
              end
              else
              begin
                   emp860.Output.Read(pipe_buffer[0], bc);
                   emp860_nosignal := 0;
     i := 0;
                   a := 0;
                   cs[0] := '';
                   cs[1] := '';
                   cs[2] := '';
                   cs[3] := '';
                   while (i < bc) do
                   begin
                         if ((pipe_buffer[i] <> ';') and (pipe_buffer[i] <> #10)) then
                         begin
                            cs[a] := cs[a] + pipe_buffer[i];
                         end
                         else
                         begin
                              if (pipe_buffer[i] = ';') then
                              begin
                                   inc(a);
                              end
                              else
                              begin
                                   code := strtoint(cs[0]);
                                   if (code = 10) then
                                   begin
                Self.Money := strtoint(cs[2]);
                                        Synchronize(@CoinDrop);
                                   end;
                                   if (code = 12) then
                                   begin
                                        Synchronize(@FinishTransaction);
                                   end;
                                   if (code = 13) then
                                   begin
                                        Synchronize(@ClearTransaction);
                                   end;
                                   a := 0;
                                   cs[0] := '';
                                   cs[1] := '';
                                   cs[2] := '';
                                   cs[3] := '';
                              end;
                         end;
                         inc(i);
                   end;
              end;
         end;
{$ENDIF}
sleep(100);
WriteLn('EMP860 TICK');
     end;
end;
and in the startup:
Code: [Select]
{$IFDEF CPUARMHF}
     WriteLn('EMP860 process initialization...');
     emp860 := TProcess.Create(nil);
     emp860.Options := [poUsePipes, poStderrToOutPut];
     emp860.CommandLine := '/usr/local/bin/emp860 /dev/ttyUSB0 ' + generate_bitmask(AcceptableCoins, 6);
     emp860_fails := 0;
     emp860_nosignal := 0;
{$ENDIF}
     WriteLn('Creating EMP860 thread...');
     emp860thread := TEMP860Thread.Create(false);
And the declaration:
Code: [Select]
  TEMP860Thread = class(TThread)
    protected
      procedure Execute; override;
          procedure ErrorSet;
          procedure ErrorClear;
          procedure CoinDrop;
          procedure FinishTransaction;
          procedure ClearTransaction;
    public
          var Stop: Boolean;
    var Money: Word;
      Constructor Create(CreateSuspended : boolean);
  end;
@TCH
What OS/CPU and Laz/FPC version?

Does the example in this post work for you?
If yes, replace the CommandLine with yours. Does it work?

Your first post shows that the C prog takes two arguments. What type of arguments? Numbers?
Linux on ARMHF, Lazarus is 1.6.4 and FPC is 3.0.2.

The linked example did not worked for me.
hello,
i have tried my example with the option -i to 200 ms for the ping ( -i = Wait interval seconds between sending each packet ) :
Code: Pascal  [Select]
  1. Proc := TProcess.Create(nil);
  2. Proc.Options := [poUsePipes];
  3. Proc.Executable := '/bin/ping';
  4. Proc.Parameters.Add('-c 100');
  5. Proc.Parameters.Add('-i 0.2');
  6. Proc.Parameters.Add('127.0.0.1');
  7. Proc.Execute();

it still works with Output every 200 milliseconds on Ubuntu 16.04 64 bits Lazarus 1.8 !

Friendly, J.P
Nope, did not work for me.
« Last Edit: January 12, 2018, 03:23:27 pm by TCH »

TCH

  • Jr. Member
  • **
  • Posts: 75
Re: TProcess.Output is permanently empty
« Reply #25 on: January 13, 2018, 04:44:00 pm »
Solved in a different way. I got the C++ sources of the external program, took the needed parts out and integrated the object file into my Lazarus program.

Thaddy

  • Hero Member
  • *****
  • Posts: 5795
Re: TProcess.Output is permanently empty
« Reply #26 on: January 13, 2018, 04:58:35 pm »
If you needed to do that, the C++ written program does not use any known standard regarding IO. Because those are pretty well defined. Let me guess: direct access.... by-passing cout...
recommends {$macro on}{$define Silly:=ObjFpc}

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 6099
Re: TProcess.Output is permanently empty
« Reply #27 on: January 13, 2018, 07:05:58 pm »
Code: Pascal  [Select]
  1. Proc := TProcess.Create(nil);
  2. Proc.Options := [poUsePipes];
  3. Proc.Executable := '/bin/ping';
  4. Proc.Parameters.Add('-c 100');
  5. Proc.Parameters.Add('-i 0.2');
  6. Proc.Parameters.Add('127.0.0.1');
  7. Proc.Execute();

This is probably wrong. You need to add e.g. -c and 100 as separate parameters. It matters most on *nix, less on Windows.
 

TCH

  • Jr. Member
  • **
  • Posts: 75
Re: TProcess.Output is permanently empty
« Reply #28 on: January 14, 2018, 01:45:53 pm »
If you needed to do that, the C++ written program does not use any known standard regarding IO. Because those are pretty well defined. Let me guess: direct access.... by-passing cout...
The C++ program used printf, but now i omitted the console writing, i changed the main function to another which has two additional parameters besides the original (i mean original expected, not the argc/argv, but what arrives in them): one is responsible for allowing the function to continue and the other is a procedure's address. So practically i run the C++ function from Pascal, give them an address of a boolean which i use for halting the cycle and a Pascal procedure's address which handles the arriving result.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus