Creation de processus [Résolu]

Signaler
Messages postés
30
Date d'inscription
jeudi 24 juillet 2008
Statut
Membre
Dernière intervention
13 novembre 2012
-
Messages postés
30
Date d'inscription
jeudi 24 juillet 2008
Statut
Membre
Dernière intervention
13 novembre 2012
-
Bonjour,

j'ai créé un objet permettant de lancer une application. Celui ci créé le process puis va lire son état à chaque top d'un timer. Des événements sont associés:
-A chaque top du timer, quand l'appli est toujours active.
-A la fin de l'execution, si tout s'est bien déroulé.
Il est également possible de passer en paramètre un Tmemo et/ou un nom de fichier pour la redirection stdout.

Le problème est le suivant:
1) Je créé mon objet
2)Je l'utilise une premiere fois pour une premiere commande
--> tout se passe bien
3)Aprés la fin de la 1ere commande, je l'utilise pour une 2 eme commande
-->Le process est bien créé
-->Les processId et Handle sont bien ceux que je peux retrouver dans le gestionnaire de tache ou Process Explorer
-->Mais quand au premier top de mon timer, je regarde l'etat du process grace a GetExitCodeProcess(hProcess, ExitCode), la fonction echoue et me retourne l'erreur idientifiant invalid... alors que le handle existe bien.

Quelqu'un aurait-il une idée?
J'ai tout essayé, j'ai tout retourné dans tous les sens mais la j'avoue que je suis largué.

Voici mon code:

unit Unite_Process_Launcher;
 
interface
Uses Windows,StdCtrls,ExtCtrls, SysUtils, Forms, Tlhelp32, dialogs;
 
Type
  TProcedure    = procedure of object;
 
  TProcLauncher = class
  private
    { Déclarations privées }
    FOutMemo    : TMemo;
    FOutFileName: String;
    FOnExit     : TProcedure;
    FOnTimer    : TProcedure;
 
    Timer              : TTimer;
    ReadPipe,WritePipe : THandle;
    Proc_Info          : TProcessInformation;
 
    procedure Timer_OnTimer(Sender: TObject);
    procedure writeLog;
    procedure killAllProcessesFrom(procId: DWORD);
    function  Is_busy: boolean;
  public
    { Déclarations publiques }
    Constructor Create;
    Function    Execute(Cmd             : String;
                        params          : String;
                        title           : String;
                        CheckInterval   : Cardinal;
                        OnTimer         : TProcedure;
                        OnExit          : TProcedure;
                        Outmemo     : TMemo;
                        OutFileName : String): Boolean;
 
    property    Busy: boolean read is_Busy;
  end;
 
 
implementation
 
{ TProcLauncher }
 
{-----------------------------------------------------------------------
 -----------------------------------------------------------------------}
constructor TProcLauncher.Create;
begin
  Timer := TTimer.create(nil);
  Timer.enabled:=false;
  Timer.OnTimer:=Timer_OnTimer;
end;
 
{-----------------------------------------------------------------------
 Execute une commande
 Cmd           : La Commande
 Params        : Les parametres
 Title         : Le titre
 CheckInterval : Interval de temps entre chaque verification d'etat
 OnTimer       : Evenement sur chaque interval (Nil si inutile)
 OnExit        : Evenement à la fin de l'execution du process (Nil si inutile)
 Outmemo       : Redirection en sortie du prcess vers un TMemo (Nil si inutile)
 OutFileName   : Redirection en sortie du prcess vers un fichier log ('' si inutile)
 -----------------------------------------------------------------------}
Function TProcLauncher.Execute(Cmd, params,title: String; CheckInterval: Cardinal;
  OnTimer,OnExit: Tprocedure; Outmemo: TMemo; OutFileName: String): Boolean;
var
 Security           : TSecurityAttributes;
 startinfo          : TStartUpInfo;
