• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 801
  • Last Modified:

Vb.net press a button programatically

Hi Experts!

I have written a vb.net app to press a specific button on an already running app (specifically the HP Fax app, HPOFXM08.exe) running on Server 2003.

According to Spy++ and Winspector Spy I have found the correct handle to the item to be clicked, but for some reason it's not clicking the button.

The code I'm using is below.

What am i missing?
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Private Declare Function ShowWindow Lib "user32" (ByVal handle As IntPtr, ByVal nCmd As Int32) As Boolean

Private Const HP_FAX_APP_TITLE As String = "HP Officejet 7200 series - Send Fax"
Private Const SW_RESTORE As Long = 9
Public Const BM_CLICK As Long = &HF5

Private ipFax as IntPtr

Sub Main()
  ' The Fax app window handle
  Dim parent As IntPtr = FindWindow(vbNullString, HP_FAX_APP_TITLE)
  ShowWindow(parent,SW_RESTORE)
  ' prior to this call, I have (according to Spy++ and Winspector Spy) found the correct handle, but for simplicity sake not
  ' showing the code.
  SendFax()

End Sub

Private Sub SendFax()
  ' this sendmessage returns a 0, whatever that means.
  SendMessage(ipFax, BM_CLICK, 0, 0)
End Sub

Open in new window

0
sgaggerj
Asked:
sgaggerj
  • 8
  • 7
  • 2
  • +1
4 Solutions
 
silemoneCommented:
well you could always just call the method that is called when the button is clicked...

i.e.

I think that you have to create a method and pass the sender as &HF5, event

i.e
pseudo code

click_HFT(&HFT, null)...
private sub click_HFT(sender, eventargs)
0
 
silemoneCommented:
you're calling click for the button, but their is not click event for is basically what i'm saying...

So SendMessage(ipFax, BM_Click, 0, 0, )

can work

but in Sendmessage --> you would have to call

click_HFT(BM_Click, null )   null since you're not passing args....

and you have to have a method in the page also...

private sub click_HFT(ByVal sender, ByVal event)
'do something...
end sub
0
 
me655321Commented:
Try sending mousedown and mouseup....
Call SendMessage(ipFax, &H201, 0, 0)
Call SendMessage(ipFax, &H202, 0, 0)

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Make sure to use Integer for your constants as well!  (looks like you copied some VB6 code for parts?)

Some controls respond differently to various messages...

Following me655321's idea, try a "catch all" approach like:
    Private Const WM_LBUTTONDOWN As Integer = &H201
    Private Const BM_SETSTATE As Integer = &HF3
    Private Const BM_CLICK As Integer = &HF5
    Private Const WM_LBUTTONUP As Integer = &H202

    Private Sub ClickButton(ByVal ButtonHandle As IntPtr)
        Call SendMessage(ButtonHandle, WM_LBUTTONDOWN, 0, 0)
        Call SendMessage(ButtonHandle, BM_SETSTATE, 1, 0)
        Call SendMessage(ButtonHandle, BM_CLICK, 0, 0)
        Call SendMessage(ButtonHandle, WM_LBUTTONUP, 0, 0)
    End Sub

Open in new window

0
 
sgaggerjAuthor Commented:
@silemone

I don't have access to the methods that are called when the 'Send Fax' button are clicked.  It's an HP built app.

@me655321 and Idle_Mind,

I tried those samples and the same thing (nothing) happens.

I did copy code from

http://joe-riggs.com/blog/2009/01/vbnet-code-to-programatically-populate-address-field-in-ups-worldship/#respond

and modified it to fit my uses.

Essentially I am filling in the fields of the fax sheet (which all works fine).

The click isn't working for some reason.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Hmm...instead of addressing the control directly, you get the bounds of it with GetWindowRect() then try left clicking in the middle of that box with mouse_event():
http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_23724897.html
http://www.experts-exchange.com/Microsoft/Development/Q_24848939.html#25678228
0
 
sgaggerjAuthor Commented:
I'll give that a looksee...

I was going this route because I had done it before in an app that i had written to close out the VS JIT Debugger (clicking on a button).
That worked, and I'm re-using some of my code , so I'm baffled why this isn't working.

