Delphi-作成されたプロセスを正常に終了します。 (tprocess / createProcessを使用)

StackOverflow https://stackoverflow.com/questions/268208

質問

Delphiで記述されたWindowsサービスを使用して、多くのプログラムを実行しています。

サービスを停止すると、これらのプログラムも閉じます。サービスが最初に作成されたとき、これは正常に機能しましたが、tProcessコンポーネントを更新し、今では-下位プログラムが閉じられていないと思います。

in tProcess-新しいプロセスを開始するコードは次のとおりです。

  if CreateProcess( nil , PChar( FProcess.Command ) , nil , nil , False ,
    NORMAL_PRIORITY_CLASS , nil , Directory ,
    StartupInfo , ProcessInfo ) then
    begin
      if FProcess.Wait then
        begin
          WaitForSingleObject( ProcessInfo.hProcess , Infinite );
          GetExitCodeProcess( ProcessInfo.hProcess , ExitCode );
          if Assigned( FProcess.FOnFinished ) then
            FProcess.FOnFinished( FProcess , ExitCode );
        end;
      CloseHandle( ProcessInfo.hProcess );
      CloseHandle( ProcessInfo.hThread );
    end;

これによって呼び出される各実行可能ファイルはWindows GUIプログラムです(上部に閉じるボタンがあります)。

サービスを停止するとき、createProcessプロシージャを使用して起動したプログラムも停止します(強制終了しません)。

これをどうしますか?

役に立ちましたか?

解決

起動したProcessIdに一致する開いているウィンドウを列挙し、それらのウィンドウを閉じるように指示します。そのためのサンプルコードを次に示します。

uses Windows;

interface   

function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean; stdcall;

implementation

function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean; 
var   
  vID:DWORD; 
begin   
  GetWindowThreadProcessID(hHwnd, @vID);   
  if vID = dwData then   
  begin
    PostMessage(hHwnd, WM_CLOSE, 0, 0); //tell window to close gracefully
    Result := False;  //can stop enumerating    
  end   
  else   
  begin
    Result := TRUE;  //keep enumerating until you find your id   
  end; 
end;

次に、起動したアプリケーションをシャットダウンするときに、コードでこれを利用します。

Procedure TerminateMe(YourSavedProcessInfo:TProcessInformation);
var
  vExitCode:UINT;
begin
  GetExitCodeProcess(YourSavedProcessInfo.hProcess, vExitCode);
  if (vExitCode = STILL_ACTIVE) then  //launched app still running..
  begin
    //tell it to close
    EnumWindows(@MyTerminateAppEnum, YourSavedProcessInfo.dwProcessId);

    if WaitForSingleObject(YourSavedProcessInfo.hProcess, TIMEOUT_VAL) <> WAIT_OBJECT_0 then
    begin
      if not TerminateProcess(YourSavedProcessInfo.hProcess, 0) then  //didn't close, try to terminate
      begin
         //uh-oh   Didn't close, didn't terminate..
      end;
    end;
  end;
  CloseHandle(YourSavedProcessInfo.hProcess);
  CloseHandle(YourSavedProcessInfo.hThread);
end;

他のヒント

JVCL TJvCreateProcess コンポーネントを使用して、プロセスをラップしますwin32の関連機能を適切な方法で。この回答はDont-touch-winapi-unless-really-required departmentから来ています:-)

プロセスを停止する唯一の一般的な方法は、 TerminateProcess 。しかし、それはあなたが得ることができる限り優雅ではありません。プロセスを適切に閉じるには、プロセスに停止したいことを伝え、それに従うことを期待する必要があります。ただし、一般的にそれを行う方法はありません。

GUIプログラムの場合、実行を停止するように指示する通常の方法は、メインウィンドウを閉じることです。 「メインウィンドウ」の正式なアイデアはありません。しかし。プログラムには0個以上のウィンドウを含めることができ、プログラムの動作を停止するために閉じる必要があるウィンドウを外部から知る方法はありません。

EnumWindows を使用して、すべてのウィンドウを切り替え、プロセスに属するものを選択します。 ( GetWindowThreadProcessId が同じプロセスを提供するものになります。 CreateProcessが提供したID。)

ウィンドウを閉じるだけでは不十分な場合があります。プログラムは、ダイアログボックスを表示する場合があります(確認のプロンプト、変更の保存などを要求する)そのダイアログボックスを閉じる方法を事前に知る必要があります。

非GUIプログラムでも同様の問題が発生する可能性があります。 Ctrl + Cキーストロークをシミュレートすれば十分かもしれません。ただし、そのキーストロークをキャッチして処理する方法が異なる場合があります。 「Q」と入力することを期待するメニューシステムがある場合があります。プログラムを終了します。

要するに、プログラムがどのように終了するかを事前に知らない限り、プログラムを正常に終了することはできません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top