Delphi: chiusura con grazia del processo creato in servizio. (usando tprocess / createProcess)

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

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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top