Hola a todos.
Si tengo una aplicación como por ejemplo la calculadora donde todos los botones son la clase "Button", como puedo recorrer todos los botones y saber en cada momento en el botón que estoy.
Muchas gracias por anticipado.
Hola
Por decucción, como has titulado el asunto como "
Spy++", supongo que te refieres a la
Calculadora de Windows accediendo a ella desde tu apliación. En Spy++ al hacer clic en
"+" correspondiente a la Calculadora se despliega un árbol donde aparecen todos los handles y textos de cada botón. De modo que cada botón tiene un
Handle (un número aleatório identificativo) y una etiqueta o texto "1","2", "Bin","hyp", "=", etc.
Para recorrer los botones primero se obtiene el
handle de la calculadora con la declaración API
FindWindow, después el handle del PRIMER botón con
FindWindowEx, y para ir recorriendo los siguientes botones se usa
GetWindow y el comando
GW_HWNDNEXT.
Para saber si estás en un determinado botón obtienes su etiquieta o texto con
GetWindowText, así si estás en "5" obtienes "5".
Aquí te dejo un plantilla de ejemplo, que recorre todos los botones e introduce el nombre de cada uno en un ListBox. Además, al pasar el cursor por los botones de la calculadora muestra en un Label el botón donde se encuentra el cursor.
Necesitas un
Botón, un
Label , un
ListBox y un control
TimerEn un Form:
EN VB6
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Private Const WM_SYSCOMMAND = &H112
Private Const SC_CLOSE = &HF060&
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, _
ByVal hWnd2 As Long, _
ByVal lpsz1 As String, _
ByVal lpsz2 As String) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hwnd As Long, _
ByVal lpString As String, _
ByVal cch As Long) As Long
Private Type POINTAPI
x As Long
y As Long
End Type
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPointXY Lib "user32" Alias "WindowFromPoint" _
(ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
'Para recorrer todos los botones
Private Declare Function GetWindow Lib "user32" _
(ByVal hwnd As Long, _
ByVal wCmd As Long) As Long
Private Const GW_CHILD = 5
Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDLAST = 1
Private Const GW_HWNDNEXT = 2
Private Const GW_HWNDPREV = 3
Private Const GW_MAX = 5
Private Const GW_OWNER = 4
Private Sub Command1_Click()
Shell "Calc", vbNormalFocus
Timer1.Enabled = True
RecorrerBotones
End Sub
Public Function TextoBoton() As String
Dim pt32 As POINTAPI
Dim ptx As Long
Dim pty As Long
Dim x As Long
Dim hw As Long
Dim hWndParent As Long
Dim TextWindow As String * 100
Call GetCursorPos(pt32) ' obtiene la posición del cursor
ptx = pt32.x
pty = pt32.y
hw = WindowFromPointXY(ptx, pty) ' Obtiene el handle debajo del cursor
hWndParent = GetParent(hw) ' Consigue el handle padre de una ventana
x = GetWindowText(hWndParent, TextWindow, 100) 'Obtiene el texto de la ventana
If Left(TextWindow, x) = "Calculadora" Then
x = GetWindowText(hw, TextWindow, 100) 'Obtiene el texto de un botón
TextoBoton = Left(TextWindow, x)
End If
End Function
Private Sub Form_Load()
Timer1.Enabled = False
Command1.Caption = "Abrir calculadora"
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim hw As Long
hw = FindWindow("SciCalc", vbNullString)
SendMessage hw, WM_SYSCOMMAND, SC_CLOSE, &H0 'Cierra la calculadora
End
End Sub
Private Sub Timer1_Timer()
'Para obtener el texto del botón donde se encuentra el cursor
Label1.Caption = TextoBoton
Me.Caption = TextoBoton
End Sub
Public Sub RecorrerBotones()
Dim hw As Long
Dim x As Long
Dim TextWindow As String * 100
hw = FindWindow("SciCalc", vbNullString)
hw = FindWindowEx(hw, &H0, "Button", vbNullString) 'obtiene el primer handle de un botón
Do While Left(TextWindow, x) <> "C "
hw = GetWindow(hw, GW_HWNDNEXT) '<--- Esto permite obtener y pasar al siguiente Handle de la lista
x = GetWindowText(hw, TextWindow, 100) 'Obtiene el texto de un botón
If x > 0 Then
List1.AddItem Left(TextWindow, x)
End If
DoEvents
Loop
End Sub
EN VB.NET
Imports VB = Microsoft.VisualBasic
Public Class Form1
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Integer, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByRef lParam As Object) As Integer
Private Const WM_SYSCOMMAND = &H112
Private Const SC_CLOSE = &HF060&
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Integer
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Integer, _
ByVal hWnd2 As Integer, _
ByVal lpsz1 As String, _
ByVal lpsz2 As String) As Integer
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hwnd As Integer, _
ByVal lpString As String, _
ByVal cch As Integer) As Integer
Structure POINTAPI
Dim X As Integer
Dim Y As Integer
End Structure
Declare Function GetCursorPos Lib "user32" (ByRef lpPoint As POINTAPI) As Integer
Private Declare Function WindowFromPointXY Lib "user32" Alias "WindowFromPoint" _
(ByVal xPoint As Integer, ByVal yPoint As Integer) As Integer
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Integer) As Integer
'Para recorrer todos los botones
Private Declare Function GetWindow Lib "user32" _
(ByVal hwnd As Integer, _
ByVal wCmd As Integer) As Integer
Private Const GW_CHILD = 5
Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDLAST = 1
Private Const GW_HWNDNEXT = 2
Private Const GW_HWNDPREV = 3
Private Const GW_MAX = 5
Private Const GW_OWNER = 4
Public Function TextoBoton() As String
Dim pt32 As POINTAPI
Dim ptx As Long
Dim pty As Long
Dim x As Long
Dim hw As Long
Dim hWndParent As Long
Dim TextWindow As String
TextoBoton = ""
TextWindow = Space(100)
Call GetCursorPos(pt32) ' obtiene la posición del cursor
ptx = pt32.X
pty = pt32.Y
hw = WindowFromPointXY(ptx, pty) ' Obtiene el handle debajo del cursor
hWndParent = GetParent(hw) ' Consigue el handle padre de una ventana
x = GetWindowText(hWndParent, TextWindow, 100) 'Obtiene el texto de la ventana
If VB.Left(TextWindow, x) = "Calculadora" Then
x = GetWindowText(hw, TextWindow, 100) 'Obtiene el texto de un botón
TextoBoton = VB.Left(TextWindow, x)
End If
Return TextoBoton
End Function
Public Sub RecorrerBotones()
Dim hw As Long
Dim x As Long
Dim TextWindow As String
TextWindow = Space(100)
hw = FindWindow("SciCalc", vbNullString)
hw = FindWindowEx(hw, &H0, "Button", vbNullString) 'obtiene el primer handle de un botón
Do While VB.Left(TextWindow, x) <> "C "
hw = GetWindow(hw, GW_HWNDNEXT) '<--- Esto permite obtener y pasar al siguiente Handle de la lista
x = GetWindowText(hw, TextWindow, 100) 'Obtiene el texto de un botón
If x > 0 Then
ListBox1.Items.Add(VB.Left(TextWindow, x))
End If
Application.DoEvents()
Loop
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Dim hw As Long
hw = FindWindow("SciCalc", vbNullString)
SendMessage(hw, WM_SYSCOMMAND, SC_CLOSE, &H0) 'Cierra la calculadora
End
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Timer1.Enabled = False
Timer1.Interval = 1
Button1.Text = "Abrir calculadora"
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Shell("Calc", vbNormalFocus)
Timer1.Enabled = True
RecorrerBotones()
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
'Para obtener el texto del botón donde se encuentra el cursor
Label1.Text = TextoBoton()
Me.Text = TextoBoton()
End Sub
End Class