Delphi - Изящно закрывающий созданный процесс в сервисе. (используя tprocess / createProcess) - PullRequest
1 голос
/ 06 ноября 2008

У меня есть служба 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.

Как бы вы это сделали?

Ответы [ 3 ]

4 голосов
/ 06 ноября 2008

Я бы использовал TJvCreateProcess компонент JVCL , который изящно объединяет все связанные с процессом функциональные возможности win32. Этот ответ поступил из отдела Dont-touch-winapi, если только в этом нет необходимости: -)

1 голос
/ 10 ноября 2008

Вы хотите перечислить открытые окна, которые соответствуют вашему запущенному 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;
1 голос
/ 10 ноября 2008

Единственный общий способ остановить процесс - это использовать TerminateProcess . Но это так далеко от грации, как вы можете получить. Чтобы изящно закрыть процесс, нужно сказать процессу, что вы хотите, чтобы он остановился, и затем надеяться, что он подчинится. Хотя, в общем-то, сделать это невозможно.

Для программы с графическим интерфейсом обычным способом сообщить, что вы хотите, чтобы она прекратила работать, является закрытие ее главного окна. Там нет формальной идеи "главного окна", хотя. Программа может иметь ноль или более окон, и нет никакого способа узнать извне, какое окно вы должны закрыть, чтобы программа перестала работать.

Вы можете использовать EnumWindows для циклического перебора всех окон и выбора тех, которые относятся к вашему процессу. (Это будут те, для которых GetWindowThreadProcessId дает тот же идентификатор процесса, который дал вам CreateProcess.)

Закрытие окна может быть недостаточно. Программа может отображать диалоговое окно (запрос подтверждения или запрос сохранения изменений и т. Д.). Вам нужно заранее знать, как закрыть это диалоговое окно.

Программы без графического интерфейса могут иметь похожие проблемы. Этого может быть достаточно для имитации нажатия клавиш Ctrl + C. Впрочем, он может по-разному отлавливать и обрабатывать нажатие клавиш. Он может иметь систему меню, которая ожидает, что вы наберете «Q» для выхода из программы.

Короче говоря, вы не можете изящно закрыть программу, если заранее не знаете, как эта программа будет закрыта.

...