I want to start a potentially long running background process from Delphi. I want to leave the process running independently, but first I want to check that the process started OK.
If anything went wrong on startup, I want to capture any output written to standardErr and log it. If the background process starts OK, my program needs to be able to exit and leave the spawned process running.
The psuedo code would be something like this:
process:=RunProgramInBackground('someCommand.exe');
sleep(1000); // Wait a bit to see if the program started OK
if process.Finished and process.ExitCode=FAIL then
Raise Exception.Create(process.ErrorStream);
process.Disp开发者_JAVA技巧ose; // Close any connection we may still have to the running process
Program.Exit; // Background process keeps running
I've looked at a few things (WinExec, CreateProcess, ShellExecute, JclMiscel) but can't find any examples for what I'm trying to do. What is the best way to do this?
I'm using Delphi 2010
The background process is a 3rd party program I don't have the source to.
Check out this article. I quote: "Here is an updated and improved version of the code that allows you to choose in code whether the calling application waits until the other program closes before continuing or just carries on leaving the newly started program to its own devices".
procedure ExecNewProcess(ProgramName : String; Wait: Boolean);
var
StartInfo : TStartupInfo;
ProcInfo : TProcessInformation;
CreateOK : Boolean;
begin
{ fill with known state }
FillChar(StartInfo,SizeOf(TStartupInfo),#0);
FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
StartInfo.cb := SizeOf(TStartupInfo);
CreateOK := CreateProcess(nil, PChar(ProgramName), nil, nil,False,
CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS,
nil, nil, StartInfo, ProcInfo);
{ check to see if successful }
if CreateOK then
begin
//may or may not be needed. Usually wait for child processes
if Wait then
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
end
else
begin
ShowMessage('Unable to run '+ProgramName);
end;
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end;
Edited: after reading your comments, I suggest that you look at this previous question
I ended up using the example No'Am linked to, and adding code to check that the process started OK. This function only checks the exit code of the background process, it doesn't read the StdErr output.
Here is what I did:
/// <summary> Runs a new process in the background. Waits for a short period, then checks that the process started succesfully.
/// If the process has already finished, checks the exit status. Otherwise, leaves it to run. </summary>
/// <param> ProgramName The executable name, including any parameters.</param>
/// <param> TimeOut Milliseconds to wait before checking the process has executed correctly</param>
/// <param> Directory The full path of the working directory</param>
/// <exception> Exception If the process was not started correctly or if the process was started but returned
/// an error before the timeout.</exception>
procedure ExecBackgroundProcess(ProgramName : String; TimeOut: Integer; Directory:string);
var
StartInfo : TStartupInfo;
ProcInfo : TProcessInformation;
CreateOK : Boolean;
status: Cardinal;
theExitCode: Cardinal;
begin
FillChar(StartInfo,SizeOf(TStartupInfo),#0);
FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
StartInfo.cb := SizeOf(TStartupInfo);
UniqueString(ProgramName); // Required if a const string is passed in. Otherwise the program crashes.
CreateOK := CreateProcess(nil, PChar(ProgramName), nil, nil,False,
CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS+CREATE_NO_WINDOW,
nil, PChar(Directory), StartInfo, ProcInfo);
if CreateOK then
begin
status:=WaitForSingleObject(ProcInfo.hProcess, TimeOut);
if status<> WAIT_TIMEOUT then
begin
// Program has exited. Get exit code.
GetExitCodeProcess(ProcInfo.hProcess, theExitCode);
if theExitCode<>0 then raise Exception.Create('Program '''+ProgramName+''' failed with exit code '+IntToStr(theExitCode));
end
end
else
Raise Exception.Create('Unable to run '+ProgramName+' in directory '+Directory);
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end;
精彩评论