none
Manipulation Logiciel avec des API RRS feed

  • Question

  • Bonjour,

    je doit effectuer des traitement qui nécessite adobe acrobat. j'ai regarder ave une manipulation OLE, mais il n'on pas implementer les fonctionnalité nécessaire.

    La seul solution qu'il me reste est de manipuler l'interface avec des API, cela fait longtemps que je n'est pa fait cette exercice et je suis un peu perdu.

    Je souaite cliquer sur un menu en particulier, ce qui ouvrira une fenetre, modifier des element dedans (un combo et une textbox) puis ensuite cliquer sur le bouton ok.

    J'arrive a retrouver le Handel de l'application comme sa :

      For Each p As Process In Process.GetProcesses

                If p.ProcessName.ToLower = "acrobat" Then

                    AddText("ID=" & p.Id)
                    AddText(p.MainWindowTitle & " = " & p.ProcessName)

                    AddText("Menu ID : " & NativeMethods.GetMenu(p.Handle).ToString)

                End If

            Next

    mais le menu de l'application me retourne toujours un handel vide (egale à 0) 

    je supose que je doit d'abort trouver la fenetre principal de acrobat ... mais impossible de faire marcher l'api.

    j'a créé une class avec des fonctions, mais je n'arrive pas a recuperer la premiere fenetre active ...

    est ce que qq aurait une piste ?

    Merci,

    Imports System.Runtime.InteropServices

    Public Class NativeMethods

        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Public Shared Function FindWindow( _
         ByVal lpClassName As String, _
         ByVal lpWindowName As StringAs IntPtr
        End Function

        <DllImport("user32.dll", EntryPoint:="FindWindow", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Public Shared Function FindWindowByClass( _
         ByVal lpClassName As String, _
         ByVal zero As IntPtrAs IntPtr
        End Function

        <DllImport("user32.dll", EntryPoint:="FindWindow", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Public Shared Function FindWindowByCaption( _
         ByVal zero As IntPtr, _
         ByVal lpWindowName As StringAs IntPtr
        End Function

        <DllImport("User32.dll")> _
        Public Shared Function EnumChildWindows _
            (ByVal WindowHandle As IntPtrByVal Callback As EnumWindowProcess, _
            ByVal lParam As IntPtrAs Boolean
        End Function

        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Public Shared Function GetWindowText(ByVal hwnd As IntPtrByVal lpString As System.Text.StringBuilderByVal cch As IntegerAs Integer
        End Function

        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Public Shared Function GetWindowTextLength(ByVal hwnd As IntPtrAs Integer
        End Function

        <DllImport("user32.dll", CharSet:=CharSet.Auto)> Public Shared Function GetMenu(ByVal hWnd As IntPtrAs IntPtr
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function EnumWindows(ByVal lpEnumFunc As EnumWindowProcessByVal lParam As IntPtrAs Boolean
        End Function

        Public Delegate Function EnumWindowProcess(ByVal Handle As IntPtrByVal Parameter As IntPtrAs Boolean

       


    End Class

    Public Class API

        Public Shared Function GetText(ByVal hWnd As IntPtrAs String
            Dim length As Integer
            If hWnd.ToInt32 <= 0 Then
                Return Nothing
            End If
            length = NativeMethods.GetWindowTextLength(hWnd)
            If length = 0 Then
                Return Nothing
            End If
            Dim sb As New System.Text.StringBuilder("", length + 1)

            NativeMethods.GetWindowText(hWnd, sb, sb.Capacity)
            Return sb.ToString()
        End Function



        Public Shared Function GetChildWindows(ByVal ParentHandle As IntPtrAs IntPtr()
            Dim ChildrenList As New List(Of IntPtr)
            Dim ListHandle As GCHandle = GCHandle.Alloc(ChildrenList)
            Try
                NativeMethods.EnumChildWindows(ParentHandle, AddressOf EnumWindow_Get, GCHandle.ToIntPtr(ListHandle))
            Finally
                If ListHandle.IsAllocated Then ListHandle.Free()
            End Try
            Return ChildrenList.ToArray
        End Function

        Private Shared Function EnumWindow_Get(ByVal Handle As IntPtrByVal Parameter As IntPtrAs Boolean
            Dim ChildrenList As List(Of IntPtr) = GCHandle.FromIntPtr(Parameter).Target
            If ChildrenList Is Nothing Then Throw New Exception("GCHandle Target could not be cast as List(Of IntPtr)")
            ChildrenList.Add(Handle)
            Return True
        End Function

        Public Shared Function WindowsText_Get(ByVal hWnd As IntPtrAs String

            Try

                Dim length As Integer
                If hWnd.ToInt32 <= 0 Then
                    Return Nothing
                End If
                length = NativeMethods.GetWindowTextLength(hWnd)
                If length = 0 Then
                    Return Nothing
                End If

                Dim sb As New System.Text.StringBuilder("", length + 1)

                NativeMethods.GetWindowText(hWnd, sb, sb.Capacity)

                Return sb.ToString()

            Catch ex As Exception
                Throw New Exception("Error in WindowsText_Get : ", ex)
            End Try

        End Function
    End Class

    Cordialement Sébastien DataBase2Code
    mercredi 5 janvier 2011 16:06

Réponses

  • Bonjour,

    Mon message précédent n'apparait pas ? J'ai testé sur Notepad avec Process.MainWindowHandle au lieu de Process.Handle et GetMenu me retourne bien une valeur.

    Selon ce que l'on veut faire il est possible qu'utiliser http://msdn.microsoft.com/fr-fr/library/ms747327.aspx soit plus facile ? J'avais juste testé il y a qq temps par curiosité mais elle permet à priori d'examiner et manipuler assez facilement les interfaces utilisateurs des applications Windows avec une API de plus haut niveau.

     


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    • Proposé comme réponse Alex Petrescu vendredi 7 janvier 2011 14:17
    • Marqué comme réponse Alex Petrescu lundi 10 janvier 2011 10:03
    mercredi 5 janvier 2011 17:33
    Modérateur

Toutes les réponses

  • Bonjour,

    Cela donne quoi en essayant http://msdn.microsoft.com/en-us/library/system.diagnostics.process.mainwindowhandle.aspx au lieu de Process.Handle ?

     


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mercredi 5 janvier 2011 17:19
    Modérateur
  • Bonjour,

    Mon message précédent n'apparait pas ? J'ai testé sur Notepad avec Process.MainWindowHandle au lieu de Process.Handle et GetMenu me retourne bien une valeur.

    Selon ce que l'on veut faire il est possible qu'utiliser http://msdn.microsoft.com/fr-fr/library/ms747327.aspx soit plus facile ? J'avais juste testé il y a qq temps par curiosité mais elle permet à priori d'examiner et manipuler assez facilement les interfaces utilisateurs des applications Windows avec une API de plus haut niveau.

     


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    • Proposé comme réponse Alex Petrescu vendredi 7 janvier 2011 14:17
    • Marqué comme réponse Alex Petrescu lundi 10 janvier 2011 10:03
    mercredi 5 janvier 2011 17:33
    Modérateur
  • Bonjour,

    Merci j'ai tester et sa marche !!! maintenant j'ai un probleme plus bas,

    je n'arrive pas a recuperer le text d'un sous menu (ceci afin de fair un clique par raport a son nom)

    j'ai essayer avec le handel du sous menu ou son ItemID, j'ai egalement essayer en recuperant la structure info, je n'arrive pas a le recupere

    pourtant les handel son bon ! lorsque je remplace la fonction avec comparaison par le nom par sa position le bon menu est cliquer !!!!

    est ce que qq vois pouquoi je n'arrive pas a recupere le text de mon sous menu ?

    Voici le code :


        Public Shared Sub sRunMenuItem(ByVal pHandel As IntPtr)
            Dim hWnd As IntPtr, hMenu As IntPtr, hSubMenu As IntPtr
            Dim sBuffer As New System.Text.StringBuilder(255), iMenu As Integer, iCmd As Integer
            Dim vMenu As String = "Fichier"
            Dim vItem As String = "Quitter"
            Dim vTemp As String = ""

            hWnd = pHandel

            hMenu = NativeMethods.GetMenu(hWnd)

            For iMenu = 0 To NativeMethods.GetMenuItemCount(hMenu) - 1

                NativeMethods.GetMenuString(hMenu, iMenu, sBuffer, 255, NativeMethods.MF_BYPOSITION)
                Dim lNomMenu As String
                lNomMenu = sBuffer.ToString.Replace("&""").Replace(Chr(0), "")

                If lNomMenu = vMenu Or True Then

                    hSubMenu = NativeMethods.GetSubMenu(hMenu, iMenu)
               
                    For iCmd = 0 To NativeMethods.GetMenuItemCount(hSubMenu) - 1

                        sBuffer = New System.Text.StringBuilder(255)
                        Dim iDItem As Integer
                        iDItem = NativeMethods.GetMenuItemID(hSubMenu, iCmd)
                        If iDItem >= 0 Then

                            Dim lInfo As NativeMethods.MENUINFO

                            Dim lRet As Integer = NativeMethods.GetMenuInfo(hMenu, lInfo)

                            Dim lNbChrCopier As Integer = NativeMethods.GetMenuString(hSubMenu, iDItem, sBuffer, 255, NativeMethods.MF_BYCOMMAND)

                            Dim lNomSousMenu As String
                            lNomSousMenu = sBuffer.ToString.Replace("&""").Replace(Chr(0), "").Replace(Chr(9), "")

                            If lNomSousMenu = vItem Or lNomSousMenu = vItem Then
                                NativeMethods.SendMessage(hWnd, NativeMethods.WM_COMMAND, NativeMethods.GetMenuItemID(hSubMenu, iCmd), 0)
                                Exit Sub
                            End If

                        End If

                    Next
                End If
            Next
            MsgBox("Menu item not found!")
        End Sub

    Cordialement Sébastien DataBase2Code
    jeudi 6 janvier 2011 09:30
  • Que donne un pas à pas ? La valeur de retour de lNbChrCopier est-elle correcte ? Je ne suis pas sûr de comprendre si le premier appel à GetMenuString est ok mais pas le deuxième ou si aucun des deux n'est bon (dans ce cas, la déclaration de GetMenuString pourrait elle être en cause ?).

    En l'absence d'erreur franche et si le pas à pas ne donne rien, le plus simple est sans doute de faire un exemple à la fois :
    - complet (avec la déclaration des appels Win32) pour que qq puisse le tester sans perdre de temps après un simple copier/coller
    - le plus court possible (par exemple ici si le premier appel de GetMenuString ne donne pas le nom attendu il est suffisant pour montrer le problème et le reste ne sert à rien. La boucle même est inutile si on récupère "Fichier" par sa position, SendMessage ne fait pas partie du problème etc...)

    Cela permet souvent de trouver le problème. Sinon cela permet d'avoir un exemple complet et simple que qq d'autre pourra examiner après un simple copier/coller et sans voir aucune ligne de code qui n'est pas destinée à se mettre dans la situation où le problème se produit.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    jeudi 6 janvier 2011 12:41
    Modérateur
  • Bonjour,

    Le premier GetmenuString retourne la bonne valeur, mais le deuxieme retourne une chaine vide (lNbChrCopier = 0 en retour)

    c'est pour cela que je supose que l'api est bien declarer et correctement utiliser dans le premier appelle.

    Dans le deuxieme appelle pour le nom, j'ai essayer par position ordinal et par ItemID, de plus j'ai essayer de recuperer les MenuIno et SubMenuInfo, il sont tous vide,

    je me demande si adobe n'a pas bricoler ces sous menu a leur sauce (il redessine le tout), malgrer que les menus existe (si je fait le sendmessage avec une position ordinal le bon sous menu s'execute ... ce qui laisse a penser que le handel du sous menu est egalement bon ...)

    Demain je vous poste un code complet et fonctionnelle,

    Merci de vous pencher sur le probleme.


    Cordialement Sébastien DataBase2Code
    jeudi 6 janvier 2011 16:55
  • Par exemple le code ci-dessous semble bien m'énumerer les sous-menus de Notepad (qui doit être ouvert bien sûr).

    Option Strict On
    Imports System.Runtime.InteropServices
    Imports System.Text
    
    Public Class Form1
    
      Class NativeMethods
        Public Const MF_BYCOMMAND As Long = 0
        Public Const MF_BYPOSITION As Long = &H400
        <DllImport("user32.dll")> _
        Public Shared Function GetSubMenu(ByVal hMenu As IntPtr, ByVal nPos As Integer) As IntPtr
        End Function
        <DllImport("user32.dll")> _
        Public Shared Function GetMenu(ByVal hWnd As IntPtr) As IntPtr
        End Function
        <DllImport("user32.dll")>
        Public Shared Function GetMenuItemCount(ByVal hMenu As IntPtr) As Integer
        End Function
        <DllImport("user32.dll")>
        Public Shared Function GetMenuString(ByVal hMenu As IntPtr, ByVal uIDItem As Integer, <Out(), MarshalAs(UnmanagedType.LPStr)> ByVal lpString As StringBuilder, ByVal nMaxCount As Integer, ByVal uFlag As Integer) As Integer
        End Function
      End Class
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Debug.WriteLine(Now.ToString)
        Dim hWnd As IntPtr, hMenu As IntPtr, hSubMenu As IntPtr
        Dim sBuffer As New System.Text.StringBuilder(255)
        hWnd = Diagnostics.Process.GetProcessesByName("notepad")(0).MainWindowHandle
        hMenu = NativeMethods.GetMenu(hWnd)
        For iMenu As Integer = 0 To NativeMethods.GetMenuItemCount(hMenu) - 1
          hSubMenu = NativeMethods.GetSubMenu(hMenu, iMenu)
          For iSubMenu As Integer = 0 To NativeMethods.GetMenuItemCount(hSubMenu) - 1
            NativeMethods.GetMenuString(hSubMenu, iSubMenu, sBuffer, sBuffer.Capacity, NativeMethods.MF_BYPOSITION)
            Debug.WriteLine(sBuffer)
          Next
        Next
      End Sub
    End Class
    

    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    jeudi 6 janvier 2011 17:49
    Modérateur