Meilleur auteur de réponses
Fermer les fenêtres d'une application distante à l'aide de processus ou autres sans fenêtre principale

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
- Modifié Jacky Perpète mardi 3 mars 2020 10:16
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
- Modifié Jacky Perpète mardi 3 mars 2020 11:00
- Marqué comme réponse Jacky Perpète mardi 3 mars 2020 11:02
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)
- Modifié Castorix31 dimanche 1 mars 2020 10:37
-
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.
-
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
- Modifié Jacky Perpète mardi 3 mars 2020 11:00
- Marqué comme réponse Jacky Perpète mardi 3 mars 2020 11:02