2


2

CreateProcessはすぐに戻りますが、開始されたプロセスが非表示の場合のみ

CreateProcess API呼び出しのわかりやすいラッパーを提供する以下のDelphiコードがあります。

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;

これを使用してバッチファイルを開始し、バッチファイルが戻るのを待ちます。 「ShowWindow」の値をTrueのままにしておく限り、うまく機能します。 コマンドラインウィンドウを非表示にしようとすると、エラーなしですぐに戻ります。 ここで私の間違いを理解するのを手伝ってくれますか? 使用例はコメント付きです。

//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);

奇妙なことは、ウィンドウが非表示になっているとき、開始したかのようにプロセスIDを取得することです。 しかし、それは非常に速く終了するので、タスクマネージャに表示されません。

バッチファイルの最後に「一時停止」があるように変更すると(実際には終了しません)、同じ結果が得られます。 したがって、コードの「if not(ShowWindow)」ブロックでフラグを設定しても、プロセスは実際には開始されないようです。

  • Rob Kennedyの提案の後、私のコードは次のようになります。*

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;

1 Answer


7


ShowWindow = False`を設定すると、スタートアップフラグに StartF_UseStdHandles`が含まれるように設定されますが、標準のI / Oハンドルに値を指定することはありません。 新しいプロセスが出力を書き込もうとすると、有効な出力ハンドルがないため失敗します。

ハンドルの値を提供しない場合は、ハンドルフィールドに有効な値があることを `CreateProcess`に伝えないでください。 起動フラグからそのフラグを省略します。

プロセスがうまく作成されたため、プロセスの作成時にエラーは発生しません。 問題が発生したのは、プロセスが実行を開始した後だけです。 プロセスの終了コードをチェックしていないので、障害を検出する方法はありません。