problems calling a DOS app from Delphi and capturing output
Posted on 2004-11-28
This really is a dos app .. not a console app. It is Wordnet and Quickview says that it is a dos executable.
I am using the code below, which works just fine for console apps.
It works OK for a simple dos test app and some of the time it works OK for Wordnet .. I am passing through stuff on the commandline.
Under W98 it attempts to access the floppy when I call a DOS app, and I can see no explanation for this. I AM using short pathnames. A: is not on the path. This happens irrespective of which dos app I am calling (even command/c dir *.* on W98).
So, maybe the attempted access to floppy on W98 is a clue (by tracking through the code it happens at the CreateProcess call). It does not do this on XP. Rebooting on W98 does not help.
The problem with calling Wordnet from Delphi is that it sometimes returns empty stuff. I can send it valid command line stuff, stuff that works when run from DOS and sometimes is OK when called in the Delphi call, and I get this non output.
I figured it might be something to do with handles or timing, but I can construct up a very heavy stress test and run it under DOS (ie a bunch of direct calls to Wordnet in a DOS batch file )and it works OK. So I don't think Wordnet itself is the culprit.
btw, I tried calling a batch file (from my Delphi app) that then invoked Wordnet . Same result as calling the app direct.
So, is there something wrong with my code ?
procedure RunConsoleApp2Strings(const DosOrConsoleApp:String;
ReadBuffer = 2400;
Security : TSecurityAttributes;
ReadPipe,WritePipe : THandle;
start : TStartUpInfo;
ProcessInfo : TProcessInformation;
Buffer : Pchar;
BytesRead : DWord;
Apprunning : DWord;
app : string;
app := sysutils.trim(DosOrConsoleApp);
if args <> '' then
app := app+' ' + Args;
With Security do begin
nlength := SizeOf(TSecurityAttributes);
binherithandle := true;
lpsecuritydescriptor := nil;
// create pipes for stdin and stdout
if Createpipe (ReadPipe, WritePipe, // 1 pipe, 2 handles
@Security, 0) then begin
Buffer := AllocMem(ReadBuffer + 1);
start.cb := SizeOf(start);
// setup pipes for stdin and stdout
start.hStdOutput := WritePipe;
start.hStdInput := ReadPipe;
start.dwFlags := STARTF_USESTDHANDLES
start.wShowWindow := SW_HIDE;
if CreateProcess (nil,
PChar(app), // should normally be a FULL command line
true, // new process inherits handles from the calling process
CREATE_NEW_CONSOLE+ // JA based on examination of CodeCentral code
NORMAL_PRIORITY_CLASS, // creation flags and process priority
nil, // environment (if different from calling process)
nil, // current drive and directory for the new process
start, // Startup info
ProcessInfo // ProcessInfor
Apprunning := WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
until (Apprunning <> WAIT_TIMEOUT);
BytesRead := 0;
outStrings.Text := outStrings.text + String(Buffer);
until (BytesRead < ReadBuffer);
// free handles for the spawned process and the thread
// the pipe handles need to be freed