none
Fermer les fenêtres d'une application distante à l'aide de processus ou autres sans fenêtre principale RRS feed

  • Question

  • Bonjour,

    Je réalise un programme en WPF avec VB.net.

    Mon application ouvre une fenêtre qui ne s’affiche pas dans la barre des tâches.

    Cette fenêtre principale peut ouvrir d’autres fenêtres non affichables dans la barre des tâches.

    Lorsque je ferme mon application, je sauvegarde des données dans un fichier XML.

    La sauvegarde des données est réalisée dans les événements MyBase.Closed et Application_SessionEnding.

    Si l’utilisateur demande une exécution de l’application déjà en cours, l’application se ferme automatiquement.

    Je réalise cette action dans l’événement Application_Startup.

    Pour fermer l’application en cours, j’utilise la classe System.Diagnostics Process

    Comme ma fenêtre principale n’est pas dans la barre de tâches, je suis obligé d’utiliser la méthode Process.Kill.

    Cette méthode ne permet pas de déclencher l’événement MyBase.Closed de ma fenêtre et de sauvegarder mes données.

    Pourtant, si je ferme mon application à l’aide du bouton de fin de tâches dans le gestionnaire d’applications l’événement MyBase.Closed est bien déclenché.

    Process.kill n’est-il pas identique à la fin de tâche de l’application ?

    Actuellement, j’essaye sans succès de trouver des APIs ou méthodes qui me permettent de référencer mes fenêtres ouvertes dans mon application comme montré dans le gestionnaire de tâches et de pouvoir toutes les fermer.

    J’ai essayé à l’aide de l’API FindWindowEx et du titre de ma fenêtre principale de récupérer son handle et puis à l’aide de l’API SendMessage de lui envoyer une commande close.

    Cela fonctionne correctement.

    Je devrais réaliser cette fonction pour toutes les autres fenêtres ouvertes de mon application.

    Actuellement, je voudrais trouver une solution pour rechercher les fenêtres par exemple dans le processus de l’application (comme montré dans le gestionnaire de tâches) pour être sûre de fermer les bonnes fenêtres. Les titres des fenêtres peuvent être une source d’erreurs (Doublon).

    Quelqu’un a-t-il une solution ?

     Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
    
            'Lors du double click sur l'icone du bureau :
            '   Démarre le programme si le programme n'est pas en cours
            '   Stoppe le programme si celui-ci est en cours
    
            Dim CreatNew As Boolean
    
            'Vérifie si le thread pour le programme est pas déjà en cours
            Dim mut As New Mutex(True, "FrameDesktop", CreatNew)
    
            If CreatNew = True Then
    
                'Ouvre la fenêtre principale du programme de gestion des cadres
                Dim MainWindow As MainWindow = New MainWindow()
                MainWindow.Show()
    
            Else
    
                'Le programme de gestion des cadres est déjà en cours
                'Ferme le programme en cours et la nouvelle demande d'ouverture de ce programme 
    
                '****************
    
                'Const WM_SYSCOMMAND As Integer = &H112
                'Const SC_CLOSE As Integer = &HF060
    
                'WindowActiveHandle = FindWindowEx(IntPtr.Zero, IntPtr.Zero, Nothing, "Mainwindow")
                'SendMessage(WindowActiveHandle, WM_SYSCOMMAND, SC_CLOSE, 0)
    
    
                '******************
    
                'Récupère le processus actif
                Dim processActif As Process = Process.GetCurrentProcess
    
                'Récupère tous les processus ouverts de gestion des cadres
                Dim ProcessFrame() As Process = Process.GetProcessesByName("FrameDesktop")
    
                'Parcours les processus ouverts de gestion des cadres
                For Each ProcessItem As Process In ProcessFrame
    
                    'Vérifie si le processus à fermer n'est pas le processus en cours
                    If ProcessItem.Id <> processActif.Id Then
    
                        'Ferme le programme en cours
                        ProcessItem.Kill()
                        ProcessItem.WaitForExit()
                    End If
                Next
    
                'Ferme le programme demandant une nouvelle ouverture
                Application.Current.Shutdown()
    
            End If
    
        End Sub
    
    End Class


    samedi 29 février 2020 15:32

