Delphi - graciosamente Encerramento Criado Processo no Serviço. (Usando TProcess / CREATEPROCESS)

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

Pergunta

Eu tenho um serviço do Windows escrito em Delphi que executa uma série de programas.

em parar o serviço, eu quero também fechar esses programas. Quando o serviço foi originalmente escrito, este bem trabalhado, mas eu acho que eu tenho atualizado o componente TProcess e agora - Os programas subordinados não estão sendo fechados.

em TProcess - Aqui está o código que começa os novos processos.

  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;

Cada um dos executáveis ??chamados por isso são programas gráficos do Windows (com um botão de fechar no topo).

Quando eu parar o serviço, eu também quero parar (não matar) os programas que eu já iniciado através do procedimento CreateProcess.

Como você faria isso?

Foi útil?

Solução

Você quer enumerar as janelas abertas que correspondem à sua lançado ProcessId e dizer aquelas janelas para perto. Aqui está um código de exemplo para isso:

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;

Em seguida, você vai querer utilizar isso em seu código quando você deseja desligar as aplicações lançadas:

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;

Outras dicas

Eu usaria TJvCreateProcess componente do JVCL que envolve cerca de qualquer processo funcionalidade relacionada de win32 de uma forma graciosa. Esta resposta vem de departamento, a menos que-realmente-required Dont-touch-winapi: -)

A única maneira genérica para parar um processo é usar TerminateProcess . Mas isso é tão longe da graciosa como você pode começar. Para graciosamente perto um processo, você precisa dizer ao processo que você gostaria que ele para parar, e depois espero que obedece. Não há nenhuma maneira de fazer isso, em geral, no entanto.

Para um programa GUI, da maneira usual para dizer-lhe que você quer que ele parar de correr é fechar a sua janela principal. Há nenhum idéia formal da "janela principal", embora. Um programa pode ter zero ou mais janelas, e não há nenhuma maneira de saber externamente qual você deveria perto, a fim de tornar o trabalho programa de parada.

Você pode usar EnumWindows para percorrer todas as janelas e selecione aqueles que pertencem ao seu processo. (Eles seriam os únicos para os quais GetWindowThreadProcessId dá o mesmo processo ID que CreateProcess lhe deu.)

O encerramento de uma janela pode não ser suficiente. O programa pode exibir uma caixa de diálogo (pedir confirmação, ou pedir para guardar as alterações, etc.). Você precisa saber com antecedência como descartar que a caixa de diálogo.

programas

Não-GUI pode ter problemas semelhantes. Ele pode ser o suficiente para simular uma combinação de teclas Ctrl + C. Ele pode pegar e alça que keystroke diferente, no entanto. Ele pode ter um sistema de menu que espera que você digite "Q" para sair do programa.

Em suma, você não pode graciosamente perto um programa a menos que você sabe de antemão como que espere programa a ser fechado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top