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 :

Besoin d'aide pour restructurer mon code autour de l'objet Process [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 Besoin d'aide pour restructurer mon code autour de l'objet Process
    Bonsoir a tous,
    Je sollicite de moins en moins le forum (grâce vous) mais cette fois-ci je suis a nouveau bloqué sur un problème un peu épineux pour moi.
    J'ai un code qui fonctionne mais qui m’empêche aujourd'hui d'implémenter correctement l'annulation des Process et je souhaite également supprimer les BackGroundWorker car normalement je ne devrais pas en avoir besoin avec des objets Process.
    Mon problème se situe plus au niveau de l’écriture de la structure du code, je ne sais pas comment m'y prendre en évitant de tout casser et compte tenu des différents points bloquant (listés plus bas) que je pourrais rencontrer. Votre suggestions me seront vraiment d'une aide très précieuse.

    Pour commencer voici mon code simplifié au maximum : (j'ai pris l'exemple de 2 processus d'encodage vidéo avec ffmpeg qui correspondent a un encodage en 2 passes).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Private Sub BackGroundWorkerFFMPEG_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
            ConvertWithFFmpeg(TSFile)
    End Sub
    Private Sub ConvertWithFFmpeg(InputFilename As String)
    .... ' Ceci est un grand bloc de code ou je prépare les lignes de commandes entre autres.
    Dim FFMPEG_EXE as string = "ffmpeg.exe"
    Dim CommandeLine as string = "Ma ligne de commande1"
    Call ShellExecuteFFMPEG(FFMPEG_EXE, CommandeLine)
    ....
    CommandeLine = "Ma ligne de commande2"
    Call ShellExecuteFFMPEG(FFMPEG_EXE, CommandeLine)
    ....
    End Sub
    La procédure d’exécution des 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
    25
    26
    27
    28
    29
    30
    31
    32
    Private Sub ShellExecuteFFMPEG(ByVal ExeFile As String, CommandLine As String)
            Dim MonProcess As New Process
            AddHandler MonProcess.OutputDataReceived, AddressOf OutputDataReceived  
            AddHandler MonProcess.ErrorDataReceived, AddressOf ErrorDataReceived  
            AddHandler MonProcess.Exited, AddressOf ProcessExit
            MonProcess.EnableRaisingEvents = True
            MonProcess.StartInfo.FileName = ExeFile
            MonProcess.StartInfo.Arguments = CommandLine
            MonProcess.StartInfo.CreateNoWindow = True  
            MonProcess.StartInfo.UseShellExecute = False  
            MonProcess.StartInfo.RedirectStandardOutput = True
            MonProcess.StartInfo.RedirectStandardInput = True
            MonProcess.StartInfo.RedirectStandardError = True
     
            MonProcess.Start()  
            MonProcess.BeginOutputReadLine()
            MonProcess.BeginErrorReadLine()
     
            MonProcess.WaitForExit()
            MonProcess.Close()
    End Sub
    Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            If e.Data = Nothing Then Exit Sub
            frmProgress1.SetProgress(e.Data.ToString, True, frmProgress.ProcessNames.FFmpeg)
    End Sub
    Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            If e.Data = Nothing Then Exit Sub
            frmProgress1.SetProgress(e.Data.ToString, True, frmProgress.ProcessNames.FFmpeg)
    End Sub
    Private Sub ProcessExit(sender As Object, e As System.EventArgs)
                My.Computer.Audio.Play(My.Resources.misc229, Microsoft.VisualBasic.AudioPlayMode.Background) ' Son joué a chaque fin de processus
    End Sub
    Les points et problèmes identifiés :
    1- Pour commencer je crois que l'instanciation des objets Process dans la procédure ShellExecuteFFmpeg est une mauvaise idée, car je ne peux pas accéder à cet objet en dehors de la procédure et a fortiori pour annuler depuis mon formulaire d'affichage de la progression a l'aide de MonProcess.kill ou MonProcess.CloseMainWindow.

    Est ce que vous pensez que le mieux serait d'utiliser 2 objets Process ou un seul ? et ou ? (dans le Form.Load par exemple) ? Comment réecrire ShellExecute dans ce cas ?

    2- Mes Processus se lance dans un backgroundWorker, je dois supprimer ce dernier. A priori cela ne devrait pas me poser trop de problème sauf que j'avais fait cela pour libérer le Thread qui exécute l'affichage de la progression (d’après un post de Pol63 (hier) je devrais utiliser l’événement exited, je n'ai pas bien compris comment cet événement pourrait me permettre d’éviter le freeze puisque celui-ci ne s’exécute qu'une fois que le Processus est terminé (si je pouvais avoir une explication la dessus ça serait sympa).
    (Pour information mon formulaire frmProgress1 me sert pour l'affichage de la progression fournie pas les DataReceived. Ce formulaire est instancié depuis le Thread UI et ma méthode SetProgress utilise une invocation pour permettre l'affichage Cross-Threads).

    3- J'utilise WaitForExit car le 2eme Processus (2eme passe) doit attendre le 1er Processus pour pouvoir s'exécuter. Mais si je supprime le BackGroundWorker cela signifie que le thread UI va s'arretter sur la ligne WaitForExit et donc figer l'affichage. Comment obtenir un affichage dans ces conditions ?

    Je suis conscient de ne pas forcement être très clair dans ma demande mais j'aimerais beaucoup avoir votre aide pour éviter de faire des bêtises et si vous pouvez.
    Merci beaucoup.

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    1
    le mieux serait une classe TraitementVideo avec une variable privée as process (non initialisé)
    depuis un form pour démarrer un processus il faudrait faire
    dim t as new TraitementVideo (les paramètres)
    t.start (et encore tu pourrais démarrer le processus sur le sub new)
    comme ca en dehors de la sub tu as ta variable processus
    après ce n'est pas utile pour tout, sender dans les évènements du process c'est le process (par contre pour un .kill c'est utile)

    tu peux donc instancier autant de TraitementVideo que tu veux, à un instance T chacun aura sa variable processus donc pas de mélange

    2
    process.start n'est pas bloquant, le processus démarre
    je ne sais pas si en interne .net démarre un thread qui démarre le processus, mais ce n'est pas spécialement important
    l'évènement exited est levé quand le processus s'arrête
    c'est l'appel à waitforexit qui est bloquant, il suffit de ne plus l'appeler
    au passage sur ta classe TraitementImage tu peux créer des events pour relayer les infos aux forms
    si les events de la classe process sont sur un thread séparé ca irait dans mon hypothèse que .net démarre un thread pour démarrer le processus
    par contre tu peux te débrouiller pour faire comme le bgw, à savoir repasser sur le thread principal momentanément pour mettre à jours l'affichage

    3
    si tu dois démarrer 2 processus l'un à la suite de l'autre, et toujours les 2, c'est à la classe de le gérer (avoir 2 variables as process par exemple)
    sur exited du 1er processus alors tu démarres le 2ème


    concernant l'annulation, si le programme .exe ne prend pas en charge cette annulation, la seule méthode est alors de tuer le processus
    (éventuellement réfléchir pour tuer le processus si l'utilisateur quitte ton appli, sinon les processus restent)
    par contre si les processus ont créé des fichiers et que tu connais les chemins le mieux serait de les deleter

    edit : à priori ffmpeg est en ligne de commande et ne permet aucun dialogue donc pas d'annulation, donc kill si annulation demandée par l'utilisateur
    et à priori tu connais les chemins des fichiers donc tu dois pouvoir les supprimer (ils seront peut etre encore verouillés pendant quelques millisecondes après le kill, donc retenter plusieurs fois sur une seconde ou deux)


    edit 2 :
    piste d'amélioration, j'imagine que ce programme bouffe pas mal de ressources, auquel cas en lancer plusieurs en même temps peut être contre productif, auquel cas tu peux permettre à l'utilisateur d'en définir plusieurs à faire et t'occuper toi même de les enchainer (en instanciant les classes de traitement au fur et à mesure que la précédente se termine)
    piste d'amélioration 2, si c'est un traitement sans trop de paramétrage tu peux aussi juste lui demander un dossier où seront les fichiers à traiter, un dossier où seront les fichiers terminés et faire un service qui s'occupe h24 de voir s'il y a quelque chose à faire ^^ (ca perd certaines fonctionnalités, mais il suffit par contre de glisser des fichiers dans le dossier)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    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 Pol63, je vais étudier ta solution point par point qui semble répondre a ce dont j'ai besoin. Ça va me prendre du temps et j’aurais peut-être besoin de quelques précisons supplémentaires d'ici a ce week-end, je pense.
    Merci beaucoup

  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
    Bonsoir,
    Merci Pol63 d'avoir relancé ma créativité. J'ai pu sortir une ébauche de la classe avec quelques ajustements personnels. je n'ai pas encore exécuté une seule ligne mais je reflechie encore autour de ce bout de code pour savoir si il peut s'adapter facilement a différents cas possible.
    Donc je n'ai pas associé une classe a un ou deux Process mais carrément a une liste de Process. C'est le fait de devoir enchaîner 2 processus qui m'a poussé a faire ça. Je pense que l'idée n'ai pas mauvaise mais après je n'ai pas le recul suffisant pour savoir si ce n'est pas une erreur de faire comme cela.
    En réalité j'ai aussi une petite idée derrière la tête, ça me permettrait éventuellement d'avoir une meilleur gestion de mes calculs de progression pour plus tard. Il reste encore beaucoup a faire, notamment dans le StopAll qui est un peu brutal pour l'instant.....
    Concernant les ressources c'est pas un soucis, c'est un logiciel qui ne fait que du traitement vidéo avec de l'encodage pure et dure donc c'est normal que ça pompent pas mal.
    J'ai pas encore testé la sortie pour l’affichage par contre, ça va être la surprise.

    Je suis preneur pour toutes critiques éventuelles notamment sur l’enchaînement des process.
    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    Public Class VideoParam
        Private _ExeFile As String
        Public Property ExeFile() As String
            Get
                Return _ExeFile
            End Get
            Set(ByVal value As String)
                _ExeFile = value
            End Set
        End Property
        Private _CommandLine As String
        Public Property CommandLine() As String
            Get
                Return _CommandLine
            End Get
            Set(ByVal value As String)
                _CommandLine = value
            End Set
        End Property
        Private _SyncMode As Boolean
        Public Property SyncMode() As Boolean
            Get
                Return _SyncMode
            End Get
            Set(ByVal value As Boolean)
                _SyncMode = value
            End Set
        End Property
    End Class
     
    Public Class clsVideoProcessing
        Private _ProcessId As Integer
        Private _ListOfAsyncProcess As New SortedList(Of Integer, Process)
        Private _listOfSyncProcess As New SortedList(Of Integer, Process)
        Private _Tasks As New SortedList(Of Integer, VideoParam)
        Event ProcessOutPutDataReceived(ByVal Sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs)
        Event ProcessErrorDataReceived(ByVal Sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs)
        Event ProcessExited(ByVal Sender As Object, ByVal e As System.EventArgs)
        Private Sub New(ByVal VideoParam As VideoParam)
            Me.Add(VideoParam)
        End Sub
        Public Sub Add(ByVal VideoParam As VideoParam)
            Dim Process As New Process
            AddHandler Process.OutputDataReceived, AddressOf OutputDataReceived
            AddHandler Process.ErrorDataReceived, AddressOf ErrorDataReceived
            AddHandler Process.Exited, AddressOf Exited
     
            'MonProcess.SynchronizingObject = Me
            Process.EnableRaisingEvents = True
     
            Process.StartInfo.FileName = VideoParam.ExeFile
            Process.StartInfo.Arguments = VideoParam.CommandLine
            'MonProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
            Process.StartInfo.CreateNoWindow = True        ' True
            Process.StartInfo.UseShellExecute = False      ' False
            Process.StartInfo.RedirectStandardOutput = True
            Process.StartInfo.RedirectStandardInput = True
            Process.StartInfo.RedirectStandardError = True
     
            If VideoParam.SyncMode Then
                Me._listOfSyncProcess.Add(Me._ProcessId, Process)
            Else
                Me._ListOfAsyncProcess.Add(Me._ProcessId, Process)
            End If
            Me._Tasks.Add(Me._ProcessId, VideoParam)
            Me._ProcessId += 1
        End Sub
        Public Sub StartAll()
            Dim Process As Process
            If _ListOfAsyncProcess.Count > 0 Then
                For Each kvp As KeyValuePair(Of Integer, Process) In _ListOfAsyncProcess
                    Process = kvp.Value
                    Process.Start()
                    Process.BeginOutputReadLine()
                    Process.BeginErrorReadLine()
                Next
            End If
            If _listOfSyncProcess.Count > 0 Then
                Process = _listOfSyncProcess.Item(0)
                Process.Start()
                Process.BeginOutputReadLine()
                Process.BeginErrorReadLine()
            End If
        End Sub
        Public Sub StopAll()
            Dim Process As Process
            For Each kvp As KeyValuePair(Of Integer, Process) In _ListOfAsyncProcess
                Process = kvp.Value
                Process.Kill()
            Next
            For Each kvp As KeyValuePair(Of Integer, Process) In _listOfSyncProcess
                Process = kvp.Value
                Process.Kill()
            Next
        End Sub
        Public Property Tasks() As SortedList(Of Integer, VideoParam)
            Get
                Return _Tasks
            End Get
            Set(ByVal value As SortedList(Of Integer, VideoParam))
                _Tasks = value
            End Set
        End Property
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            RaiseEvent ProcessOutPutDataReceived(sender, e)
        End Sub
        Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            RaiseEvent ProcessErrorDataReceived(sender, e)
        End Sub
        Private Sub Exited(sender As Object, e As System.EventArgs)
            Dim Process As Process = CType(sender, Diagnostics.Process)
            Dim ProcessId As Integer
            If Me._listOfSyncProcess.ContainsValue(CType(sender, Process)) Then
                ' Process synchrone terminé
                ProcessId = Me._listOfSyncProcess.IndexOfValue(CType(sender, Diagnostics.Process))
                Me._listOfSyncProcess.Remove(ProcessId)
                Me.StartAll()
            ElseIf Me._ListOfAsyncProcess.ContainsValue(CType(sender, Diagnostics.Process)) Then
                ' Process asynchrone terminé
                ProcessId = Me._ListOfAsyncProcess.IndexOfValue(CType(sender, Diagnostics.Process))
                Me._ListOfAsyncProcess.Remove(ProcessId)
            End If
            Me._Tasks.Remove(ProcessId)
            Process.Close()
        End Sub
    End Class

  5. #5
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    ca m'a l'air pas mal

    Citation Envoyé par BasicZX81 Voir le message
    Concernant les ressources c'est pas un soucis, c'est un logiciel qui ne fait que du traitement vidéo avec de l'encodage pure et dure donc c'est normal que ça pompent pas mal.
    je ne dis pas que c'est anormal
    Citation Envoyé par Pol63 Voir le message
    j'imagine que ce programme bouffe pas mal de ressources, auquel cas en lancer plusieurs en même temps peut être contre productif
    je dis juste que dans certains cas il vaut mieux faire les choses à la suite plutot qu'en même temps, là ca doit prendre plus de processeur que de disque donc c'est à tester ...
    sur un disque dur non ssd, faire plusieurs files de copies de fichiers en même temps peut prendre plus de temps que chacune leur tour
    et en plus ca flingue un peu le disque
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  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
    ca m'a l'air pas mal
    Merci
    J'ai pensé a une chose, j’aurais peut-être besoin t’identifier mes process, par exemple dans ma classe videoParam je pourrais rajouter TaskName ou quelque chose dans ce style, puis l'enregistrer quelque part dans ma Classe VideoProcessing au moment du New ou du Add. Ceci afin pouvoir récupérer cet identifiant dans les évents.
    Je voudrais aussi pouvoir donner un accès public pour chaque Process avec un accès a partir de l'identifiant (on ne sais jamais, c'est au cas ou j'aurais besoin d'arrêter un Process Particulié par exemple) mais ça je devrais savoir faire.

    J'ai vu que l'objet Process possède une propriété ProcessId mais je ne sais pas si ça peut me servir et a quel moment ce ProcessId est connu (au moment du start ?).

    Une idée pour mettre ce système d'identifiant en place ?

  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
    Bonjour, Bon je crois que j'ai a peu prêt fini ma classe. Je n'ai pas encore exécuté le code mais ça devrait aller. Je regrette peut-être quelques lourdeurs dans l’écriture au niveau de la déclaration des CustomEvents, j'aurais peut-être préféré faire de l'héritage des DataReceivedEvents pour avoir un code plus concis mais on ne peut pas. Ma seconde étape va être de tester tout ça en situation réelle, si je n'ai pas de retouche a faire j'aurais bien de la chance...
    Je passe des paramètres dans les CustomsEvents pour faciliter l'identification des Processus avec notamment la variable ProcessId. J'espère que ça va fonctionner

    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    Imports System.Threading
     
    Public Class VideoParam
        Public Sub New(ByVal ExeFile As String, ByVal CommandLine As String, ByVal SyncMode As Boolean)
            Me._ExeFile = ExeFile
            Me._CommandLine = CommandLine
            Me._SyncMode = SyncMode
        End Sub
        Public Sub New(ByVal ExeFile As String, ByVal CommandLine As String, ByVal SyncMode As Boolean, ByVal TaskName As String)
            Me.New(ExeFile, CommandLine, SyncMode)
            Me._TaskName = TaskName
        End Sub
        Private _ExeFile As String
        Public ReadOnly Property ExeFile() As String
            Get
                Return _ExeFile
            End Get
        End Property
        Private _CommandLine As String
        Public ReadOnly Property CommandLine() As String
            Get
                Return _CommandLine
            End Get
        End Property
        Private _SyncMode As Boolean
        Public ReadOnly Property SyncMode() As Boolean
            Get
                Return _SyncMode
            End Get
        End Property
        Private _TaskName As String
        Public Property TaskName() As String
            Get
                Return _TaskName
            End Get
            Set(ByVal value As String)
                _TaskName = value
            End Set
        End Property
    End Class
    Public Class CustomDataReceivedEventArgs
        Public Sub New(ByVal ProcessId As Integer, ByVal VideoParam As VideoParam, ByVal e As DataReceivedEventArgs)
            Me._ProcessId = ProcessId
            Me._VideoParam = VideoParam
            Me._e = e
        End Sub
        Private _ProcessId As Integer
        Public ReadOnly Property ProcessId As Integer
            Get
                Return _ProcessId
            End Get
        End Property
        Private _VideoParam As VideoParam
        Public ReadOnly Property VideoParam() As VideoParam
            Get
                Return _VideoParam
            End Get
        End Property
        Private _e As DataReceivedEventArgs
        Public ReadOnly Property e As DataReceivedEventArgs
            Get
                Return _e
            End Get
        End Property
    End Class
    Public Class CustomExitedEventArgs
        Public Sub New(ByVal ProcessId As Integer, ByVal VideoParam As VideoParam, ByVal e As EventArgs)
            Me._ProcessId = ProcessId
            Me._VideoParam = VideoParam
            Me._e = e
        End Sub
        Private _ProcessId As Integer
        Public ReadOnly Property ProcessId As Integer
            Get
                Return _ProcessId
            End Get
        End Property
        Private _VideoParam As VideoParam
        Public ReadOnly Property VideoParam() As VideoParam
            Get
                Return _VideoParam
            End Get
        End Property
        Private _e As EventArgs
        Public ReadOnly Property e As EventArgs
            Get
                Return _e
            End Get
        End Property
    End Class
    Public Class clsVideoProcessing
        Private _ProcessId As Integer
        Private _ListOfAsyncProcess As New SortedList(Of Integer, Process)
        Private _listOfSyncProcess As New SortedList(Of Integer, Process)
        Private _Tasks As New SortedList(Of Integer, VideoParam)
        Event ProcessOutPutDataReceived(ByVal Sender As Object, ByVal e As CustomDataReceivedEventArgs)
        Event ProcessErrorDataReceived(ByVal Sender As Object, ByVal e As CustomDataReceivedEventArgs)
        Event ProcessExited(ByVal Sender As Object, ByVal e As CustomExitedEventArgs)
        Public Sub New(ByVal VideoParam As VideoParam)
            Me.Add(VideoParam)
        End Sub
        Public Sub Add(ByVal VideoParam As VideoParam)
            Dim Process As New Process
            AddHandler Process.OutputDataReceived, AddressOf OutputDataReceived
            AddHandler Process.ErrorDataReceived, AddressOf ErrorDataReceived
            AddHandler Process.Exited, AddressOf Exited
     
            'MonProcess.SynchronizingObject = Me
            Process.EnableRaisingEvents = True
     
            Process.StartInfo.FileName = VideoParam.ExeFile
            Process.StartInfo.Arguments = VideoParam.CommandLine
            'MonProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
            Process.StartInfo.CreateNoWindow = True        ' True
            Process.StartInfo.UseShellExecute = False      ' False
            Process.StartInfo.RedirectStandardOutput = True
            Process.StartInfo.RedirectStandardInput = True
            Process.StartInfo.RedirectStandardError = True
     
            'MonProcess.Start()
     
            'MonProcess.BeginOutputReadLine()
            'MonProcess.BeginErrorReadLine()
     
            ''MonProcess.WaitForExit()
            'MonProcess.Close()
            If VideoParam.SyncMode Then
                Me._listOfSyncProcess.Add(Me._ProcessId, Process)
            Else
                Me._ListOfAsyncProcess.Add(Me._ProcessId, Process)
            End If
            Me._Tasks.Add(Me._ProcessId, VideoParam)
            Me._ProcessId += 1
        End Sub
        Public ReadOnly Property Tasks() As SortedList(Of Integer, VideoParam)
            Get
                Return _Tasks
            End Get
        End Property
        Public ReadOnly Property ListOfsyncProcess() As SortedList(Of Integer, Process)
            Get
                Return _listOfSyncProcess
            End Get
        End Property
        Public ReadOnly Property ListOfAsyncProcess() As SortedList(Of Integer, Process)
            Get
                Return _ListOfAsyncProcess
            End Get
        End Property
        Public Sub StartAll()
            Dim Process As Process
            If _ListOfAsyncProcess.Count > 0 Then
                For Each kvp As KeyValuePair(Of Integer, Process) In _ListOfAsyncProcess
                    Process = kvp.Value
                    Process.Start()
                    Process.BeginOutputReadLine()
                    Process.BeginErrorReadLine()
                Next
            End If
            If _listOfSyncProcess.Count > 0 Then
                Process = _listOfSyncProcess.Item(0)
                Process.Start()
                Process.BeginOutputReadLine()
                Process.BeginErrorReadLine()
            End If
        End Sub
        Public Sub StopAll()
      Dim Process As Process
            For Each kvp As KeyValuePair(Of Integer, Process) In _listOfSyncProcess
                Process = kvp.Value
                CloseProcess(Process)
            Next
            _listOfSyncProcess.Clear()
            For Each kvp As KeyValuePair(Of Integer, Process) In _ListOfAsyncProcess
                Process = kvp.Value
                CloseProcess(Process)
            Next
            _ListOfAsyncProcess.Clear()
        End Sub
        Private Sub CloseProcess(ByVal Process As Process)
            Dim i As Integer
            For i = 0 To 4
                If Not Process.HasExited Then
                    ' Wait 2 seconds.
                    Thread.Sleep(2000)
                    Process.CloseMainWindow()
                Else
                    Exit For
                End If
            Next i
            Process.Kill()
        End Sub
     
        Private Function GetId(ByVal Process As Process) As Integer
            If Me._listOfSyncProcess.ContainsValue(Process) Then
                GetId = Me._listOfSyncProcess.IndexOfValue(Process)
            ElseIf Me._ListOfAsyncProcess.ContainsValue(Process) Then
                GetId = Me._ListOfAsyncProcess.IndexOfValue(Process)
            End If
            Return GetId
        End Function
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Dim ProcessId As Integer = GetId(CType(sender, Diagnostics.Process))
            Dim Task As VideoParam = _Tasks.Item(ProcessId)
            Dim EventArgs As New CustomDataReceivedEventArgs(ProcessId, Task, e)
            RaiseEvent ProcessOutPutDataReceived(sender, EventArgs)
        End Sub
        Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Dim ProcessId As Integer = GetId(CType(sender, Diagnostics.Process))
            Dim Task As VideoParam = _Tasks.Item(ProcessId)
            Dim EventArgs As New CustomDataReceivedEventArgs(ProcessId, Task, e)
            RaiseEvent ProcessErrorDataReceived(sender, EventArgs)
        End Sub
        Private Sub Exited(sender As Object, e As System.EventArgs)
            Dim Process As Process = CType(sender, Diagnostics.Process)
            Dim ProcessId As Integer = GetId(Process)
            If Me._listOfSyncProcess.ContainsKey(ProcessId) Then
                ' Process synchrone terminé
                Me._listOfSyncProcess.Remove(ProcessId)
                Me.StartAll()
            ElseIf Me._ListOfAsyncProcess.ContainsKey(ProcessId) Then
                ' Process asynchrone terminé
                Me._ListOfAsyncProcess.Remove(ProcessId)
            End If
     
            Dim Task As VideoParam = _Tasks.Item(ProcessId)
            Dim EventArgs As New CustomExitedEventArgs(ProcessId, Task, e)
            RaiseEvent ProcessExited(sender, EventArgs)
            Me._Tasks.Remove(ProcessId)
            Process.Close()
        End Sub
    End Class

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    lu en diagonale, mais je pense que si tu mettais le process sur la classe videoparam tu aurais moins de code
    la classe videoparam ne devrait peut etre pas être juste une classe de paramétrage, mais une classe de traitement (process) avec des paramètres et des états (statut, avancement ...)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    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 Pol63, je vais tenter d’améliorer mon code.
    Donc je viens de faire des essais en réel et forcement j'ai fait des erreurs que je corrige au fur et a mesure (notamment pour accéder aux listes soit par la clé soit par l'index). Bref c'est pas très grave.
    En revanche j'ai un soucis que je ne sais pas régler :
    Pour l'instant il m'est difficile d’enchaîner 2 processus a l’intérieur de la classe car tel que mon programme principal est écrit, entre 2 processus j'envoi des informations d'initialisation pour les calculs de progression + de l'affichage a vers mon formulaire de progression.
    Ton 1er Post qui a l'air de reprendre point par point tous ces problèmes mais je pense que je n'ai peut être pas tout compris. J'avoue que je ne sais pas par quel bout je dois reprendre mon code pour regler ca (au moins provisoirement).
    Devant cette difficulté j'ai fait ceci (en attentant de pouvoir faire mieux):
    A noter que j'ai ajouté une propriété Terminated pour la circonstance qui n'est peut-être pas judicieuse (ou que j'utilise incorrectement) :
    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
     
          CommandLine = "CommandLine 1ere Pass"
          Dim VideoParam As New VideoParam(FFMPEG_EXE, CommandeLine, True)
          VideoProcessing.Add(VideoParam)
          VideoProcessing.StartAll()
          Do
          Loop While VideoProcessing.Terminated = False
     
    ' Ici j'ai du code d'initialisation des calculs de progression + affichage vers frmProgress
     
          CommandLine = "CommandLine 2eme Pass"
          Dim VideoParam As New VideoParam(FFMPEG_EXE, CommandeLine, True)
          VideoProcessing.Add(VideoParam)
          VideoProcessing.StartAll()
          Do
          Loop While VideoProcessing.Terminated = False
    Je dois libérer le thread principal pour pouvoir au moins lancer l'action d'annulation depuis frmProgress et j'imagine que le Do Loop est a proscrire.
    L’exécution de l'affichage se fera principalement a partir des Events DataReceived mais j'ai aussi des messages issus du thread principal comme celui que je cite plus haut.
    Je procède d'une très mauvaise façon a mon avis, si je pouvais être orienté sur une solution qui m’évite ces soucis ça m'intéresserais beaucoup.

    Merci beaucoup si je peux avoir a nouveau de l'aide.

  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
    Bonsoir Pol63,
    Bon après réflexion je crois que je vais repousser l’intégration de ma nouvelle classe dans le code. C'est beaucoup plus compliqué que je ne le pensais.
    Je dois déplacer les lignes de codes entre les 2 processus dans la classe VideoProcessing puisque ce sont des lignes liés aux calculs de l'avancement.
    Donc dans cette classe je devrais intégrer les calculs liées a l'avancement en tenant compte du fait que je peux aussi avoir des traitements qui s'effectue directement dans le code (sans Process) et que je dois intégrer dans le calcul. Je doit aussi interpréter les sorties DataReceived (pour calculer l'avancement) d'une façon différente suivant le Process.
    Donc je dois réfléchir d'une manière plus global et ça passe par une grosse restructuration de mon code. Difficile dans ces conditions de faire une classe en 3 jours
    Je me referais certainement surface sur le Forum à un moment ou a un autre quand j'aurais plus avancé .

  11. #11
    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, Je passe ce post en résolu. L'affichage fonctionne (a condition de ne pas bloquer le Thread principale comme je l'avais fait avec mes Do Loop) et il n'y a aucun soucis avec la classe.
    J'ai rajouté WaitForExit dans l’événement Exited. Même si çà peut être bloquant pendant un cours instant mais ça permet de traiter correctement les messages DataReceived qui sont encore dans le buffer après l'arrêt du Process.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Private Sub Exited(sender As Object, e As System.EventArgs)
            Dim Process As Process = CType(sender, Diagnostics.Process)
            Process.WaitForExit()
            .....
    End Sub
    Merci à Pol63.

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

Discussions similaires

  1. [XL-2007] Besoin d'aide pour parfaire mon code enregistrement
    Par capi81 dans le forum Macros et VBA Excel
    Réponses: 11
    Dernier message: 14/08/2014, 16h31
  2. [XL-2007] Besoin d'aide pour améliorer mon code copier-coller
    Par capi81 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 31/07/2014, 16h14
  3. [VB.NET] besoin d'aide pour déchiffrer un code
    Par pcdj dans le forum Windows Forms
    Réponses: 10
    Dernier message: 27/06/2006, 11h32
  4. [VBA-E] Aide pour éxécuter mon code en cliquant sur un bouton dans excel.
    Par pauletta22 dans le forum Macros et VBA Excel
    Réponses: 53
    Dernier message: 29/05/2006, 13h47
  5. Je besoin d'aide pour terminer mon code
    Par Paulinho dans le forum C++
    Réponses: 7
    Dernier message: 06/11/2005, 23h30

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