IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

CreateProcess / Redirection -> Err


Sujet :

Windows

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2007
    Messages : 3
    Par défaut CreateProcess / Redirection -> Err
    Bonjour,

    Voila quelques jours que je cherche la cause du problème suivant :
    Je travail avec Delphi sous Windows 2000
    J'effectue un appel a CreateProcess() en redirigeant les e/s selon le code ci dessous. Une fois le processus fils terminé je souhaite exploiter le fichier généré par la redirection de stdout.
    Je précise que cette fonction est appelée par plusieurs thread et qu'il y a donc exécution simultanée de plusieurs process identiques.
    Le problème est que je récupère une erreur lors de l'ouverture du fichier résultat.
    D'après cette erreur, le fichier serait "utilisé par un autre processus."
    Il est bien évident que chaque thread lance le process avec des noms de fichiers différent pour stdout, stdin et stderr et que par consequent chaque fichier de sortie a un nom unique.
    Se pourrait il que l'application lancée avec CreateProcess ne soit pas complétement terminée malgré le WaitForSingleObjet ?

    Toute idée ou début de piste est la bienvenue.
    Forte récompense


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    function TProcessControl.StartProcess() : Integer;
    var
      si      : StartupInfo;
      pi      : Process_Information;
      sattr   : TSecurityAttributes;
    begin
      fIsLoaded:=false;
      result:=0;
      ZeroMemory(@sattr,sizeof(sattr));
      sattr.nLength:=sizeof(TSecurityAttributes);
      sattr.lpSecurityDescriptor:=Nil;
      sattr.bInheritHandle:=true;
    
      fhdlStdOutWr:=CreateFile(PChar(fOutputFile),GENERIC_WRITE or GENERIC_READ,FILE_SHARE_READ,@sattr,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL+FILE_FLAG_NO_BUFFERING,0);
      if fhdlStdOutWrTmp = INVALID_HANDLE_VALUE
        then raise EControllerException.Create('stdout file: '+SysErrorMessage(GetLastError()));
    
      fhdlStdInRd:=CreateFile(PChar(fInputFile),GENERIC_READ,FILE_SHARE_READ,@sattr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
      if fhdlStdInRd = INVALID_HANDLE_VALUE
        then raise EControllerException.Create('stdin file: '+SysErrorMessage(GetLastError()));
    
      fhdlStdErrWr:=CreateFile(PChar(fErrFile),GENERIC_READ,FILE_SHARE_READ,@sattr,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
      if fhdlStdErrWr = INVALID_HANDLE_VALUE
        then raise EControllerException.Create('stderr file: '+SysErrorMessage(GetLastError()));
    
      fillChar(si,sizeOf(StartupInfo),0);
      si.cb:=sizeOf(StartupInfo);
      si.hStdError:=fhdlStdErrWr;
      si.hStdInput:=fhdlStdInRd;
      si.hStdOutput:=fhdlStdOutWr;
      si.dwFlags:=STARTF_USESHOWWINDOW or	STARTF_USESTDHANDLES;
      si.wShowWindow:=SW_SHOWMINNOACTIVE;
      si.lpTitle:=PChar(fcmdLine);
    
      if CreateProcess(nil,PCHar(fcmdLine),Nil,Nil,true,CREATE_NEW_CONSOLE ,Nil,Nil,si,pi)
      then begin
        CloseHandle(pi.hThread);
        WaitForSingleObject(pi.hProcess,INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(fHdlStdOutWr);
        CloseHandle(fHdlStdOutRd);
        CloseHandle(fHdlStdInWr);
        CloseHandle(fHdlStdInRd);
        CloseHandle(fHdlStdErrWr);
        CloseHandle(fHdlStdErrRd);
        With TStringList.Create() do
        Try
           LoadFromFile();  // CA PLANTE ICI !!! 
        Finally
        end
      end
    end;

  2. #2
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Ce code-ci marche très bien, même s'il ne fait "que" capturer la sortie d'un programme (et ne permet pas de piloter les entrées dudit programme). Déjà testé de nombreuses fois :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    function Win32ExecuteAndCapture(const ProgName: String   ;
      const Parameters: String; const Folder: String   ; var Output: TStrings;
      const OnNewLine: TNotifyEvent): Cardinal;
    Const
         LF = #10 ;
         CR = #13 ;
    Var
       StartupInfo        : TStartupInfo        ;
       ProcessInfo        : TProcessInformation ;
       SecurityAttributes : TSecurityAttributes ;
       TempHandle,
       WriteHandle,
       ReadHandle         : THandle ;
       ReadBuf            : Array[0..256] Of Char;
       BytesRead          : Cardinal;
       LineBuf            : Array[0..256] Of Char;
       LineBufPtr         : Integer;
       Newline            : Boolean;
       I                  : Integer;
    
       Procedure OutputLine;
       Begin
            LineBuf[LineBufPtr]:=#0;
            With Output Do
                 If Newline Then Add(LineBuf)
                            Else Strings[Count-1]:=LineBuf;
            Newline:=False;
            LineBufPtr:=0;
            If Assigned(OnNewLine) Then
               OnNewLine(Output);
       End;
    
    begin
         FillChar(StartupInfo,SizeOf(StartupInfo), 0);
         FillChar(ReadBuf, SizeOf(ReadBuf), 0);
         FillChar(SecurityAttributes, SizeOf(SecurityAttributes), 0);
         LineBufPtr:=0;
         Newline:=True;
         If Not Assigned(Output) Then
            Output:=THashedStringList.Create;
         With SecurityAttributes Do
              Begin
              nLength:=SizeOf(SecurityAttributes);
              bInheritHandle:=True;
              End;
         If Not CreatePipe(ReadHandle, WriteHandle, @SecurityAttributes, 0) Then
            RaiseLastOSError;
         Try
            If Win32Platform=VER_PLATFORM_WIN32_NT Then Begin
                                                        If Not SetHandleInformation(ReadHandle, HANDLE_FLAG_INHERIT, 0) Then
                                                           RaiseLastOSError ;
                                                        End
                                                   Else Begin
                                                        If Not DuplicateHandle(GetCurrentProcess, ReadHandle, GetCurrentProcess, @TempHandle, 0, True, DUPLICATE_SAME_ACCESS) Then
                                                           RaiseLastOSError;
                                                        CloseHandle(ReadHandle);
                                                        ReadHandle:=TempHandle;
                                                        End;
            With StartupInfo Do
                 Begin
                 cb:=SizeOf(StartupInfo);
                 dwFlags:=STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
                 wShowWindow:=SW_HIDE;
                 hStdOutput:=WriteHandle;
                 End;
            If Not CreateProcess( Nil, PChar(ProgName+' '+Parameters), Nil, Nil, True, NORMAL_PRIORITY_CLASS Or CREATE_NO_WINDOW, Nil, PChar(Folder), StartupInfo, ProcessInfo) Then
               RaiseLastOSError;
    
            CloseHandle(ProcessInfo.hThread);
            CloseHandle(WriteHandle);
            Try
               While ReadFile(ReadHandle, ReadBuf, SizeOf(ReadBuf), BytesRead, Nil) Do
                     For I:=0 to BytesRead-1 Do
                         If (ReadBuf[I]=LF) Then Newline:= True
                                            Else If (ReadBuf[I]=CR) Then OutputLine
                                                                    Else Begin
                                                                         LineBuf[LineBufPtr]:=ReadBuf[I];
                                                                         Inc(LineBufPtr);
                                                                         If LineBufPtr>=(SizeOf(LineBuf)-1) Then
                                                                            Begin
                                                                            Newline:=True;
                                                                            OutputLine;
                                                                            End ;
                                                                         End ;
               WaitForSingleObject(ProcessInfo.hProcess, TerminationWaitTime);
               If Not GetExitCodeProcess(ProcessInfo.hProcess, Result) Then
                  RaiseLastOSError ;
               OutputLine;
            Finally
                   CloseHandle(ProcessInfo.hProcess)
            End;
         Finally
                CloseHandle(ReadHandle);
         End;
    end;
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #3
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    (Problème de post, désolé du double message)

    Remarques bien comment je crée le processus et redirige les sorties. Après, si tu n'as pas besoin de te connecter aux entrées du programme, mon code est directement utilisable.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2007
    Messages : 3
    Par défaut Precision sur le DuplicateHandle
    Re-Bonjour,

    Merci Lak, pour ta/tes réponse(s).
    Cela semble corriger le problème. Cependant ,je me demande pourquoi la duplication du handle est nécessaire ?

    N'est il pas possible de communiquer a CreateProcess() via StartupInfo des handles obtenus par CreateFile() directement sur des fichiers ?

    Merci de m'apporter ces précisions .

  5. #5
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Attention, regarde bien le test avant : la duplication de handle n'est faite que si l'on n'est PAS sur une plate-forme NT... Donc, pour W95/98 !
    Sur NT (NT4, 2k, XP, ...), c'est SetHandleInformation qui sera utilisé pour propager les droits.

    Pour le reste, il est en général peu utile de rediriger vers un fichier : en faisant cela, tu ne peux RIEN savoir du processus engendré tant qu'il n'a pas totalement terminé son travail, ce qui est gênant. Si c'est ce dont tu as besoin, autant l'appeler via "cmd.exe" et rediriger directement via un "> monfichier.txt", c'est souvent plus rapide et pratique.

    Et pour "fliquer" le processus, un pipe est nécessaire, donc inutile de passer un handle de fichier disque existant... Surtout que ce fichier sera à priori créé avec un accès exclusif par le processus père, donc inutilisable par le processus fils !
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

Discussions similaires

  1. [Delphi 6] CreateProcess et redirection I/O
    Par ludovic tambour dans le forum Delphi
    Réponses: 4
    Dernier message: 31/01/2007, 21h49
  2. [Kylix] Erreur "File not Found : Windows.dcu"
    Par derrick23_2003 dans le forum EDI
    Réponses: 4
    Dernier message: 27/12/2005, 11h18
  3. [VB6] probleme de redirection d'une commande DOS
    Par WriteLN dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 10/06/2003, 09h36
  4. CreateProcess + paramètres passé
    Par obione dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 20/03/2003, 17h25
  5. [reseaux] redirection de flux
    Par Olive1808 dans le forum Programmation et administration système
    Réponses: 2
    Dernier message: 12/08/2002, 09h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo