Dear Lazarus community,
I've started playing around with this nifty and very impressive language and IDE of yours, and tried to implement a little Windows GUI application to run external console programs with. I do not have any programming experience with either Windows nor Pasal/Delphi to speak of, and have some difficulty in assessing I am doing wrong about a runtime failure I experience, which is why I turn to you to ask for help.
I adapted some example code from the wiki and StackOverflow to have a child process running in the background with my application communication with it over its stdio descriptors. It seems like something during the execution goes wrong, and there might be some memory corruption involved. My x86 ASM is too limited to know what exactly is going on, but the memory address shown in the crash message does not look right to me.
My procedure:
function RunExternalAppInMemo(AppPath: string; ArgV: TStringArray;
OutMemo: TMemo; ErrMemo: TMemo): integer;
const
READ_BYTES = 2048;
var
aProcess: TProcess;
NumBytes: longint;
Buffer: array of byte;
ErrBuffer: array of byte;
ReadCount: integer;
LastRead: longint;
ExitCode: integer;
i: integer;
begin
Buffer := [];
ErrBuffer := [];
SetLength(Buffer, READ_BYTES + 1);
SetLength(ErrBuffer, READ_BYTES + 1);
LastRead := -1;
ExitCode := -1;
aProcess := TProcess.Create(nil);
aProcess.Executable := AppPath;
for i := 0 to Length(ArgV) - 1 do
begin
aProcess.Parameters.Add(ArgV[i]);
ErrMemo.Lines.Add(ArgV[i]);
end;
aProcess.ShowWindow := swoHIDE;
//aProcess.Options := aProcess.Options + [poUsePipes] + [poStdErrToOutput];
aProcess.Options := aProcess.Options + [poUsePipes];
try;
//ShowMessage(BoolToStr(aProcess.Running));
aProcess.Execute;
//ShowMessage(IntToStr(aProcess.Output.NumBytesAvailable));
while aProcess.Running or (aProcess.Output.NumBytesAvailable > 0) or
(aProcess.Stderr.NumBytesAvailable > 0) do
begin
while aProcess.Output.NumBytesAvailable > 0 do
begin
ReadCount := Min(READ_BYTES, aProcess.Output.NumBytesAvailable);
ShowMessage('Have bytes stdout: ' + IntToStr(aProcess.Output.NumBytesAvailable) + ' - Will read stdout: ' + IntToStr(ReadCount));
ShowMessage('Have bytes stderr: ' + IntToStr(aProcess.Stderr.NumBytesAvailable));
LastRead := aProcess.Output.Read(Buffer, ReadCount);
if (LastRead = 0) then ShowMessage('Read 0 bytes, EOF?');
ShowMessage('Have read:' + IntToStr(LastRead));
// OutMemo.Lines.Append(PChar(Buffer)); // TODO: manage and eval buffer intellgently to get at logical lines or records of output to append
application.ProcessMessages;
ShowMessage('About to crash in NumBytesAvailable...');
ShowMessage('Have bytes stdout: ' + IntToStr(aProcess.Output.NumBytesAvailable));
ShowMessage('First iter end');
end;
while aProcess.Stderr.NumBytesAvailable > 0 do
begin
ReadCount := Min((READ_BYTES - 1), aProcess.Stderr.NumBytesAvailable);
aProcess.Stderr.Read(ErrBuffer, ReadCount);
ErrMemo.Lines.Add(PChar(ErrBuffer));
application.ProcessMessages;
end;
sleep(10);
end;
ExitCode := aProcess.ExitStatus;
finally
setlength(Buffer, 0);
setlength(ErrBuffer, 0);
aProcess.Free;
end;
Result := ExitCode;
end;
The crash message reads like this:
Project ProcRun raised exception class 'External: ACCESS VIOLATION' with message: Access violation reading from address $FFFF...FFFF.
In file 'unit1.pas' at line 109: ShowMessage('Have bytes stdout' + IntToStr(aProcess.Output.NumBytesAvailable));
Interacting with the TProcess instance that seems to be executing my dependant process just fine after having read from
aProcess.Output.Read seems to trigger the crash.
I have attached a contrived example of my code that should be able to demonstrate the failure on Windows hosts that can build it.
Can anyone please enlighten me what I am droing wrong? Any help - as well as tips on how to use the debugger to learn more about the underlyzing cause of this crash - would be greatly appreciated!
[Edited to fix code tags. Please read
How to use the forum.]