Réponses

  • Bonjour,

    Merci pour votre réponse.

    Après plusieurs recherches sur le Net voici la solution que j'ai utilisée.

    J’ai remarqué que dans mon processus concerné le thread à l’indice 0 correspondait à ma fenêtre principale.

    Je transmets donc, l'Id du thread à la fonction EnumThreadWindows (API) et à l'aide d'une fonction de rappelle, je récupère les handles des fenêtres associées au thread.

    Dans la fonction de rappelle, à l'aide des APIs IsWindowVisible et GetWindowTextLength, je vérifie que les handles correspondent à des fenêtres visibles.

    Ensuite, à l'aide de l'API SendMessage, j'envoie une commande de fermeture aux fenêtres.

    La commande de fermeture du SendMessage me permet de passer par l’événement MyBase.Closed et d’exécuter ma tâche de sauvegarde.

    Après fermeture de toutes les fenêtres, j’utilise la méthode Process.Kill pour mettre fin à mon application.

    Vous pouvez apercevoir le code de mon programme sans les déclarations des APIs ci-dessous.

    Jacky

    Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
    
            'Lors du double click sur l'icone du bureau :
            '   Démarre le programme si le programme n'est pas en cours
            '   Stoppe le programme si celui-ci est en cours
    
            Dim ProcessFrame() As Process
    
            'Vérifie si un processus d'application du programme est déjà en cours
            ProcessFrame = Process.GetProcessesByName("FrameDesktop")
    
            If ProcessFrame.Count = 1 Then
    
                'Ouvre la fenêtre principale du programme de gestion des cadres
                Dim MainWindow As MainWindow = New MainWindow()
                MainWindow.Show()
    
            Else
                'Récupère le processus actif
                Dim processActif As Process = Process.GetCurrentProcess
    
                'Récupère tous les processus ouverts de gestion des cadres
                ProcessFrame = Process.GetProcessesByName("FrameDesktop")
    
                'Parcours les processus ouverts de gestion des cadres
                For Each ProcessItem As Process In ProcessFrame
    
                    'Vérifie si le processus à fermer n'est pas le processus en cours
                    If ProcessItem.Id <> processActif.Id Then
    
                        'Récupère l'identifiant du thread de la fenêtre de démarrage du processus en cours à l'indice 0
                        Dim idThread As UInteger = CUInt(ProcessItem.Threads(0).Id)
    
                        'Va récupèrer le handle des fenêtres associées au thread et les fermer
                        EnumThreadWindows(idThread, AddressOf EnumThreadWndProc, IntPtr.Zero)
    
                        'Détruit le processus
                        ProcessItem.Kill()
    
                    End If
                Next
    
                'Ferme le programme demandant une nouvelle ouverture
                Application.Current.Shutdown()
    
            End If
    
        End Sub
    
        Function EnumThreadWndProc(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    
            'Récupère le handle de la fenêtre associée au thread
    
            Const WM_SYSCOMMAND As Integer = &H112
            Const SC_CLOSE As UInt32 = &HF060
    
            'Vérifie si la fenêtre est visible
            If Not IsWindowVisible(hwnd) Then
                Return True
            End If
    
            'Vérifie si la fenêtre contient un titre
            Dim length As Integer = GetWindowTextLength(hwnd)
            If (length = 0) Then
                Return True
            End If
    
            'Ferme la fenêtre
            SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0)
    
            Return True
    
        End Function



    mardi 3 mars 2020 10:57

