Results 1 to 9 of 9

Thread: [RESOLVED] Identify enabled state of button in another app

  1. #1

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Resolved [RESOLVED] Identify enabled state of button in another app

    I have the hwnd of a button in another app. I click it using PostMessage, and it works like gangbusters. The problem is that PostMessage won't care whether the button is enabled or not; it'll assume it worked even when disabled.

    So I need to know how to tell if a button is enabled or not using its hwnd. Any help?

  2. #2
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Identify enabled state of button in another app

    PostMessage is used when you don't want to know the answer. SendMessage will wait until the message is processed and you should get some kind of reply. So try SendMessage instead and see if the return value changes.

    Other than that you could try checking for the window style of the button, WS_DISABLED and so on.

  3. #3

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Identify enabled state of button in another app

    I don't really know what I'm doing when it comes to automation. Here's my automation module:
    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 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 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&
        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
                PostMessage mlngButton, BM_CLICK, 0, 0&
                ClickButton = True
            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, Optional pblnExact As Boolean = True) 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
    I changed the PostMessage call to SendMessage in the ClickButton() function, but the results are weird.

    The button gets half-clicked; the enabled properties of the buttons around it change as if it were clicked, but nothing else happens.

    Is BM_CLICK only for PostMessage? Does SendMessage need a different value to click a command button?

  4. #4
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Identify enabled state of button in another app

    Quote Originally Posted by Ellis Dee
    So I need to know how to tell if a button is enabled or not using its hwnd. Any help?
    Try changing Command1.hwnd in the code below to the buttons handle and see if that works.
    Code:
    Option Explicit
    
    Private Const WS_DISABLED = &H8000000
    Private Const GWL_STYLE = (-16)
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
    
    Private Sub Command2_Click()
    
        If (GetWindowLong(Command1.hwnd, GWL_STYLE) And WS_DISABLED) <> 0 Then
            Debug.Print "Command1 is disabled." 
        Else
            Debug.Print "Command1 is enabled."
        End If
    End Sub
    Last edited by Edgemeal; Jul 19th, 2008 at 02:24 AM.

  5. #5

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Identify enabled state of button in another app

    Perfect, thanks. Here's my new and improved automation module. It now checks if a button is enabled before clicking it in the ClickButton() function. Plus I added a new function: ButtonEnabled(), which returns a simple boolean matching the enabled state of a button.
    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
    Last edited by Ellis Dee; Jul 19th, 2008 at 09:50 AM.

  6. #6

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: [RESOLVED] Identify enabled state of button in another app

    And for the record:

    You must spread some Reputation around before giving it to Edgemeal again.

  7. #7
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: [RESOLVED] Identify enabled state of button in another app

    To check if button is enabled you can probably just use the simpler, IsWindowEnabled API call.

  8. #8

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: [RESOLVED] Identify enabled state of button in another app

    Quote Originally Posted by Edgemeal
    To check if button is enabled you can probably just use the simpler, IsWindowEnabled API call.
    Yeah, probably, but it's not like ANDing a state with a mask is involved. It's identifying a window by its caption that takes all the code.

    EDIT: I went ahead and made that change, as it is definitely more elegant. I also edited the code above to reflect it for posterity.
    Last edited by Ellis Dee; Jul 19th, 2008 at 09:49 AM.

  9. #9
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Identify enabled state of button in another app

    Quote Originally Posted by Ellis Dee
    The button gets half-clicked; the enabled properties of the buttons around it change as if it were clicked, but nothing else happens.
    I was trying to use this same sort of code and seems if the button you want to click is the default button(/already has focus) bm_click doesn't work on the first try but does on the second try, was searching around the web and found a working solution so thought I'd post it in case you ran into the same problem. Before sending the BM_CLICK send a WM_ACTIVATE.
    Code:
    SendMessage ButnHandle, WM_ACTIVATE, MA_ACTIVATE, 0
    SendMessage ButnHandle, BM_CLICK, 0, 0
    EDIT
    Actually that second parameter should be WA_ACTIVE, although it still has the same value (1) as MA_ACTIVATE, that constant is really used with the mouse messages.

    Code:
    SendMessage ButnHandle, WM_ACTIVATE, WA_ACTIVE, 0
    SendMessage ButnHandle, BM_CLICK, 0, 0
    HTH,
    Ed
    Last edited by Edgemeal; Dec 5th, 2008 at 12:57 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width