Delphi - Изящно закрывающий созданный процесс в сервисе. (используя tprocess / createProcess)
-
06-07-2019 - |
Вопрос
У меня есть служба Windows, написанная на Delphi, которая запускает несколько программ. Р>
Останавливая службу, я хочу также закрыть эти программы. Когда сервис изначально был написан, это работало нормально, но я думаю, что я обновил компонент tProcess и теперь - подчиненные программы не закрываются. Р>
в 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 Programs (кнопка закрытия вверху). Р>
Когда я останавливаю службу, я также хочу остановить (не уничтожить) программы, которые я запустил с помощью процедуры 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;
Другие советы
Я бы использовал TJvCreateProcess компонент JVCL , который охватывает любой процесс изящный функционал win32. Этот ответ поступил из отдела Dont-touch-winapi, если только он действительно не требуется: -)
Единственный общий способ остановить процесс - это использовать TerminateProcess . Но это так далеко от грации, как вы можете получить. Чтобы изящно закрыть процесс, нужно сказать процессу, что вы хотите, чтобы он остановился, и затем надеяться, что он подчинится. Хотя, в общем, сделать это невозможно.
Для программы с графическим интерфейсом обычным способом сообщить, что вы хотите, чтобы она перестала работать, является закрытие ее главного окна. Нет формального представления о «главном окне». хоть. Программа может иметь ноль или более окон, и нет никакого способа узнать извне, какое окно вы должны закрыть, чтобы программа перестала работать.
Вы можете использовать EnumWindows для циклического просмотра всех окон и выберите те, которые принадлежат вашему процессу. (Это будут те, для которых GetWindowThreadProcessId выполняет тот же процесс Идентификатор, который вам дал CreateProcess.)
Закрытие окна может быть недостаточно. Программа может отображать диалоговое окно (запрос подтверждения или запрос сохранения изменений и т. Д.). Вам нужно заранее знать, как закрыть это диалоговое окно.
Программы без GUI могут иметь похожие проблемы. Этого может быть достаточно для имитации нажатия клавиш Ctrl + C. Впрочем, он может по-разному отлавливать и обрабатывать нажатие клавиш. В нем может быть система меню, которая ожидает, что вы наберете "Q" выйти из программы.
Короче говоря, вы не можете изящно закрыть программу, если заранее не знаете, как эта программа будет закрыта.