begin
  result:=false;
  if busy then exit; // un process est deja en cours
  {Initialisation}
  if checkinterval>0 then Timer.Interval:=CheckInterval
  else Timer.Interval:=3000;
  Foutmemo      :=OutMemo;
  FoutFilename  :=OutFileName;
  FOnExit       :=OnExit;
  FOnTimer      :=Ontimer;
 
  With Security do begin
    nlength := SizeOf(TSecurityAttributes) ;
    binherithandle := true;
    lpsecuritydescriptor := nil;
  end;
 
  if Createpipe (ReadPipe, WritePipe,@Security, 0) then
  begin
   FillChar(proc_info, sizeof(TProcessInformation), #0);
   FillChar(startinfo, sizeof(TStartupInfo), #0);
   startinfo.cb := sizeof(TStartupInfo);
   startinfo.hStdOutput := WritePipe;
   startinfo.hStdInput := ReadPipe;
   startinfo.&dwFlags := STARTF_USESTDHANDLES+StartF_USESHOWWINDOW;
   startinfo.wShowWindow := SW_HIDE;
   startinfo.lpTitle:= PANSICHAR(Title);
 
   if CreateProcess(nil,PANSICHAR(cmd+params),@Security,@Security,
                    true,CREATE_DEFAULT_ERROR_MODE
                    + NORMAL_PRIORITY_CLASS, nil, nil,
                    startinfo,proc_info) then
   Begin
     Timer.enabled:=true;  //Timer attend la fin de process
     result:=true;
   End;
 End;
 
 if Result=false then
 Begin
   CloseHandle(proc_info.hProcess);
   CloseHandle(proc_info.hThread) ;
   CloseHandle(ReadPipe) ;
   CloseHandle(WritePipe);
 End;
end;
 
function TProcLauncher.Is_busy: boolean;
begin
  result:=timer.enabled;
end;
 
 
{-----------------------------------------------------------------------
 A chaque top du timer, on met à jour le log et on regarde l'etat du process
 -----------------------------------------------------------------------}
procedure TProcLauncher.Timer_OnTimer(Sender: TObject);
var
 ExitCode: LongWord;
begin
  Timer.Enabled := False;
  writeLog;
  {Action suivant etat}
  Application.ProcessMessages;
  if GetExitCodeProcess(proc_info.hProcess, ExitCode) then
  Begin
    if ExitCode = STILL_ACTIVE
    then
    begin
      if assigned(FOnTimer) then FOntimer;
      Timer.Enabled := True
    end
    else
    begin
      if assigned(FOnExit) then FOnExit;
      CloseHandle(proc_info.hProcess);
      CloseHandle(proc_info.hThread) ;
      CloseHandle(ReadPipe) ;
      CloseHandle(WritePipe) ;
    end;
  end
  else
  begin
      ShowMessage(SysErrorMessage(GetLastError));
 
      if assigned(FOnExit) then FOnExit;
      CloseHandle(proc_info.hProcess);
      CloseHandle(proc_info.hThread) ;
      CloseHandle(ReadPipe) ;
      CloseHandle(WritePipe) ;
  end;
end;
 
{-----------------------------------------------------------------------
 Redirection de ReadPipe vers le Memo log et/ou le fichier log
 -----------------------------------------------------------------------}
procedure TProcLauncher.writeLog;
const
  ReadBuffer = 2400;
var
  BytesRead : DWord;
  Buffer    : Pchar;
  OutFile   : TextFile;
begin
   Buffer := AllocMem(ReadBuffer + 1) ;
   Repeat
    BytesRead := 0;
    ReadFile(ReadPipe,Buffer[0],ReadBuffer,BytesRead,nil) ;
    Buffer[BytesRead]:= #0;
    OemToAnsi(Buffer,Buffer) ;
    {Memo Log}
    If FOutMemo<>Nil then FOutMemo.Text := FOutMemo.text + String(Buffer)  ;
    {Fichier Log}
    If FOutFileName<>'' then
    Begin
     try
       assignfile(outFile,FoutFilename);
       If FileExists(FOutFileName) then append(OutFile)
       else rewrite(OutFile);
       write(OutFile,String(Buffer));
       closeFile(OutFile);
     Except
       FOutFileName:='';
     end;
    End;
   until (BytesRead < ReadBuffer) ;
  FreeMem(Buffer);
end;
               
end.
 

3 réponses

Messages postés
30
Date d'inscription
jeudi 24 juillet 2008
Statut
Membre
Dernière intervention
13 novembre 2012

Problème résolu.

J'appelle mon deuxième processus dans le FOnExit du premier.
Il faut donc que la libération des Handles se fasse avant le FOnExit.
Sinon les handles libérés sont ceux du deuxième process, donc au premier top du timer, les Handles n'existent plus.

C'était juste ça!

Voici le nouveau code pour la procedure OnTimer

procedure TProcLauncher.Timer_OnTimer(Sender: TObject);
var
 ExitCode: LongWord;
begin
  Timer.Enabled := False;
  writeLog;
  {Action suivant etat}
  if GetExitCodeProcess(proc_info.hProcess, ExitCode) then
  Begin
    if ExitCode = STILL_ACTIVE
    then
    begin
      if assigned(FOnTimer) then FOntimer;
      Timer.Enabled := True
    end
    else
    begin
      FreeHandles;
      if assigned(FOnExit) then FOnExit;

    end;
  end
  else
  begin
      If getlasterror>0 then
      ShowMessage(SysErrorMessage(GetLastError));
      FreeHandles;
      if assigned(FOnExit) then FOnExit;

  end;
end;
Messages postés
3793
Date d'inscription
samedi 22 décembre 2007
Statut
Membre
Dernière intervention
3 juin 2016
8
Ben ... je sais pas mais ... à chaque top du timer, tu libères tes handles :

CloseHandle(proc_info.hProcess);

CloseHandle(proc_info.hThread) ;

CloseHandle(ReadPipe) ;

CloseHandle(WritePipe) ;


Tu es sûr que tu les recrées après ?

Cordialement, Bacterius !
Messages postés
30
Date d'inscription
jeudi 24 juillet 2008
Statut
Membre
Dernière intervention
13 novembre 2012

Tout d'abord merci pour la réponse.

A chaque top du timer, si le process est terminé ou si il n'existe plus, je libère les handles.

A chaque execution ReadPipe et WritePipe sont recréés via Createpipe; proc_info.hProcess et proc_info.hThread sont recréés via CreateProcess

Cordialement