I want to run a background application from my Delphi code. The application that opens is a DOS based EXE which outputs stuff to the DOS window. The program will be open indefinitely until it is closed from task manager. The current code I use to open the application is;
procedure CaptureConsoleOutput(const ACommand, AParameters: String; CallBack: TArg<PAnsiChar>);
const
CReadBuffer = 2400;
var
saSecurity: TSecurityAttributes;
hRead: THandle;
hWrite: THandle;
suiStartup: TStartupInfo;
piProcess: TProcessInformation;
pBuffer: array [0 .. CReadBuffer] of AnsiChar;
dBuffer: array [0 .. CReadBuffer] of AnsiChar;
dRead: DWord;
dRunning: DWord;
begin
saSecurity.nLength := SizeOf(TSecurityAttributes);
saSecurity.bInheritHandle := True;
saSecurity.lpSecurityDescriptor := nil;
if CreatePipe(hRead, hWrite, @saSecurity, 0) then
begin
FillChar(suiStartup, SizeOf(TStartupInfo), #0);
suiStartup.cb := SizeOf(TStartupInfo);
suiStartup.hStdInput := hRead;
suiStartup.hStdOutput := hWrite;
suiStartup.hStdError := hWrite;
suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
suiStartup.wShowWindow := SW_HIDE;
if CreateProcess(nil, pChar(ACommand + ' ' + AParameters), @saSecurity, @saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess) then
begin
repeat
dRunning := WaitForSingleObject(piProcess.hProcess, 100);
//Application.ProcessMessages();
repeat
dRead := 0;
ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil);
if(dRead > 0) then
begin
pBuffer[dRead] := #0;
//ShowMessage(pBuffer);
//OemToAnsi(pBuffer, pBuffer);
//Unicode support by Lars Fosdal
OemToCharA(pBuffer, dBuffer);
CallBack(dBuffer);
end;
until (dRead < CReadBuffer);
until (dRunning <> WAIT_TIMEOUT);
CloseHandle(piProcess.hProcess);
CloseHandle(piProcess.hThread);
end;
CloseHandle(hRead);
CloseHandle(hWrite);
end;
end;
This is good, however because the program doesn't 'quit' and stays open forever, my application hangs, and the code never moves along.
Any help would be appreciated
Execute in the background: To execute in the background, instead of left- clicking on the execute icon, use the menu path Program > Execute in background.
You can easily send such commands to the background by hitting the Ctrl + Z keys and then using the bg command. Hitting Ctrl + Z stops the running process, and bg takes it to the background. You can view a list of all background tasks by typing jobs in the terminal. Use the fg command to get back to the running task.
If you don't need to do anything with the spawned process, you can simply close the handles that CreateProcess()
returned and move on, the process will keep running. But since you appear to need to read continuously from the output of the spawned process, you can simply move that logic into a worker thread so your main code is not blocked anymore.
//You have to put your conde inside a thread. For example:
//Let's suppose you want to ping Google Server. You'll have to create a thread just like //below in your interface section inside Delphi. You'll get this done by choosing File-New-//Other-Thread Object, Then name your thread as you want.
type TPing = class(TThread) private { Private declarations } protected procedure Execute; override; end;
//Copy your CaptureConsoleOutput procedure onto Thread unit.
//inside Execute procedure, call your CaptureConsoleOutput procedure. //In my case, I just capture the output directly in the Memo component.
//That worked just fine for me !
procedure TPing.Execute; begin Priority := tpLower; CaptureConsoleOutput('ping www.yahoo.com', '-t', Form1.Memo2); end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With