Delphi - graciosamente Encerramento Criado Processo no Serviço. (Usando TProcess / CREATEPROCESS)
-
06-07-2019 - |
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?
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.
programasNã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.