Toutes les réponses

  • Le Task Manager utilise EnumDesktopWindows

    pour énumérer toutes les fenêtres, puis les filtre (selon style (Visible principalement pour "Applications") et style étendu)

    Pour un process/thread donné, on peut faire avec EnumThreadWindows

    (GetWindowThreadProcessId pour récupérer le thread ou PID d'une fenêtre)


    dimanche 1 mars 2020 10:36
  • Bonjour Jacky Perpète,

    Merci d’avoir contacté les forums MSDN France. La langue utilisée sur ces forums est la langue Française, donc s’il vous plaît modifiez votre premier message, comme on vous demande dans l’étiquette sur les forums MSDN France.
    Merci pour votre compréhension et collaboration.

    Cordialement,
    Nina


    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    lundi 2 mars 2020 08:27
    Modérateur
  • Bonjour,

    Merci pour votre réponse.

    Après plusieurs recherches sur le Net voici la solution que j'ai utilisée.

    J’ai remarqué que dans mon processus concerné le thread à l’indice 0 correspondait à ma fenêtre principale.

    Je transmets donc, l'Id du thread à la fonction EnumThreadWindows (API) et à l'aide d'une fonction de rappelle, je récupère les handles des fenêtres associées au thread.

    Dans la fonction de rappelle, à l'aide des APIs IsWindowVisible et GetWindowTextLength, je vérifie que les handles correspondent à des fenêtres visibles.

    Ensuite, à l'aide de l'API SendMessage, j'envoie une commande de fermeture aux fenêtres.

    La commande de fermeture du SendMessage me permet de passer par l’événement MyBase.Closed et d’exécuter ma tâche de sauvegarde.

    Après fermeture de toutes les fenêtres, j’utilise la méthode Process.Kill pour mettre fin à mon application.

    Vous pouvez apercevoir le code de mon programme sans les déclarations des APIs ci-dessous.

    Jacky

    Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
    
            'Lors du double click sur l'icone du bureau :
            '   Démarre le programme si le programme n'est pas en cours
            '   Stoppe le programme si celui-ci est en cours
    
            Dim ProcessFrame() As Process
    
            'Vérifie si un processus d'application du programme est déjà en cours
            ProcessFrame = Process.GetProcessesByName("FrameDesktop")
    
            If ProcessFrame.Count = 1 Then
    
                'Ouvre la fenêtre principale du programme de gestion des cadres
                Dim MainWindow As MainWindow = New MainWindow()
                MainWindow.Show()
    
            Else
                'Récupère le processus actif
                Dim processActif As Process = Process.GetCurrentProcess
    
                'Récupère tous les processus ouverts de gestion des cadres
                ProcessFrame = Process.GetProcessesByName("FrameDesktop")
    
                'Parcours les processus ouverts de gestion des cadres
                For Each ProcessItem As Process In ProcessFrame
    
                    'Vérifie si le processus à fermer n'est pas le processus en cours
                    If ProcessItem.Id <> processActif.Id Then
    
                        'Récupère l'identifiant du thread de la fenêtre de démarrage du processus en cours à l'indice 0
                        Dim idThread As UInteger = CUInt(ProcessItem.Threads(0).Id)
    
                        'Va récupèrer le handle des fenêtres associées au thread et les fermer
                        EnumThreadWindows(idThread, AddressOf EnumThreadWndProc, IntPtr.Zero)
    
                        'Détruit le processus
                        ProcessItem.Kill()
    
                    End If
                Next
    
                'Ferme le programme demandant une nouvelle ouverture
                Application.Current.Shutdown()
    
            End If
    
        End Sub
    
        Function EnumThreadWndProc(ByVal hwnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    
            'Récupère le handle de la fenêtre associée au thread
    
            Const WM_SYSCOMMAND As Integer = &H112
            Const SC_CLOSE As UInt32 = &HF060
    
            'Vérifie si la fenêtre est visible
            If Not IsWindowVisible(hwnd) Then
                Return True
            End If
    
            'Vérifie si la fenêtre contient un titre
            Dim length As Integer = GetWindowTextLength(hwnd)
            If (length = 0) Then
                Return True
            End If
    
            'Ferme la fenêtre
            SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0)
    
            Return True
    
        End Function



    mardi 3 mars 2020 10:57