Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Using pipes and createprocess



Permlink Replies: 2 - Last Post: Dec 18, 2017 11:45 PM Last Post By: Michael Rabatsc... Threads: [ Previous | Next ]
Michael Rabatsc...

Posts: 125
Registered: 1/22/07
Using pipes and createprocess
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 18, 2017 6:01 AM
Hey there!

I'm struggling a bit with pipes and reading from them...
Here is what I want:

There is a tool on physionet.org (dfa.c -> dfa.exe) which takes
somes console input and writes out the resulting parameters.
Also to the console...

So ... it works quite well in case I open a console
and put in

dfa.exe -l 4 -u 64 -d 1 < myinput.txt

-> puts out the resulting dfa parameters on the console..

Now I want to create my own dfa analysis and for verification I wanted
to compare my results with the open source stuff.
For that reason I tried to call the dfa.exe via
CreateProcess, input there some pipe handles and let it do the exact
same thing.

Now the problem is that dfa.exe immediately exits and writes something
to stderr. I tried to read that but I always get 0 available bytes in
that pipe (but the correct exit code aka 1)

I actually also tried to create a simple console appication which just
writes something to the console and immediately exits then -> also
here... I cannot read the output...

Here is the some source:
Note: interesting is the part with the check for the exit process and
the peek call... always says there is no data...

function TfrmHRVEval.CalcPhysionetDFA(rr: TDoubleDynArray): TDoubleDynArray;
var StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
SecurityAttr: TSecurityAttributes;
PipeOutputRead: THandle;
PipeOutputWrite: THandle;
PipeInputRead, PipeInputWrite : THandle;
PipeErrorRead, PipeErrorWrite : THandle;
Succeed: Boolean;
Buffer: TByteDynArray;
NumberOfBytesRead: DWORD;
overallRead : integer;
s : string;
output : UTF8String;
counter: integer;
fmt : TFormatSettings;
numBytesWritten : longword;
aLine : TStringList;
exitCode : LongWord;
numBytesAvail : LongWord;
begin
GetLocaleFormatSettings(0, fmt);
fmt.DecimalSeparator := '.';
SetLength(buffer, 4096);

// create command line
FillChar(buffer[0], High(buffer) + 1, 0);

// Initialize process info
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);

// initialize SecurityAttr
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.bInheritHandle := True;
SecurityAttr.lpSecurityDescriptor := nil;

// create Pipes
CreatePipe(PipeInputRead, PipeInputWrite, @SecurityAttr, 0);
CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
CreatePipe(PipeErrorRead, PipeErrorWrite, @SecurityAttr, 0);

