Delphi: chiusura con grazia del processo creato in servizio. (usando tprocess / createProcess)
-
06-07-2019 - |
Domanda
Ho un servizio Windows scritto in Delphi che esegue una serie di programmi.
All'arresto del servizio, voglio anche chiudere questi programmi. Quando il servizio è stato originariamente scritto, funzionava bene, ma penso di aver aggiornato il componente tProcess e ora - I programmi subordinati non vengono chiusi.
in tProcess: ecco il codice che avvia i nuovi processi.
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;
Ognuno degli eseguibili chiamati da questo sono i programmi di GUI di Windows (con un pulsante di chiusura in alto).
Quando interrompo il servizio, voglio anche arrestare (non uccidere) i programmi che ho avviato tramite la procedura createProcess.
Come lo faresti?
Soluzione
Vuoi enumerare le finestre aperte che corrispondono al tuo ProcessId avviato e dire a quelle finestre di chiudersi. Ecco un esempio di codice per questo:
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;
Quindi vorrai utilizzarlo nel tuo codice quando vuoi chiudere le applicazioni avviate:
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;
Altri suggerimenti
Utilizzerei il componente TJvCreateProcess di JVCL che avvolge qualsiasi processo funzionalità correlate di win32 in modo elegante. Questa risposta arriva dal dipartimento Dont-touch-winapi-a meno che non sia veramente richiesto :-)
L'unico modo generico per interrompere un processo è utilizzare TerminateProcess . Ma è tutt'altro che grazioso che puoi ottenere. Per chiudere con grazia un processo, devi dire al processo che vorresti che si fermasse, e quindi sperare che obbedisca. Non c'è modo di farlo in generale, tuttavia.
Per un programma GUI, il solito modo per dirgli che vuoi che si fermi è chiudere la sua finestra principale. Non c'è idea formale di " finestra principale " anche se. Un programma può avere zero o più finestre e non c'è modo di sapere esternamente quale si dovrebbe chiudere per far smettere di funzionare.
È possibile utilizzare EnumWindows per scorrere tutte le finestre e seleziona quelli che appartengono al tuo processo. (Sarebbero quelli per i quali GetWindowThreadProcessId fornisce lo stesso processo ID che ti ha creato CreateProcess.)
La chiusura di una finestra potrebbe non essere sufficiente. Il programma potrebbe visualizzare una finestra di dialogo (richiesta di conferma o richiesta di salvataggio delle modifiche, ecc.). Dovresti sapere in anticipo come chiudere quella finestra di dialogo.
I programmi non GUI possono avere problemi simili. Potrebbe essere sufficiente simulare una sequenza di tasti Ctrl + C. Tuttavia, potrebbe catturare e gestire la sequenza di tasti in modo diverso. Potrebbe avere un sistema di menu che si aspetta che tu digiti " Q " per uscire dal programma.
In breve, non è possibile chiudere con garbo un programma a meno che non si sappia in anticipo come quel programma prevede di essere chiuso.