Before I get into trying your last suggestion - for my previous approach, the window only needs to be visible (it is), not on top right (it's not)?
and for the GetWindowRect, the window would need to be on top, or does the z order not matter?
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
For the mouse_event() approach the window would have to be directly under where ever the mouse is clicking as we are essentially blindly clicking on the screen at that point.  The window wouldn't necessarily have to be on top though if the part you wanted to click on was visible.
0
 
sgaggerjAuthor Commented:
I tried the mouse_event approach... and still nothing.

I did this...

Private Sub SendFax()
        Dim DialogRect As RECT
        GetWindowRect(ipFax, DialogRect)
        ClickAt(DialogRect.Left + (DialogRect.Right - DialogRect.Left) / 2, DialogRect.Top + (DialogRect.Bottom - DialogRect.Top) / 2, True, False)

End Sub

where ipFax is the handle of the SEND FAX button.

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Running out of ideas...

Can you post a screenshot of the dialog in question along with the Spy++/Winspector entry showing its classname and relationship to its parents?
0
 
sgaggerjAuthor Commented:
Here it is.
If you need my full code listing, let me know.
Screenshot..jpg
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
That button has an accelerator key of "Alt-X".  If the window is in the foreground you could just use SendKeys() to make it trigger...

0
 
sgaggerjAuthor Commented:
That I was able to get to work! (though on the machine it's going to be running on the shortcut is ALT+S)

How reliable is sendkeys vs an API click? (granted this app will have pretty LOW usage, but I don't want to have to keep checking up on it)
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
It's pretty finicky...the target app MUST be the foreground window for it to work.  SendKeys() just blindly presses the keys as if the user typed them on the keyboard and whatever is in the foreground will receive them.  It has its place but use with CAUTION....
0
 
sgaggerjAuthor Commented:
I ended up using

BringWindowToTop

and

SetForegroundWindow

to make sure that it's ready to accept the SendKeys.

I was hoping to use an API for this, but as long as this works, I don't see too much of a problem.
0
 
me655321Commented:
Here is the full method I use to click a window...
Const WM_LBUTTONDOWN As Integer = &H201
    Const WM_LBUTTONUP As Integer = &H202

    Declare Function GetWindowInfo Lib "user32" (ByVal hwnd As IntPtr, ByRef pwi As WINDOWINFO) As Boolean
    Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

    Public Structure WINDOWINFO
        Dim cbSize As UInt32
        Dim rcWindow As RECT
        Dim rcClient As RECT
        Dim dwStyle As UInt32
        Dim dwExStyle As UInt32
        Dim dwWindowStatus As UInt32
        Dim cxWindowBorders As UInt32
        Dim cyWindowBorders As UInt32
        Dim atomWindowType As UInt16
        Dim wCreatorVersion As UInt16
    End Structure
    Public Structure RECT
        Public Left As Integer
        Public Top As Integer
        Public Right As Integer
        Public Bottom As Integer
        Public Sub New(ByVal pLeft As Integer, ByVal pTop As Integer, ByVal pRight As Integer, ByVal pBottom As Integer)
            Left = pLeft
            Top = pTop
            Right = pRight
            Bottom = pBottom
        End Sub
        Public ReadOnly Property Height() As Integer
            Get
                Return Bottom - Top
            End Get
        End Property
        Public ReadOnly Property Width() As Integer
            Get
                Return Right - Left
            End Get
        End Property
        Public ReadOnly Property Location() As Point
            Get
                Return New Point(Left, Top)
            End Get
        End Property
        Public ReadOnly Property Size() As Size
            Get
                Return New Size(Width, Height)
            End Get
        End Property
        Public Function ToRectangle() As Rectangle
            Return Rectangle.FromLTRB(Me.Left, Me.Top, Me.Right, Me.Bottom)
        End Function
        Public Shared Function ToRectangle(ByVal sourceRect As RECT) As Rectangle
            Return Rectangle.FromLTRB(sourceRect.Left, sourceRect.Top, sourceRect.Right, sourceRect.Bottom)
        End Function
        Public Shared Function FromRectangle(ByVal r As Rectangle) As RECT
            Return New RECT(r.Left, r.Top, r.Right, r.Bottom)
        End Function
    End Structure

    Public Sub ClickWindow(ByVal hwnd As Integer)
        Dim tmpWinInfo As WINDOWINFO
        GetWindowInfo(hwnd, tmpWinInfo)
        Dim X As Integer = tmpWinInfo.rcWindow.Width / 2
        Dim Y As Integer = tmpWinInfo.rcWindow.Height / 2
        Dim lparam As Integer = X + (Y * &H10000)
        Call PostMessage(hwnd, WM_LBUTTONDOWN, 0, lparam)
        Call PostMessage(hwnd, WM_LBUTTONUP, 0, lparam)
    End Sub

Open in new window

0
 
sgaggerjAuthor Commented:
OK..... so I'm COMPLETELY retarded.

This whole time I've been clicking on the FAX NUMBER text box (ipFax) and NOT the SEND FAX button (ipSend)

after that change, everyone's ideas work.... man I feel stupid.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Hehe...grab another cup of coffee my friend!

Glad you figured it out and now have several different approaches in your "toolbox".  =)
0
 
sgaggerjAuthor Commented:
Or two or three... =)

Thanks again!
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 8
  • 7
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now