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 :

Synchronisation de SetWindwosPos avec un process.start (fichier exe)


Sujet :

VB.NET

  1. #1
    Membre éprouvé Avatar de excalybur
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2014
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Chargé d'affaire
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2014
    Messages : 317
    Par défaut Synchronisation de SetWindwosPos avec un process.start (fichier exe)
    Bonjour,

    Je lance un fichier exécutable (notepad.exe pour exemple) depuis le Form.

    Par défaut il s'affiche en format minimized (1/4 de l'écran) à un emplacement aléatoire.

    Je dimensionne et positionne la fenêtre du process en cours avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SetWindowPos(myProcess1.MainWindowHandle, IntPtr.Zero, 0, 0, 800, 1000, 0)
    Mon programme :

    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
     Using myProcess1 As New Process()
     
     
                                                myProcess1.StartInfo.FileName = "C:\notepad.exe"   'charge le processus 
     
                                                myProcess1.Start() 'lance le process
     
                                                Thread.Sleep(100) 'laisse le temps au pocess de se lancer
     
                                                SetWindowPos(myProcess1.MainWindowHandle, IntPtr.Zero, 0, 0, 800, 1000, 0)  'dimensionner la fenêtre process 
     
                                                SetWindowText(myProcess1.MainWindowHandle, "TITRE NUMERO UN")  'change le titre de la fenêtre process
     
                                                'fermer la fenêtre en fin de processus :
                                                myProcess1.WaitForExit()  'attend qu'il soit terminé avant d'aller plus loin
                                                myProcess1.Close()  'ferme le process
                                            End Using
    On note que laisse le temps au pocess de se lancer sauf que dans certains cas (mise à jour du PC, etc.) ce délai est trop court et le process démarre définitivement dans le format aléatoire vu plus haut.

    Si j'augmente la durée de Thread.Sleep l'écran va flasher une fraction de seconde sur le format aléatoire avant de passer au format imposé. => pas terrible !

    Bien sur on ne peut pas mettre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SetWindowPos(myProcess1.MainWindowHandle, IntPtr.Zero, 0, 0, 800, 1000, 0)
    avant myProcess1.Start

    Ma question :

    Comment synchroniser SetWindowPos avec myProcess1.Start pour éviter les problèmes évoqués ci-dessus. Je n'ai rien trouvé sur les rares sujets traitant du sujet

    En vous remerciant pour votre aide.

    Bien à vous

  2. #2
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour

    Code exemple qui fera peut être ton bonheur:
    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
     
    Imports System.Runtime.InteropServices
    Public Class Form1
        Private myProcess As Process
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            'Dim pi As New ProcessStartInfo
            'pi.FileName = "notepad"
            'myProcess = New Process
            'myProcess.StartInfo = pi
            'myProcess.Start()
        End Sub
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
     
            StartProcess()
            If myProcess Is Nothing Then Return
            myProcess.WaitForInputIdle()
            Dim handle As IntPtr = myProcess.MainWindowHandle
            If handle <> IntPtr.Zero Then
                SetWindowPos(handle, 0, 150, 0, 400, 250, 0)
            End If
     
     
        End Sub
        Private Sub StartProcess()
            Dim pi As New ProcessStartInfo
            pi.FileName = "notepad"
            myProcess = New Process
            myProcess.StartInfo = pi
            myProcess.Start()
     
        End Sub
      Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
            If myProcess IsNot Nothing Then
                myProcess.WaitForExit()
                myProcess.CloseMainWindow()
            End If
        End Sub
     
        <DllImport("user32.dll", EntryPoint:="SetWindowPos")>
        Public Shared Function SetWindowPos(HWND As IntPtr,
                                            hWndInsertAfter As IntPtr,
                                            Xpos As Integer, Ypos As Integer, xSize As Integer, ySize As Integer, wFlags As Integer) As IntPtr
        End Function
     
     
    End Class
    bon code ...

  3. #3
    Membre éprouvé Avatar de excalybur
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2014
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Chargé d'affaire
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2014
    Messages : 317
    Par défaut
    Merci pour la réponse,

    J'étudie la chose car apparemment cela ne marche pas avec tous les exe.

    Je reviens vers vous après mon analyse.

  4. #4
    Membre éprouvé Avatar de excalybur
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2014
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Chargé d'affaire
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2014
    Messages : 317
    Par défaut
    Bonsoir,

    Excusez-moi pour ce retard j'ai dû régler des urgences en ces temps compliqué.

    Pour revenir au sujet de la discussion, j'ai essayé le code proposé et il fonctionne parfaitement avec Notepad.exe

    Par contre en remplaçant notepad.exe avec mon exe

    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
    Imports System.Runtime.InteropServices
    Imports System.Threading
     
    Public Class Form1
        Private myProcess As Process
     
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
     
            Dim pi As New ProcessStartInfo
            '  pi.FileName = "notepad"
            pi.FileName = "d:\sbwin\py483USR\pywin64.exe"
            myProcess = New Process
            myProcess.StartInfo = pi
            myProcess.Start()
     
            If myProcess Is Nothing Then Return
            myProcess.WaitForInputIdle()
            Dim handle As IntPtr = myProcess.MainWindowHandle
            If handle <> IntPtr.Zero Then
                SetWindowPos(handle, 0, 150, 0, 600, 250, 0)
            End If
        End Sub
     
        Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
            If myProcess IsNot Nothing Then
                myProcess.WaitForExit()
                myProcess.CloseMainWindow()
            End If
        End Sub
     
        <DllImport("user32.dll", EntryPoint:="SetWindowPos")>
        Public Shared Function SetWindowPos(HWND As IntPtr,
                                            hWndInsertAfter As IntPtr,
                                            Xpos As Integer, Ypos As Integer, xSize As Integer, ySize As Integer, wFlags As Integer) As IntPtr
        End Function
     
    End Class
    j'obtiens une erreur à la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myProcess.WaitForInputIdle()
    qui précise : "Echec de WaitForInputIdle. Cet échec est peut-être dû à l'absence d'interface graphique pour le processus"

    Cette curieuse erreur n'a pas de sens (pour l'interface graphique) à mon avis car avec la version que je propose dans le topic initial mon EXE fonctionne nickel sauf pour ce qui est du problème d'affichage parfois aléatoire.

    En fait la fenêtre minimized et à une position aléatoire de mon application apparait bien et de plus fonctionne bien. Sauf que la fenêtre n'a pas pris la bonne taille. Il y a un autre problème avec SetWindowsPos. (Problème inexistant dans mon application initiale).

    Je pense que le problème est dû à la configuration de certains EXE. Il manque peut être un Import et une précision du WaitForInputIdle ?

    J'ai passé beaucoup de temps à essayer de trouver une explication et là j'avoue je cale !

    Si quelqu'un à une idée car on est pas loin d'une application utile pour tous les EXE.

    A vous lire

  5. #5
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour

    Je pense qu'il faut sortir le code de positionnement dans un second button:
    code vb.net modifie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
            If myProcess IsNot Nothing Then
                myProcess.WaitForInputIdle()
                Dim handle As IntPtr = myProcess.MainWindowHandle
                If handle <> IntPtr.Zero Then
                    Dim retval = SetWindowPos(handle, 0, 400, 400, 100, 100, 0)
                End If
            End If
        End Sub

  6. #6
    Membre éprouvé Avatar de excalybur
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2014
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Chargé d'affaire
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2014
    Messages : 317
    Par défaut
    Bonsoir,

    Merci pour ta réponse. Je ne vois pas pourquoi avec un deuxième bouton cela devrait fonctionner car je ne comprends pas la logique. A moins que tu ne veuille donner du temps à mon exe. c'est vrai qu'il met une bonne seconde pour s'afficher.

    En rendant ton sub public et en le testant avec un deuxième bouton j'ai toujours le retour de la même erreur.

    Précision cet exe a été écrit en langage C sous Linux mais pour application Windows 64.

    Il serait intéressant de faire le test avec d'autre exe pour console.

    Je continu à creuser !

    [Edit - complément]

    En recherchant sur les sites anglophones, le problème est récurant. Si notepad marche il n'en est rien pour cmd.exe

    Avec le test avec cmd.exe j'obtiens le même message d'erreur que pour mon programme pywin64

    Il semblerait (version du topic pour VB de 2014 ) qu'il s'agirait d'un problème lié aux UI sans autres explications.

    Si vous avez une idée ?

    A vous lire.

    Bien à vous

  7. #7
    Membre éprouvé Avatar de excalybur
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Novembre 2014
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Chargé d'affaire
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2014
    Messages : 317
    Par défaut
    bonjour

    Voici la solution ! Après une longue recherche infructueuse autour de la planète j'ai pris le problème à l'envers et j'ai supprimer le WaitForExit (un vrai poison dans ce cas) du ou des Process et remplacer par un test astucieux.

    Il faut régler la valeur de Thread.sleep(N) en fonction du temps de démarrage de vos EXE. Dans mon exemple j'ai mis N=100 ms tout dépend de votre PC. Une optimisation du sleep peut être prévu en automatisant le test qui vérifie si le Process est ouvert (automatisation non développé dans l'exemple). Résultat les fenêtres des EXE s'ouvrent correctement.

    Cerise sur le gâteau : L'idée est de pouvoir arrêter des process EXE autonomes pour X raisons depuis votre application sous Windows.

    Pour essayer le programme, ci-dessous ouvrir un Form avec 3 boutons. Les boutons 1 et 2 ouvrent chacun un programme de votre choix (ça peut même être le même ouvert deux fois) par exemple CMD et Notepad. Dans mon exemple ils prennent le nom des process pywin1 et pywin2. Le bouton 3 sert à 'tuer' le process en route en éludant toutes les configurations indésirables possibles comme Process is nothing ou Proces.HasExited. Admirez l'astuce pour passer à la ligne suivante si pywin1 hasExited :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    If pywin1.HasExited() Then Else pywin1.Kill()
    !

    Le code a utiliser :

    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
     
     
    Option Explicit On
     
    Imports System.Threading
    Imports System.IO
    Imports System.Runtime.InteropServices
    Imports System.Text
    Imports System.Text.RegularExpressions
    Imports System.Threading.Tasks
     
    Public Class Form1
     
        <DllImport("user32.dll")>
        Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Boolean
        End Function 'pour positionner la fenêtre de pywin64.exe
        <DllImport("user32.dll")>
        Shared Function SetWindowText(ByVal hwnd As IntPtr, ByVal windowName As String) As Boolean
        End Function 'pour changer le titre de la fenêtre de pywin64.exe
     
        Public pInfoPy As New ProcessStartInfo()
        Public pywin1 As Process
        Public pywin2 As Process
     
     
        Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     
            pInfoPy.FileName = "C:\Windows\System32\cmd.exe"
            pywin1 = Process.Start(pInfoPy)        'lance le process pywin1
     
            Thread.Sleep(100) 'tempo 100 ms
            SetWindowPos(pywin1.MainWindowHandle, IntPtr.Zero, 600, 0, 600, 1000, 0) 'Positionne et dimensionne la fenêtre du process actif
     
        End Sub
     
     
     
        Public Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
     
            pInfoPy.FileName = "C:\Windows\System32\notepad.exe"
            pywin2 = Process.Start(pInfoPy)        'lance le process pywin2
     
            Thread.Sleep(100) 'tempo 100 ms
            SetWindowPos(pywin2.MainWindowHandle, IntPtr.Zero, 1250, 0, 650, 1000, 0) 'Positionne et dimensionne la fenêtre du process actif
     
        End Sub
     
        Public Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
     
            If pywin1 Is Nothing And pywin2 Is Nothing Then Exit Sub
     
            If pywin1 Is Nothing Then pywin2.Kill() : Exit Sub
            If pywin2 Is Nothing Then pywin1.Kill() : Exit Sub
     
            If pywin1.HasExited() Then Else pywin1.Kill()
            If pywin2.HasExited() Then Exit Sub Else pywin2.Kill() 
     
        End Sub
     
    End Class
    Certes cet exemple ne permet pas de voir toutes les possibilités de gestion d'arrêt d'un programme 100% autonome que l'on ne peut plus arrêter normalement une fois lancé. Il est préférable de placer deux exe qui une fois qu'ils ont reçu les informations via pInfoPy.Arguments = 'paramètres à fournir à l'EXE' exécutent leurs tâches et s'arrêtent automatiquement en restituant un résultat dans un fichier.
    Sel bémol : Si une interruption se produit suite au changement d'état du Process pendant le test (pendant une microseconde voir moins ?) comment gérer l'éventuel erreur qui va bloquer le système? Je n'ai jamais eu le cas jusqu'à présent. Il ne se produira peux être jamais ? Si c'est cela pourquoi ?

    J'espère que ce topic vous rendra bien service.

    Bien à vous

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

Discussions similaires

  1. process.start et .exe cmd
    Par GrosF***.fr dans le forum C#
    Réponses: 0
    Dernier message: 08/07/2010, 20h15
  2. [VB.NET 1.1] Ping silencieux avec Process.Start()
    Par toniolol dans le forum Windows Forms
    Réponses: 6
    Dernier message: 30/09/2008, 13h35
  3. Process.start avec un processus père
    Par DranDane dans le forum C#
    Réponses: 2
    Dernier message: 24/09/2008, 14h02
  4. Réponses: 4
    Dernier message: 02/04/2008, 15h19
  5. Probleme avec Process.Start
    Par lucyole dans le forum VB.NET
    Réponses: 4
    Dernier message: 03/01/2008, 18h42

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