SetHandleInformation( PipeOutputWrite, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation( PipeOutputRead, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation( PipeInputRead, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation( PipeInputWrite, HANDLE_FLAG_INHERIT, 0);

SetHandleInformation( PipeErrorRead, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation( PipeErrorWrite, HANDLE_FLAG_INHERIT, 0);

// initialize StartupInfo
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb := SizeOf(StartupInfo);
StartupInfo.hStdInput := PipeInputRead;
StartupInfo.hStdOutput := PipeOutputWrite;
StartupInfo.hStdError := PipeErrorWrite;
StartupInfo.wShowWindow := sw_Hide;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;

// #################################################
// #### Main process cration step
s := '"' + fDFACmd + '" oasch';// + fDFAParams;
output := '';
if CreateProcess(nil, PChar(s), nil,
nil, true,
CREATE_DEFAULT_ERROR_MODE or
CREATE_NO_WINDOW or
NORMAL_PRIORITY_CLASS, nil, nil,
StartupInfo,
ProcessInfo) then
begin
// write rr intervals via pipe:
for counter := 0 to Length(rr) - 1 do
begin
if WaitForSingleObject(ProcessInfo.hProcess, 100) <>
WAIT_TIMEOUT then
begin
GetExitCodeProcess(ProcessInfo.hProcess, exitCode);

if exitCode = 1 then
begin
output := '';
// get input from stderr
while PeekNamedPipe( PipeErrorRead,
@buffer[0], sizeof(buffer), Pointer(@NumberOfBytesRead),
Pointer(@numBytesAvail), nil) do
begin
if (NumberOfBytesRead <> 0) or
(numBytesAvail > 0) then
begin
ReadFile(PipeErrorRead, Buffer[0],
255, NumberOfBytesRead, nil);
SetLength(output, Length(output) +
NumberOfBytesRead);
Move(buffer[0],
output[Length(output) - NumberOfBytesRead + 1], NumberOfBytesRead);
end
else
break;
end;

OutputDebugString(PChar( String(output) ));
end;

raise Exception.Create('Process exited with code: '
+ IntToStr(exitCode));
end;

output := Format('%.5f' + #13#10, [rr[counter]], fmt);
if not WriteFile(PipeInputWrite, output[1],
Length(output)*sizeof(output[1]), numBytesWritten, nil) then
raise Exception.Create('WTF');

if numBytesWritten <> length(output)*sizeof(output[1]) then
begin
CloseHandle(PipeInputRead);
CloseHandle(PipeInputWrite);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeOutputRead);
CloseHandle(ProcessInfo.hProcess);

raise Exception.Create('DFA write of rr intervals
failed');
end;
end;

CloseHandle(PipeInputWrite);

sleep(1000);

//Ausgabe Read-Pipe auslesen
overallRead := 0;
while true do
begin
NumberOfBytesRead := 0;
succeed := ReadFile(PipeOutputRead, Buffer[0], 255,
NumberOfBytesRead, nil);
if not succeed then
break;

SetLength(output, Length(output) + NumberOfBytesRead);
if NumberOfBytesRead > 0 then
Move( Buffer[0], output[overallRead + 1],
NumberOfBytesRead);

inc(overallRead, NumberOfBytesRead);
end;

CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeInputRead);

while WaitForSingleObject(ProcessInfo.hProcess, 1000) =
WAIT_TIMEOUT do
begin
if cancelBeatAnalysis then
break;
end;

CloseHandle(ProcessInfo.hProcess);
end
else
begin
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeInputRead);
CloseHandle(PipeInputWrite);
end;

// ###########################################
// #### convert output to dfa params
aLine := TStringList.Create;
try
with TStringList.Create do
try
Text := String( output );

SetLength(Result, Count);

for counter := 0 to Count - 1 do
begin
aLine.CommaText := Strings[counter];

if aLine.Count = 2 then
Result[counter] := StrToFloat(aLine[0], fmt);
end;
finally
Free;
end;
finally
aLine.Free;
end;
end;

Peter Below

Posts: 1,227
Registered: 12/16/99
Re: Using pipes and createprocess
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 18, 2017 10:49 PM   in response to: Michael Rabatsc... in response to: Michael Rabatsc...
Michael Rabatscher wrote:

Hey there!

I'm struggling a bit with pipes and reading from them...
Here is what I want:

There is a tool on physionet.org (dfa.c -> dfa.exe) which takes
somes console input and writes out the resulting parameters.
Also to the console...

So ... it works quite well in case I open a console
and put in

dfa.exe -l 4 -u 64 -d 1 < myinput.txt

-> puts out the resulting dfa parameters on the console..

If you use a command line like
dfa.exe -l 4 -u 64 -d 1 < myinput.txt > myoutput.txt

The program output should go to the myoutput.txt file instead of the
console. So the easiest way to handle your problem is to have your
program create a batch file with the required command line (using full
pathes enclosed in double quotes for the files) and then just run that
via ShellExecute. Then read the resulting file and analyze it.
Much easier to code than all this pipe stuff.

--
Peter Below
TeamB

Michael Rabatsc...

Posts: 125
Registered: 1/22/07
Re: Using pipes and createprocess
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 18, 2017 11:45 PM   in response to: Peter Below in response to: Peter Below

The program output should go to the myoutput.txt file instead of the
console. So the easiest way to handle your problem is to have your
program create a batch file with the required command line (using full
pathes enclosed in double quotes for the files) and then just run that
via ShellExecute. Then read the resulting file and analyze it.
Much easier to code than all this pipe stuff.

Yeah actually that would be my next step to try.

kind regards
Mike
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02