Delphi - Fermeture gracieuse du processus créé dans Service. (en utilisant tprocess / createProcess)

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

Question

J'ai un service Windows écrit en Delphi qui exécute plusieurs programmes.

À l’arrêt du service, je souhaite également fermer ces programmes. Lorsque le service a été écrit à l'origine, cela fonctionnait bien, mais je pense avoir mis à jour le composant tProcess et maintenant: les programmes subordonnés ne sont pas fermés.

in tProcess - Voici le code qui lance les nouveaux processus.

  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;

Chacun des exécutables appelés par ceci est un programme d’interface graphique Windows (avec un bouton de fermeture en haut).

Lorsque j'arrête le service, je souhaite également arrêter (et non supprimer) les programmes que j'ai démarrés via la procédure createProcess.

Comment feriez-vous cela?

Était-ce utile?

La solution

Vous souhaitez énumérer les fenêtres ouvertes qui correspondent à votre ProcessId lancé et demander à ces fenêtres de se fermer. Voici un exemple de code pour cela:

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;

Ensuite, vous voudrez utiliser ceci dans votre code lorsque vous voulez arrêter les applications lancées:

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;

Autres conseils

Je voudrais utiliser le composant TJvCreateProcess de JVCL , qui traite de tous les processus. fonctionnalités connexes de win32 de manière élégante. Cette réponse provient de Dont-touch-winapi-si le département vraiment requis: -)

Le seul moyen générique d'arrêter un processus consiste à utiliser TerminateProcess . Mais c'est aussi loin d'être gracieux que vous pouvez obtenir. Pour clôturer gracieusement un processus, vous devez lui indiquer que vous souhaitez qu'il s'arrête, puis espérer qu'il obéit. Il n’ya aucun moyen de le faire en général, cependant.

Pour un programme graphique, le moyen habituel de lui indiquer que vous souhaitez qu'il cesse de fonctionner consiste à fermer sa fenêtre principale. Il n'y a pas d'idée formelle de " fenêtre principale, " bien que. Un programme peut avoir zéro fenêtre ou plus, et il n’ya aucun moyen de savoir en externe celle que vous êtes censé fermer pour que le programme cesse de fonctionner.

Vous pouvez utiliser EnumWindows pour parcourir toutes les fenêtres et sélectionnez ceux qui appartiennent à votre processus. (Ce sont ceux pour lesquels GetWindowThreadProcessId donne le même processus Identifiant que CreateProcess vous a donné.)

Fermer une fenêtre peut ne pas suffire. Le programme peut afficher une boîte de dialogue (vous demandant de confirmer ou de sauvegarder les modifications, etc.). Vous devez savoir à l'avance comment fermer cette boîte de dialogue.

Les programmes non-graphiques peuvent avoir des problèmes similaires. Il suffirait peut-être de simuler une frappe Ctrl + C. Cependant, il est possible que cette frappe soit saisie et gérée différemment. Un système de menus peut vous demander de taper " Q " quitter le programme.

En résumé, vous ne pouvez pas fermer un programme correctement, à moins de savoir à l'avance comment ce programme est censé être fermé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top