Anyone know how I can click a button in another program, knowing the text (caption/title) on the button and of the window?
Printable View
Anyone know how I can click a button in another program, knowing the text (caption/title) on the button and of the window?
By sending BM_CLICK to the control. The following code will click the 8 button in Calculator.
VB Code:
Option Explicit Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" ( _ ByVal hWnd As Long, _ ByVal Msg As Long, _ wParam As Any, _ lParam As Any) As Long Private Declare Function SetActiveWindow Lib "user32.dll" ( _ ByVal hWnd As Long) As Long Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _ ByVal lpClassName As Any, _ ByVal lpWindowName As Any) As Long Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" ( _ ByVal hwndParent As Long, _ ByVal hwndChildAfter As Long, _ ByVal lpszClass As Any, _ ByVal lpszWindow As Any) As Long Private Const BM_CLICK As Long = &HF5 Private Sub Command1_Click() Dim appHandle As Long Dim buttonHandle As Long Dim retval As Long appHandle = FindWindow("SciCalc", vbNullString) If appHandle = 0 Then Exit Sub buttonHandle = FindWindowEx(appHandle, 0, CLng(0), "8") retval = SetActiveWindow(appHandle) retval = SendMessage(buttonHandle, BM_CLICK, ByVal CLng(0), ByVal CLng(0)) End Sub
I wrote a generic automation module to handle this exact type of thing. It has several helpful functions for automation, all of which are based on window and button captions. Copy the code into its own module and toss it into your project and you're all set.
To use dee-u's example of pressing the 8 button on the calculator, you'd simply call:
ClickButton "Calculator", "8"Code:Option Explicit
Public Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName 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 Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Private Declare Function IsWindowEnabled Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private mstrButton As String
Private mlngButton As Long
Public Function ButtonEnabled(pstrWindow As String, pstrButton As String) As Boolean
Const WS_DISABLED = &H8000000
Const GWL_STYLE = (-16)
Dim lngWindow As Long
Dim lngButton As Long
mstrButton = pstrButton
mlngButton = 0
lngWindow = FindWindow(vbNullString, pstrWindow)
If lngWindow <> 0 Then
EnumChildWindows lngWindow, AddressOf EnumChildProc, ByVal 0&
If mlngButton <> 0 Then ButtonEnabled = (IsWindowEnabled(mlngButton) = 1)
End If
End Function
Public Function ButtonExists(pstrWindow As String, pstrButton As String) As Boolean
Dim lngWindow As Long
Dim lngButton As Long
mstrButton = pstrButton
mlngButton = 0
lngWindow = FindWindow(vbNullString, pstrWindow)
If lngWindow <> 0 Then
EnumChildWindows lngWindow, AddressOf EnumChildProc, ByVal 0&
If mlngButton <> 0 Then ButtonExists = True
End If
End Function
Public Function ClickButton(pstrWindow As String, pstrButton As String) As Boolean
Const BM_CLICK As Long = &HF5&
Const WS_DISABLED = &H8000000
Const GWL_STYLE = (-16)
Dim lngWindow As Long
Dim lngParam1 As Long
Dim lngParam2 As Long
mstrButton = pstrButton
mlngButton = 0
lngWindow = FindWindow(vbNullString, pstrWindow)
If lngWindow <> 0 Then
EnumChildWindows lngWindow, AddressOf EnumChildProc, ByVal 0&
If mlngButton <> 0 Then
If IsWindowEnabled(mlngButton) = 1 Then
PostMessage mlngButton, BM_CLICK, 0, 0&
ClickButton = True
End If
End If
End If
End Function
Public Function CloseWindow(pstrWindow As String) As Boolean
Const WM_CLOSE = &H10
Dim lngWindow As Long
lngWindow = FindWindow(vbNullString, pstrWindow)
If lngWindow <> 0 Then
SendMessage lngWindow, WM_CLOSE, 0, 0&
CloseWindow = True
End If
End Function
Public Function CloseWindowIfButtonExists(pstrWindow As String, pstrButton As String, pblnExists As Boolean) As Boolean
Const WM_CLOSE = &H10
Dim lngWindow As Long
Dim lngButton As Long
Dim blnExists As Boolean
mstrButton = pstrButton
mlngButton = 0
lngWindow = FindWindow(vbNullString, pstrWindow)
If lngWindow <> 0 Then
EnumChildWindows lngWindow, AddressOf EnumChildProc, ByVal 0&
blnExists = (mlngButton <> 0)
If blnExists = pblnExists Then
SendMessage lngWindow, WM_CLOSE, 0, 0&
CloseWindowIfButtonExists = True
End If
End If
End Function
Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Dim strCaption As String
strCaption = Space$(GetWindowTextLength(hwnd) + 1)
GetWindowText hwnd, strCaption, Len(strCaption)
strCaption = Left$(strCaption, Len(strCaption) - 1)
If strCaption = mstrButton Then
mlngButton = hwnd
Else
EnumChildProc = 1
End If
End Function
Public Function WindowIsOpen(pstrWindow As String) As Boolean
WindowIsOpen = (FindWindow(vbNullString, pstrWindow) <> 0)
End Function
FYI: The code that dee-u posted does not look for the app's Title Bar Name. "SciCalc" is the Class of the Calculator and this is what FindWindow is looking for.Quote:
Originally Posted by dee-u
Included in your VB package is a utility named SpyXX.exe. This utility is invaluable when working with inter-app communication. That's how I determined that "SciCalc" is the Class of the Calculator.
dee-u...... NICE! :thumb:
Ellis, this is nice too. It would be advantageous if you would post calling examples for each function. Just a thought...;)Quote:
Originally Posted by Ellis Dee
It's pretty basic stuff:Quote:
Originally Posted by CDRIVE
vb Code:
If ButtonEnabled("Calculator", "8") Then ' There is a program titled "Calculator" open, it has a button titled "8", ' and that button is enabled End If If ButtonExists("Calculator", "8") Then ' There is a program titled "Calculator" open, and it has a button titled "8" End If If ClickButton("Calculator", "8") Then ' There is a program titled "Calculator" open, it has a button titled "8", ' the button is enabled, and it was just clicked End If If CloseWindow("Calculator") Then ' The "Calculator" app was just closed End If If WindowIsOpen("Calculator") Then ' The calculator is open End If If CloseWindowIfButtonExists("AVG Anti-Virus Free", "Close Results") Then ' Calling this inside a timer with ann interval of around 4 seconds ' will wait until AVG has finished its scan, when it then displays ' a Close Results button. Alternately you could just keep trying to ' the press the Close Results button using the ClickButton() function ' and waiting for success. That's the approach I ended up using, ' but since I already wrote this function I left it in the module. End If
Perhaps, but the examples you posted will prevent others from finding this post someday and asking this question. It is also presumptuous to assume that members of all levels of expertise will regard your code as basic stuff. Think about it. ;)Quote:
Originally Posted by Ellis Dee
The code isn't basic; calling it is.
C'mon, you have to admit the calls are basic.
Yes the calls are basic to about 65% of programmers. So you did a favor for the other 35% and they'll thank you for it.Quote:
Originally Posted by Ellis Dee