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 :

Faire [TAB] sur un .exe qui n'est pas en premier plan (Sendmessage?)


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2016
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2016
    Messages : 33
    Par défaut Faire [TAB] sur un .exe qui n'est pas en premier plan (Sendmessage?)
    Bonjour tout le monde,


    Je cherche à contrôler un executable dont la fenêtre n'est pas en premier plan (c'est à dire qu'il est ouvert, mais le client fait autre chose).
    J'ai réussi à changer du texte en utilisant cette méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dim iHwnd As IntPtr = FindWindow("notepad", Nothing)
    Dim iHwndChild As IntPtr = FindWindowEx(iHwnd, IntPtr.Zero, "edit", Nothing)
    SendMessage(iHwndChild, WM_SETTEXT, 0, "Texte injecté par mon executable")
    Maintenant j'aimerais faire pareil avec [TAB] [ENTER] etc etc. Malgré avoir épluché le web pendant une journée je n'y arrive vraiment pas .... (J'ai d'ailleurs crée un exectuable test avec des boutons seulement pour voir si ça marchait.
    Voici un de mes essai:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Dim iHwnd As IntPtr = FindWindow("notepad", Nothing)
    SendMessage(iHwnd, WM_KEYDOWN, VK_TAB, 0)
    Est-ce que quelqu'un sait pourquoi je n'y parviens s'il vous plaît?

    Merci d'avance

  2. #2
    Membre Expert
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Billets dans le blog
    7
    Par défaut
    Bonjour,

    Dans ton titre tu dis que le programme n'est pas en premier plan donc pourquoi ne pas s'orienter dans un premier temps vers la fonction API qui mets ton appli en premier plan pour pouvoir travailler avec :

    http://pinvoke.net/default.aspx/user...regroundWindow

    Si tu veux persister dans l'automatisation/le pilotage d'application alors je te suggère d'éplucher les fonctions API natives : http://pinvoke.net/index.aspx

    Ensuite lorsque ta fenêtre possède le focus alors tu appelles la methode SendKeys :

    puis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SendKeys.Send("{ENTER}")
    PS : Un outil bien pratique pour connaitre les noms de classe d'une fenêtre, ...etc... : SPY++

    A+

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2016
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2016
    Messages : 33
    Par défaut
    Merci de ta réponse Wallace1

    Je connaissais la fonction SendKeys, mais je n'aime pas trop dans la mesure où je veux que l'executable contrôlé reste en arrière plan.

    Ceci étant dit, est ce que pourra m'aider? Car pour l'instant je ne vois pas en quoi ça peut faire un {TAB} ou{ENTER}.

    Encore merci de ton aide.

  4. #4
    Membre Expert
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par Sodruza Voir le message
    Merci de ta réponse Wallace1

    Je connaissais la fonction SendKeys, mais je n'aime pas trop dans la mesure où je veux que l'executable contrôlé reste en arrière plan.

    Ceci étant dit, est ce que pourra m'aider? Car pour l'instant je ne vois pas en quoi ça peut faire un {TAB} ou{ENTER}.

    Encore merci de ton aide.
    Bien sure que cela va t'aider car il existe la fonction API PostMessage et les constantes WM_KEYDOWN, WM_KEYUP, VK_TAB !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


    A+

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2016
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2016
    Messages : 33
    Par défaut
    Justement, j'avais déjà essayé les 2 fonctions postmessage et sendmessage => Sans aucun résultat:

    Déclarations
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean
    End Function
     
    Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
     
    Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
     
    Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As IntPtr, ByVal hWnd2 As IntPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As IntPtr
     
     
    Const VK_TAB As Integer = &H9
    Const WM_KEYDOWN As Integer = &H100
    Const WM_KEYUP As Integer = &H101
    Essai 1:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dim iHwnd As IntPtr = FindWindow("FichierTest", Nothing)
    SendMessage(iHwnd, WM_KEYDOWN, VK_TAB, 0) 'ne marche pas
    SendMessage(iHwnd, WM_KEYUP, VK_TAB, 0)
    Essai 2:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dim iHwnd As IntPtr = FindWindow("FichierTest", Nothing)
    PostMessage(iHwnd, WM_KEYDOWN, VK_TAB, 0)
    PostMessage(iHwnd, WM_KEYUP, VK_TAB, 0)
    L'executable s'appelle bien "FichierTest" car iHwnd a effectivement une valeur. (c'est un .exe contenant 2 boutons, pour voir si la touche {TAB} a marché)


    Y a t'il quelque chose que j'ai fait de travers? car sur les autres forums (car j'ai déjà cherché sur d'autres forums) ça marcherait ... Mais pas ici.

  6. #6
    Membre Expert
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Billets dans le blog
    7
    Par défaut
    Bon très bien visiblement tu ne connais pas le fonctionnement du système d'exploitation Windows (fenêtré) :

    Pour l'exemple j'ai codé une application type Windows Forms (Framework 4.0 ciblé) nommée "TestApp" dans laquelle j'ai ajouté 2 boutons (Button1 et Button2).
    Lorsqu'on clique sur Button1 ça affiche une msgBox.

    ---> Dans un premier temps on récupère le handle du processus et on vérifie qu'il existe bien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Dim processes As Process() = Process.GetProcessesByName("TestApp")
    If Not processes Is Nothing AndAlso Not processes.Length = 0 Then
          Dim hwnd As IntPtr = processes(0).MainWindowHandle
     
    End If
    ---> Ensuite on énumère toutes les fenêtre enfants du processus (ce qui permet de récupérer tous les handle des contrôles du processus parent) :

    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
     
     <DllImport("user32.dll")>
        Private Shared Function EnumChildWindows(window As IntPtr, callback As EnumWindowProc, i As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
     
      Private Delegate Function EnumWindowProc(hWnd As IntPtr, parameter As IntPtr) As Boolean
     
      Private Shared Function ChildWindowsFromHandle(parent As IntPtr) As List(Of IntPtr)
            Dim result As New List(Of IntPtr)()
            Dim listHandle As GCHandle = GCHandle.Alloc(result)
            Try
                Dim childProc As New EnumWindowProc(AddressOf EnumWindowFromHandle)
                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle))
            Finally
                If listHandle.IsAllocated Then
                    listHandle.Free()
                End If
            End Try
            Return result
        End Function
     
       Private Shared Function EnumWindowFromHandle(handle As IntPtr, pointer As IntPtr) As Boolean
            Dim gch As GCHandle = GCHandle.FromIntPtr(pointer)
            Dim list As List(Of IntPtr) = TryCast(gch.Target, List(Of IntPtr))
            If list Is Nothing Then
                Throw New InvalidCastException("La cible de GCHandle ne peut pas être castée en type List<IntPtr>")
            End If
            list.Add(handle)
            Return True
        End Function
    Ce qui nous donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     Dim processes As Process() = Process.GetProcessesByName("TestApp")
            If Not processes Is Nothing AndAlso Not processes.Length = 0 Then
                Dim hwnd As IntPtr = processes(0).MainWindowHandle
                For Each wind In ChildWindowsFromHandle(hwnd)
     
                Next
            End If
    ---> On implémente 2 fonctions permettant de récupérer le titre d'une fenêtre et son nom de classe :

    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
     
     <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
        Private Shared Function GetClassName(hwnd As IntPtr, lpClassName As StringBuilder, nMaxCount As Long) As Long
        End Function
     
        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
        Private Shared Function GetWindowTextLength(hWnd As IntPtr) As Integer
        End Function
     
        <DllImport("user32.dll")>
        Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
        End Function
     
       Private Function CaptionFromHandle(hwnd As IntPtr) As String
            Dim cName As String = String.Empty
            Dim cText As StringBuilder = Nothing
            Try
                Dim cLength As Integer = GetWindowTextLength(hwnd)
                cText = New StringBuilder(String.Empty, cLength + 5)
                GetWindowText(hwnd, cText, cLength + 2)
                If Not String.IsNullOrEmpty(cText.ToString()) AndAlso
                    Not String.IsNullOrWhiteSpace(cText.ToString()) Then
                    cName = cText.ToString()
                End If
            Catch ex As Exception
                cName = ex.Message
            Finally
                cText = Nothing
            End Try
            Return cName
        End Function
     
        Private Function ClassNameFromHandle(hwnd As IntPtr) As String
            Dim cName As String = String.Empty
            Dim cText As StringBuilder = Nothing
            Try
                Dim cLength As Integer = 1000
                cText = New StringBuilder(String.Empty, cLength + 5)
                GetClassName(hwnd, cText, cLength + 2)
                If Not String.IsNullOrEmpty(cText.ToString()) AndAlso
                    Not String.IsNullOrWhiteSpace(cText.ToString()) Then
                    cName = cText.ToString()
                End If
            Catch ex As Exception
                cName = ex.Message
            Finally
                cText = Nothing
            End Try
            Return cName
        End Function
    ---> Si je souhaite simuler la touche ENTRER sur le Button1 je procède ainsi :

    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
     
     <DllImport("user32.dll", SetLastError:=True)>
        Private Shared Function PostMessage(hWnd As IntPtr, Msg As UInteger, wParam As IntPtr, lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function
     
        Const WM_KEYDOWN As UInteger = &H100
        Const WM_KEYUP As UInteger = &H101
        Const VK_ENTER As Integer = &HD
     
      Dim processes As Process() = Process.GetProcessesByName("TestApp")
            If Not processes Is Nothing AndAlso Not processes.Length = 0 Then
                Dim hwnd As IntPtr = processes(0).MainWindowHandle
                For Each wind In ChildWindowsFromHandle(hwnd)
                    If CaptionFromHandle(wind) = "Button1" Then
                        PostMessage(wind, WM_KEYDOWN, CType(VK_ENTER, IntPtr), IntPtr.Zero)
                        PostMessage(wind, WM_KEYUP, CType(VK_ENTER, IntPtr), IntPtr.Zero)
                    End If
                Next
            End If
    ---> Au cas ou tu souhaiterais simuler la touche TAB sur le contrôle alors c'est comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
      Const VK_TAB As Integer = &H9
     
      Dim processes As Process() = Process.GetProcessesByName("TestApp")
            If Not processes Is Nothing AndAlso Not processes.Length = 0 Then
                Dim hwnd As IntPtr = processes(0).MainWindowHandle
                For Each wind In ChildWindowsFromHandle(hwnd)
                    If CaptionFromHandle(wind) = "Button2" Then
                        PostMessage(wind, WM_KEYDOWN, CType(VK_TAB, IntPtr), IntPtr.Zero)
                        PostMessage(wind, WM_KEYUP, CType(VK_TAB, IntPtr), IntPtr.Zero)
                    End If
                Next
            End If
    En espérant que ça sera instructif et que ta curiosité fera le reste

    PS1 : Dans le cas ou l'application avec laquelle tu souhaites interagir est développée en DotNet il est également possible d'utiliser "System.Reflection" pour simuler des clics etc.....

    PS2 : Sujet similaire

    ++

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 10/07/2011, 20h20
  2. pointeur sur un childframe qui n'est pas active
    Par moooona dans le forum MFC
    Réponses: 1
    Dernier message: 05/10/2010, 08h44
  3. Réponses: 3
    Dernier message: 01/06/2006, 17h26

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