Delphi-作成されたプロセスを正常に終了します。 (tprocess / createProcessを使用)
-
06-07-2019 - |
質問
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」と入力することを期待するメニューシステムがある場合があります。プログラムを終了します。
要するに、プログラムがどのように終了するかを事前に知らない限り、プログラムを正常に終了することはできません。