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

VB.NET Discussion :

Formulaire pour afficher la progression d'un processus externe. [Débutant]


Sujet :

VB.NET

  1. #1
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut Formulaire pour afficher la progression d'un processus externe.
    Bonsoir à tous,
    J'ai écris un programme pour convertir des vidéos avec ffmpeg.exe et j'ai enfin réussi à lire les messages de sorties de ce processus. Le but est d'afficher la progression sur un formulaire "frmProgress" spécialement dédié à cet usage.

    Problème :
    1- J'arrive à afficher les messages de sorties dans la fenêtre Debug de Visual Studio mais je n'ai rien qui s'affiche dans mon formulaire frmProgress qui contient un RichTextBox.
    2- Quelle est la méthode la plus propre pour passer les paramètres de progression à mon formulaire ?. Pour l'instant j'ecrits directement dans le RichTextBox pour faire des essais, par la suite je ferais une barre de progression + un label calculé à partir de la chaine de caractére retournée (voir ci-dessous).
    3- Le processus me retourne un string toute les secondes environ du style :
    "frame= 4169 fps= 81 q=39.0 size= 10513kB time=00:01:22.74 bitrate=1040.8kbits/s dup=2134 drop=0". Je pense faire une analyse cette chaine de caractère pour extraire la valeur 'frame' ou 'time' qui me servira d'indication de progression, la sortie se compose egalement d'autres chaines de caractères qui retourne par exemple quelques lignes d'erreurs (je vais devoir ignorer les chaines qui commence par Error:.....) est ce que c'est bien comme cela que l'on procède habituellement concernant ce principe d'extraction des infos de progression ?

    Le code exécuté dés que je lance la conversion depuis le formulaire principal :
    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
        Private Sub ShellExecute(ByVal ExeFile As String, CommandLine As String)
     
            Dim MonProcess As New Process
            AddHandler MonProcess.OutputDataReceived, AddressOf OutputDataReceived
            AddHandler MonProcess.ErrorDataReceived, AddressOf ErrortDataReceived
     
            MonProcess.StartInfo.FileName = ExeFile
            MonProcess.StartInfo.Arguments = CommandLine
            'MonProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
            MonProcess.StartInfo.CreateNoWindow = True        ' True
            MonProcess.StartInfo.UseShellExecute = False      ' False
            MonProcess.StartInfo.RedirectStandardOutput = True
            MonProcess.StartInfo.RedirectStandardInput = True
            MonProcess.StartInfo.RedirectStandardError = True
     
            MonProcess.Start()
     
            frmProgress.Show()
            MonProcess.BeginOutputReadLine()
            MonProcess.BeginErrorReadLine()
     
     
            MonProcess.WaitForExit()
            MonProcess.Close()
        End Sub
    Les évenements pour capturer la sortie du processus :
    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
     
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Try
                frmProgress.RichTextBox1.Text += e.Data.ToString
                frmProgress.RichTextBox1.Text += Environment.NewLine
                Debug.Print(e.Data.ToString)
            Catch ex As Exception
     
            End Try
     
        End Sub
     
        Private Sub ErrortDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Try
                frmProgress.RichTextBox1.Text += e.Data.ToString
                frmProgress.RichTextBox1.Text += Environment.NewLine
                Debug.Print(e.Data.ToString)
            Catch ex As Exception
     
            End Try
     
        End Sub
    Merci à tous pour votre aide.

  2. #2
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonsoir j'ai progressé sur les points 2 et 3 mais j'ai toujours le problème pour l'affichage sur mon formulaire de progression.
    Voici le message que j'obtiens sur la ligne : frmProgress1.CurrentValue += 1
    AccessibilityObject = {"Opération inter-threads non valide*: le contrôle 'RichTextBox1' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé."}

    Pour info j'ai modifié le code comme ceci et j'ai instancié frmProgress1 dans le module 'main' de démarrage de l'application :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Try
                frmProgress1.CurrentValue += 1   ' Incremente de 1 pour tester l'affichage
                Debug.Print(e.Data.ToString)
            Catch ex As Exception
     
            End Try
     
        End Sub
    Le Code du formulaire de progression :
    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
    Public Class frmProgress
        Private _CurrentValue As Integer
        Private _MaxValue As Integer
     
        Sub New()
            ' Cet appel est requis par le concepteur.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
        End Sub
        Sub New(ByVal CurrentValue As Integer, ByVal MaxValue As Integer)
     
            ' Cet appel est requis par le concepteur.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            CurrentValue = _CurrentValue
            MaxValue = _MaxValue
     
        End Sub
        Public Property CurrentValue As Integer
            Get
                Return _CurrentValue
            End Get
            Set(ByVal value As Integer)
                _CurrentValue = value
                Call DisplayProgress()
            End Set
        End Property
        Public Property MaxValue As Integer
            Get
                Return _MaxValue
            End Get
            Set(ByVal value As Integer)
                _MaxValue = value
                Call DisplayProgress()
            End Set
        End Property
     
        Private Sub frmProgress_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            Call DisplayProgress()
        End Sub
        Private Sub DisplayProgress()
            RichTextBox1.Text = CurrentValue.ToString & " / " & MaxValue.ToString
        End Sub
    End Class

  3. #3
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Points : 5 100
    Points
    5 100
    Par défaut
    Bonjour,

    Vous ne pouvez pas mettre à jours les contrôles graphiques depuis un autre thread.
    OutputDataReceived et ErrortDataReceived provenant de votre Process externe tournant dans un autre thread ne peut pas mettre directement à jour le RichtextBox. Il faut utiliser Invoke.

    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
        Delegate Sub EcritTexteCallback(ByVal Texte As String)
        Private Sub EcritTexte(ByVal texte As String)
            ' InvokeRequired compare l'ID du thread appelant à l'ID du thread qui a créé le controle. Si ces threads sont différent, renvoie true.
            If frmProgress1.RichTextBox1.InvokeRequired Then
                frmProgress1.RichTextBox1.Invoke(New EcritTexteCallback(AddressOf EcritTexte), texte)
            Else
                frmProgress1.RichTextBox1.Text += texte
                frmProgress.RichTextBox1.Text += Environment.NewLine
            End If
        End Sub
     
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
                EcritTexte(e.Data.ToString)
        End Sub
        Private Sub ErrortDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
                EcritTexte(e.Data.ToString)
        End
    Faites une recherche sur invoke vous aurez des exemples comme ceci.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  4. #4
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Merci beaucoup rv26t, je vais essayer ça.

  5. #5
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonjour à tous,
    N'etant pas très à l'aise avec Invoke j'ai tenté d'utiliser un backgroundWorker que je connais un peu mieux mais je me heurte à un nouveau problème. En effet je dois lancer plusieurs Processus, le 2éme devant se lancer après que le 1er soit terminé.
    Comment faire pour que les BackgroundWorker s’exécute les uns après les autres ?
    Peut-être que je fais un mauvais choix avec le BackGroundWorker dans ce cas précis et je devrais peut-être m'en tenir à la méthode Invoke proposé plus haut mais dans ce cas mon formulaire frmProgress1 comprenant plusieurs controles d'affichage (plusieurs Label et plusieurs progressbar pour affichage des progressions de la tache en cours et pour la progression de l'ensemble des taches), est ce que je devrais vérifier chaque contrôle un par un avant d’exécuter ma méthode frmProgress1.AfficheLaProgression ou est-ce que l'on peut controler le formulaire tout entier : frmProgress1.InvokeRequired ?


    Pour simplifier je fait quelques choses qui ressemble à ça :
    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
     
    For Tache = 1 to MaxTache
    frmProgress1.Show()
    If TotalPass=2 then
    ' Passe 1/2 :
               ProcessCommandeLine = "ffmpeg.exe Pass=1.......etc"
               BackgroundWorker1.RunWorkerAsync()
    ' Passe 2/2 :
               ProcessCommandeLine = "ffmpeg.exe Pass=2.......etc"
               BackgroundWorker1.RunWorkerAsync()
    else
    ' Passe 1
              ProcessCommandeLine = "ffmpeg.exe Pass=1.......etc"
              BackgroundWorker1.RunWorkerAsync()
     
    end if
    Next Tache
    Le code de l’événement ErrorDataReceived de l'objet MonProcess
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            ' Cet evenement s'execute dans le Thread qui a lancé le Processus
                ProcessOutputData = e.Data.ToString
                BackgroundWorker1.ReportProgress(0)  ' Notifie le BackgroundWorker pour affichage de la progression
                Debug.Print(e.Data.ToString)
        End Sub
    Le code de l’événement DoWork de l'objet BackGroundWorker1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Private Sub BackGroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
            ' Cet evenement s'execute dans le Thread qui a lancé le BackGroundWorker
            Call ShellExecute2("ffmpeg.exe", ProcessCommandeLine)
        End Sub
    Le Code de l'evenement ProgressChanged de l'objet BackGroundWorker1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       Private Sub BackGroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs)
            ' Cet evenement s'execute dans le Thread principale et permet l'affichage de la progression
                ' Affichage de la progression :
            frmProgress1.AfficheLaProgression(ProcessOutputData) ' La méthode du formulaire frmProgress1 pour afficher la progression.
     End Sub
    Pour merci beaucoup si vous pouvez m’éclairer ou me donner des conseils n’étant pas très à l'aise avec les Threads. Je suis très intéressé par vos suggestions.
    Christian.

  6. #6
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonsoir, j'ai abandonné la solution avec le BackGroundWorker, la méthode Invoke me semble plus approprié, j'ai malgré tout un problème sur la ligne suivante :
    frmProgress1.Invoke(MyDelegate)
    En pas à pas je perds la main dés que j’exécute cette ligne et je n'ai pas de message d'erreur. Ma seule possibilité est de stopper le programme depuis visual Studio.

    Le code principale :
    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
    For Tache = 1 to MaxTache
    frmProgress1.Show()
    If TotalPass=2 then
    ' Passe 1/2 :
               CommandeLine = "ffmpeg.exe Pass=1.......etc"
               Call ShellExecute2("ffmpeg.exe", CommandeLine)
    ' Passe 2/2 :
               CommandeLine = "ffmpeg.exe Pass=2.......etc"
               Call ShellExecute2("ffmpeg.exe", CommandeLine)
    else
    ' Passe 1
              CommandeLine = "ffmpeg.exe Pass=1.......etc"
              Call ShellExecute2("ffmpeg.exe", CommandeLine)
     
    end if
    Next Tache
    Le code de lancement du processus :
    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
        Private Sub ShellExecute2(ByVal ExeFile As String, CommandLine As String)
     
            Dim MonProcess As New Process
            AddHandler MonProcess.OutputDataReceived, AddressOf OutputDataReceived 
            AddHandler MonProcess.ErrorDataReceived, AddressOf ErrorDataReceived  
     
            MonProcess.StartInfo.FileName = ExeFile
            MonProcess.StartInfo.Arguments = CommandLine
            'MonProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
            MonProcess.StartInfo.CreateNoWindow = True        ' True
            MonProcess.StartInfo.UseShellExecute = False      ' False
            MonProcess.StartInfo.RedirectStandardOutput = True
            MonProcess.StartInfo.RedirectStandardInput = True
            MonProcess.StartInfo.RedirectStandardError = True
     
            frmProgress1.Show() 
            MonProcess.Start()
     
            MonProcess.BeginOutputReadLine() 
            MonProcess.BeginErrorReadLine()  
     
            MonProcess.WaitForExit()
            MonProcess.Close()
        End Sub
    L'evenement de l'objet MonProcess :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            ' Cet evenement s'execute dans le Thread qui a lancé le Processus
                ProcessOutputData = e.Data.ToString
                Invoquer(e.Data.ToString)
                Debug.Print(e.Data.ToString)
        End Sub
    La méthode Invoke et l'affichage de la progression.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        Delegate Sub DelegateAffichage(Texte As String)
        Private Sub Invoquer(ByVal texte As String)
            Dim MyDelegate As New DelegateAffichage(AddressOf Affiche)
            ' InvokeRequired compare l'ID du thread appelant à l'ID du thread qui a créé le controle. Si ces threads sont différent, renvoie true.
            If frmProgress1.RichTextBox1.InvokeRequired Then
                frmProgress1.Invoke(MyDelegate)
            Else
                Affiche(texte)
            End If
        End Sub
        Private Sub Affiche(Texte As String)
            frmProgress1.RichTextBox1.Text = texte
            frmProgress.RichTextBox1.Text += Environment.NewLine
        End Sub

  7. #7
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonsoir, J'ai enfin trouvé...
    En rajoutant un Thread cela fonctionne. J'ai pas compris pourquoi il faut passer par un Thread supplémentaire alors que le Process se lance déjà dans son propre Thread, si quelqu'un à une explication je suis preneur.

    Voici donc le code qui fonctionne enfin :
    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
    For Tache = 1 to MaxTache
    frmProgress1.Show()
    If TotalPass=2 then
    ' Passe 1/2 :
               CommandeLine = "ffmpeg.exe Pass=1.......etc"
               Call StartProcessInThread()
    ' Passe 2/2 :
               CommandeLine = "ffmpeg.exe Pass=2.......etc"
               Call StartProcessInThread()
    else
    ' Passe 1
              CommandeLine = "ffmpeg.exe Pass=1.......etc"
              Call StartProcessInThread()
     
    end if
    Next Tache
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       Private Sub StartProcessInThread()
            Dim t As Threading.Thread
     
            t = New Threading.Thread(AddressOf ShellExecute3)
            t.Start()
        End Sub
    Le reste du code ne change pas.......

  8. #8
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bon finalement ça ne fonctionne pas. . Le processus de la passe 1 ne se lance pas et l’exécution démarre directement par la passe 2 si j'utilise les Threads. Et si je n'utilise pas les Threads je ne n'arrive pas a afficher la progresssion. Je tourne en rond....
    Si quelqu'un a une idée ça m'interresse beaucoup sinon je vais devoir ma passer de l'affichage de la progression.

  9. #9
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Points : 5 100
    Points
    5 100
    Par défaut
    Déjà en passant le texte, non? (pour voir l'affichage)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    frmProgress1.RichTextBox1.Invoke(MyDelegate, Texte)
    après, je n'ai pas suivi tout le reste.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  10. #10
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonjour rv26t et merci de m'aider.
    Oui j'avais déja corrigé cette erreur en effet mais ça ne change rien sur le fait que je suis obligé de lancer le processus dans un nouveau Thread pour pouvoir afficher la sortie de ce processus. Du coup je ne peux plus exécuter les Processus les uns après les autres correctement.
    Pour mieux comprendre ce qu'il se passe j'ai rajouter cette ligne juste avant de démarrer le Process :
    Debug.Print(CommandLine)
    MonProcess.Start()

    C'est ainsi que je me suis appercu que j'ai 2 Process qui se lance avec une ligne de commande qui contient Pass=2. Je voudrais (dans le cas de l'encodage 2 passes) la Passe 1 se lance d'abord puis quand celle-ci est terminé je lance la passe 2.

    Merci beaucoup si quelqu'un peut m'aider.




    C'est à dire que dans ma procédure principale je passe comme argument une ligne de commande qui indique notamment le N° de la passe relatif à l'encodage (puisqu'il s'agit d'un processus d'encodage de vidéo).

  11. #11
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Points : 5 100
    Points
    5 100
    Par défaut
    Citation Envoyé par BasicZX81 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    For Tache = 1 to MaxTache
    frmProgress1.Show()
    If TotalPass=2 then
    ' Passe 1/2 :
               CommandeLine = "ffmpeg.exe Pass=1.......etc"
               Call StartProcessInThread()
    ' Passe 2/2 :
               CommandeLine = "ffmpeg.exe Pass=2.......etc"
               Call StartProcessInThread()
    else
    '...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       Private Sub StartProcessInThread()
            Dim t As Threading.Thread
     
            t = New Threading.Thread(AddressOf ShellExecute3)
            t.Start()
        End Sub
    Citation Envoyé par BasicZX81 Voir le message
    Le processus de la passe 1 ne se lance pas et l’exécution démarre directement par la passe 2 si j'utilise les Threads. Et si je n'utilise pas les Threads je ne n'arrive pas a afficher la progresssion.
    J'ai l'impression que tu mélanges, et rajoute des thread pour rien..
    Avec ton code du premier post et ta nouvelle procedure Invoquer cela aurait du fonctionner.
    MonProcess.Start() de la sub ShellExecute lancait ExeFile dans un autre thread. C'est pour cela qu'il fallait faire un invoke sur la réception des évènements OutputDataReceived.
    Après, je ne teste pas le fonctionnement non plus, donc je cerne peut être mal.
    ____________________________________________________

    Citation Envoyé par BasicZX81 Voir le message
    3- Le processus me retourne un string toute les secondes environ du style :
    "frame= 4169 fps= 81 q=39.0 size= 10513kB time=00:01:22.74 bitrate=1040.8kbits/s dup=2134 drop=0". Je pense faire une analyse cette chaine de caractère pour extraire la valeur 'frame' ou 'time' qui me servira d'indication de progression, la sortie se compose egalement d'autres chaines de caractères qui retourne par exemple quelques lignes d'erreurs
    Citation Envoyé par BasicZX81 Voir le message
    Les évenements pour capturer la sortie du processus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
    '...
    Citation Envoyé par BasicZX81 Voir le message
    Je voudrais (dans le cas de l'encodage 2 passes) la Passe 1 se lance d'abord puis quand celle-ci est terminé je lance la passe 2.
    N'existe t-il pas une info ou un élément dans le string retourné (voire un autre événement) qui indique que la fin de traitement de a eu lieu ? (et dans ce cas lancer le deuxième)
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  12. #12
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    J'ai l'impression que tu mélanges, et rajoute des thread pour rien..
    Avec ton code du premier post et ta nouvelle procedure Invoquer cela aurait du fonctionner.
    MonProcess.Start() de la sub ShellExecute lancait ExeFile dans un autre thread. C'est pour cela qu'il fallait faire un invoke sur la réception des évènements OutputDataReceived.
    Après, je ne teste pas le fonctionnement non plus, donc je cerne peut être mal.
    Je suis tout à fait d'accord. Je me dit que je ne devrais pas avoir besoin de Threads supplémentaires mais il n'y a que comme ça que j'ai pu obtenir un affichage
    Concernant la fin du traitement il n'y a rien qui indique clairement que le Processus est terminé dans le message de sortie.

    Pour info et pour tester j'ai également modifié cette ligne de code qui me paressais suspect :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim MyDelegate As New DelegateAffichage(AddressOf Invoquer)
    comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim MyDelegate As New DelegateAffichage(AddressOf Affiche)
    mais ça ne change le rien, le programme se comporte de façon identique.

    Je continue mes recherches en essayant de ne pas utiliser de Threads supplémentaire mais j'avoue que je ne comprends pas.

  13. #13
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Points : 5 100
    Points
    5 100
    Par défaut
    Citation Envoyé par BasicZX81 Voir le message
    Je voudrais (dans le cas de l'encodage 2 passes) la Passe 1 se lance d'abord puis quand celle-ci est terminé je lance la passe 2.
    Sinon utiliser un timer qui scrute si le thread de la première passe est actif, quand il est fini lancer la deuxième passe.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  14. #14
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Merci beaucoup rv26t pour l'astuce avec le timer. Je m'en servirais si vraiment je ne vois pas d'autres solutions. Avant je vais faire d'autres essais avec d'autres Processus déjà présent dans mon programme. On ne sait jamais.

  15. #15
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonsoir, j'ai crée un nouveau projet spécialement dans le but d'isoler le problème et j'ai des informations inintéressantes, seulement ça devient aussi très compliqué pour moi.

    Voici mes essais :
    J'ai supprimé cette ligne qui bloqué l'affichage de la sortie du Processus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MonProcess.WaitForExit()
    Donc maintenant j'ai bien mon affichage en utilisant la méthode Invoke et sans utiliser un Thread supplémentaire.
    Problème : sans la méthode WaitForExit les processus s’exécute tous en même temps.

    J'ai donc cherché un moyen de contrôler la fin du Processus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    AddHandler MonProcess.Exited, AddressOf ProcessExit
       Private Sub ProcessExit(sender As Object, e As System.EventArgs)
            eventHandled = True
            MessageBox.Show("Terminé")
            Debug.Print("Process terminé")
        End Sub
    Mais l’événement Exited ne se déclenche jamais sauf si j'ajoute ce bout de code ...
    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
     
    ......
            MonProcess.start()
     
           ' Wait for Exited event, but not more than 30 seconds.
            Const SLEEP_AMOUNT As Integer = 100
            Do While Not eventHandled
                elapsedTime += SLEEP_AMOUNT
                If elapsedTime > 30000 Then
                    Exit Do
                End If
                Thread.Sleep(SLEEP_AMOUNT)
            Loop
     
            MonProcess.Close()
    ...qui mets le Thread principal en pause (pas plus de 30 secondes) en attendant l’événement Exited. Hors ce n'est pas du tout adapté à mon programme puisque les processus peuvent durer pendant des heures et que si je mets en pause le Thread Principale en attendant la fin du processus je mets aussi en pose l'affichage puisque c'est aussi le Thread qui gère l'affichage.

    En clair si je bloque le thread principale soit par la méthode WaitForExit soit par la méthode Thread.Sleep() je n'est pas d'affichage.
    Y a t'il un moyen de récupérer l’événement Exited sans être obligé de mettre le Thread principal en pause ?

  16. #16
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    J'ai trouvé....
    C'était tout bête. Puisque WaitForExit bloque le Thread Principal et que j'ai besoin de cette méthode pour ne pas que les Processus s'execute tous en même temps. Il suffit de lancer L'ENSEMBLE des Processus dans un backGroundWorker, ainsi, SEUL le Thread du backGroundWorker est bloqué tant qu'un Processus n'est pas terminé. Le Thread principal est donc libre pour l'affichage.
    L'erreur que je faisais était de lancer plusieurs BackgroundWorker (un pour chaque Processus), hors il faut lancer TOUS les processus dans un seul BackgroundWorker.

    Comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Private Sub BackGroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
            Call ExecuteAllProcess
    End Sub
    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
     
    Private sub ExecuteAllProcess
    For Tache = 1 to MaxTache
    If TotalPass=2 then
    ' Passe 1/2 :
               CommandeLine = "ffmpeg.exe Pass=1.......etc"
               Call ShellExecute2("ffmpeg.exe", CommandeLine)
    ' Passe 2/2 :
               CommandeLine = "ffmpeg.exe Pass=2.......etc"
               Call ShellExecute2("ffmpeg.exe", CommandeLine)
    else
    ' Passe 1
              CommandeLine = "ffmpeg.exe Pass=1.......etc"
              Call ShellExecute2("ffmpeg.exe", CommandeLine)
     
    end if
    Next Tache
    End Sub
    J'ai donc mes Processus qui s’exécute les uns après les autres avec un affichage en temps réel de la sortie des Processus.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2007] Formulaire pour afficher un enregistrement d'un Etat
    Par magic57 dans le forum IHM
    Réponses: 2
    Dernier message: 26/05/2011, 10h48
  2. Probleme formulaire pour afficher donnée
    Par nuFox dans le forum IHM
    Réponses: 1
    Dernier message: 04/12/2008, 16h02
  3. Pb bouton d'options pour afficher ou non un formulaire
    Par Patrick78 dans le forum Access
    Réponses: 11
    Dernier message: 07/09/2006, 16h48
  4. [MySQL] Un formulaire pour afficher et modifier un enregistrement
    Par Atchoum_002 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 26/09/2005, 14h13
  5. Problème pour afficher un contrôle dans un formulaire
    Par JahRastafari dans le forum IHM
    Réponses: 5
    Dernier message: 16/06/2005, 10h15

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