1

多くのプログラムを実行する 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 プロシージャを介して起動したプログラムも停止 (強制終了ではなく) したいと考えています。

これをどのように行いますか?

4

3 に答える 3

4

win32 のプロセス関連の機能を適切にラップするJVCLのTJvCreateProcessコンポーネントを使用します。この回答は、Dont-touch-winapi-unless-really-required 部門からのものです :-)

于 2008-11-06T11:10:40.680 に答える
1

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

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

EnumWindowsを使用して、すべてのウィンドウを循環し、プロセスに属するウィンドウを選択できます。(これらは、GetWindowThreadProcessIdがCreateProcessから提供されたものと同じプロセスIDを提供するものになります。)

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

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

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

于 2008-11-10T04:08:55.570 に答える
1

起動した 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;
于 2008-11-10T05:00:02.940 に答える