开发者

CreateProcess returns immediately, but only if the started process is hidden

I have the below Delphi code to provide a friendly wrapper for the CreateProcess API call.

function StartProcess(ExeName: string; CmdLineArgs: string = '';
  ShowWindow: boolean = True; WaitForFinish: boolean = False): integer;
const
  c_Wait = 100;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
begin
  //Simple wrapper for the CreateProcess command
  //returns the process id of the started process.
  FillChar(StartInfo,SizeOf(TStartupInfo),#0);
  FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
  StartInfo.cb := SizeOf(TStartupInfo);

  //this block is the only part of execution that is different
  //between my two calls.  What am I doing wrong with these flags?
  if not(ShowWindow) then begin
    StartInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    StartInfo.wShowWindow := SW_HIDE;
  end;

  CreateProcess(nil,PChar(ExeName + ' ' + CmdLineArgs),nil,nil,False,
    CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS,nil,nil,StartInfo,
    ProcInfo);

  Result := ProcInfo.dwProcessId;

  if WaitForFinish then begin
    while IsProcessRunning(Result) do begin
      Sleep(c_Wait);
    end;
  end;

end;

I am using it to start a batch file, and wait for the batch file to return. It works nicely as long as I leave the "ShowWindow" value as True. If I try to hide the command line window, then it returns immediately with no error. Can anyone help me understand my mistake here? Example usage is below with comments.

//this will not show the cmd line window, and it will return immediately
StartProcess('C:\run_me.bat','',False,True);

//this will show the cmd line, and (correctly) wait for the job to finish
StartProcess('C:\run_me.bat','',True,True);

An odd thing is when the window is hidden, I still get a process ID back, as if it started. But it quits so fast that I can't see it in the task manager.

If I change the batch file to have a "pause" at the end of it (so it will never really finish), I still get the same result. So it appear开发者_Python百科s that the process really does not start when I set the flags in the "if not(ShowWindow)" block of my code.

After Rob Kennedy's suggestions, my code looks like this:

function StartProcess(ExeName: string; CmdLineArgs: string = '';
  ShowWindow: boolean = True; WaitForFinish: boolean = False): integer;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
begin
  //Simple wrapper for the CreateProcess command
  //returns the process id of the started process.
  FillChar(StartInfo,SizeOf(TStartupInfo),#0);
  FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
  StartInfo.cb := SizeOf(TStartupInfo);

  if not(ShowWindow) then begin
    StartInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartInfo.wShowWindow := SW_HIDE;
  end;

  CreateProcess(nil,PChar(ExeName + ' ' + CmdLineArgs),nil,nil,False,
    CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS,nil,nil,StartInfo,
    ProcInfo);

  Result := ProcInfo.dwProcessId;

  if WaitForFinish then begin
    WaitForSingleObject(ProcInfo.hProcess,Infinite);
  end;

  //close process & thread handles
  CloseHandle(ProcInfo.hProcess);
  CloseHandle(ProcInfo.hThread);
end;


When you set ShowWindow = False, you set the startup flags to include StartF_UseStdHandles, but you never provide any values for the standard I/O handles. The moment the new process attempts to write any output, it will fail because it doesn't have a valid output handle.

If you're not going to provide values for the handles, then don't tell CreateProcess that the handle fields have valid values in them. Omit that flag from the startup flags.

You don't get any error when creating the process because creating the process went fine. It's only after the process started running that it ran into problems. You're not checking the process's exit code, so there's no way you'd detect any failure.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