Question

how to find coordinates on window to click on button displayed in active x control

Asked by: lcha

Hello experts,

I need to click on a specific location on a window popup.   The window popup displays a crystal report in an active x control (crystal reports viewer) as shown in screenshot.

I've managed to get the internet browser window handle so now to click on the button, I need the coordinates to click on the button.  

I have the following code as a sample that I'm working with but not sure how to determine exact coordinates for clicking on that button.  

 Private Const MOUSEEVENTF_LEFTDOWN As Integer = &H2
    Private Const MOUSEEVENTF_LEFTUP As Integer = &H4
 
    Private Const MOUSEEVENTF_RIGHTDOWN As Integer = &H8
    Private Const MOUSEEVENTF_RIGHTUP As Integer = &H10
 
    Private Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Integer, _
        ByVal dx As Integer, ByVal dy As Integer, ByVal cButtons As Integer, _
        ByVal dwExtraInfo As Integer)
 
    Private Sub ClickAt(ByVal x As Integer, ByVal y As Integer, ByVal LeftClick As Boolean, ByVal RestorePosition As Boolean)
        Dim pt As Point = Cursor.Position
        Cursor.Position = New Point(x, y)
        If LeftClick Then
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
        Else
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)
        End If
        If RestorePosition Then
            Cursor.Position = pt
        End If
    End Sub
 
    Private Structure RECT
        Dim Left As Integer
        Dim Top As Integer
        Dim Right As Integer
        Dim Bottom As Integer
    End Structure
 
    Private Declare Function GetWindowRect Lib "user32" (ByVal handle As IntPtr, ByRef lpRect As RECT) As Integer
 
    ...
        Dim DialogRect As RECT
        GetWindowRect(YourDialogHandleHere, DialogRect)
        ClickAt(DialogRect.Left + 2, DialogRect.Top + 2, True, False) 
 
    
 
 
    
                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:

Select allOpen in new window

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2009-11-02 at 23:44:16ID24866321
Topics

Microsoft Visual Basic.Net

,

Microsoft Development

,

.NET

Participating Experts
2
Points
250
Comments
36

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Taskbar icon and popup menu coordinates
    My App added icon to the TaskBar by Shell_NotifyIcon and receiving notifycations about mouse events...Now I want to bring up popup menu after right button click. But how should I know proper coordinates for the menu ? How I can obtain coordinates of icon or coordinates of mou...
  2. Mouse coordinates...
    How can i read mouse coordinates ? I need to know where my mouse is on the screen. I want to have a trayicon, which shows current mouse coordinates.
  3. C++ world coordinates to screen coordinates
    i am an intermediate programmer still learning the true art of game programming. I am using opengl to do my graphics and directX for the inputs. I created a 3d grid using glVertex3f() defing the vertices. I just need a way to convert my 3d vertex coordinates to actual 2d scre...
  4. get click coordinates
    i want to popup a <select> list when the user clicks an <a> link at the (x,y) position he clicks. does a javascript have access to the coordinates of the input click?

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: sedgwickPosted on 2009-11-03 at 00:11:22ID: 25726857

use mouse hook, example attached:

Imports System.Runtime.InteropServices
 
 
 
Public Class Form1
 
 
 
    Private Structure MSLLHOOKSTRUCT
 
        Public pt As Point
 
        Public mouseData As Int32
 
        Public flags As Int32
 
        Public time As Int32
 
        Public extra As IntPtr
 
    End Structure
 
 
 
    Private _mouseHook As IntPtr
 
    Private Const WH_MOUSE_LL As Int32 = 14
 
    Private Delegate Function CallBack(ByVal nCode As Int32, ByVal wParam As IntPtr, ByRef lParam As MSLLHOOKSTRUCT) As Int32
 
    <MarshalAs(UnmanagedType.FunctionPtr)> Private _mouseProc As CallBack
 
    Private Declare Function SetWindowsHookExW Lib "user32.dll" (ByVal idHook As Int32, ByVal HookProc As CallBack, ByVal hInstance As IntPtr, ByVal wParam As Int32) As IntPtr
 
    Private Declare Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hook As IntPtr) As Boolean
 
    Private Declare Function CallNextHookEx Lib "user32.dll" (ByVal idHook As Int32, ByVal nCode As Int32, ByVal wParam As IntPtr, ByRef lParam As MSLLHOOKSTRUCT) As Int32
 
    Private Declare Function GetCurrentThreadId Lib "kernel32.dll" () As Integer
 
    Private Declare Function GetModuleHandleW Lib "kernel32.dll" (ByVal fakezero As IntPtr) As IntPtr
 
 
 
    Public Function InstallHook() As Boolean
 
        If _mouseHook = IntPtr.Zero Then
 
            _mouseProc = New CallBack(AddressOf MouseHookProc)
 
            _mouseHook = SetWindowsHookExW(WH_MOUSE_LL, _mouseProc, GetModuleHandleW(IntPtr.Zero), 0)
 
        End If
 
        Return _mouseHook <> IntPtr.Zero
 
    End Function
 
 
 
    Public Sub RemoveHook()
 
        If _mouseHook = IntPtr.Zero Then Return
 
        UnhookWindowsHookEx(_mouseHook)
 
        _mouseHook = IntPtr.Zero
 
    End Sub
 
 
 
    Private Shared Function MouseHookProc(ByVal nCode As Int32, ByVal wParam As IntPtr, ByRef lParam As MSLLHOOKSTRUCT) As Int32
 
        Debug.Print("Message = {0}, x={1}, y={2}", wParam.ToInt32, lParam.pt.X, lParam.pt.Y)
 
        ' Get the current cursor coordinate
 
        Form1.Text = "Current Point: " & lParam.pt.X & " " & lParam.pt.Y           
 
        Return CallNextHookEx(WH_MOUSE_LL, nCode, wParam, lParam)
 
    End Function
 
 
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 
        InstallHook()
 
    End Sub
 
 
 
    Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
 
        RemoveHook()
 
    End Sub
 
 
 
End Class
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:

Select allOpen in new window

 

by: sedgwickPosted on 2009-11-03 at 00:15:15ID: 25726871

add those declarations:
Private Const HC_ACTION As Integer = 0
Private Const WH_MOUSE_LL As Integer = 14
Private Const WM_LBUTTONDOWN As Integer = &H201
Private Const WM_MOUSEWHEEL As Integer = &H20A

and in MouseHookProc():
If (nCode = HC_ACTION) Then

If wParam = WM_LBUTTONDOWN Then

''do something on left mouse click

End If

 

by: sedgwickPosted on 2009-11-03 at 06:02:54ID: 25728980

any progress mate?

 

by: Idle_MindPosted on 2009-11-03 at 07:32:46ID: 25729887

Take a screenshot and figure out the offset...I think (95, 190) should work:

(using your originally posted code)

    ...
        Dim DialogRect As RECT
        GetWindowRect(YourDialogHandleHere, DialogRect)
        ClickAt(DialogRect.Left + 95, DialogRect.Top + 190, True, False)

Things that could throw this off would be if the User has turned off the Links Toolbar (or added another).

 

by: lchaPosted on 2009-11-03 at 07:59:05ID: 25730234

Hello, just got up and on the way to work now. Thx for the feedback.  I'll look at this asap.

 

by: lchaPosted on 2009-11-03 at 11:59:47ID: 25732901

Modalot and experts, apologies if this creates confusion.  I will be more conscious of this in the future.   thanks.

 

by: lchaPosted on 2009-11-03 at 12:33:07ID: 25733265

sedgewick, thank you again.   i haven't had the opportunity to try out the code you posted as I think (or hoping at least) that some progress is being made with the current code base.   I will look more in depth at what you provided as soon as possible and make use of it if needed ... thank u very much for providing this code.

In the meantime, since the last post I made some additional modifications to the code -

I first find the internet explorer window using the WindowsEnumerator class.  
- I find the appropriate top level window as you can see in the code I try to find a match on the string, "crystal", to find the appropriate IE popup window.  

- Once I find the match, the program finds the child window where the class name = ATL:07868280 (I used spy++ to find the lower level window and get the class name of where the export button is located.)

When running the code, I see now that it is able to find the window with that export button on it so it seems I've narrowed the area that needs to be clicked on now so the code wouldn't be thrown off by the toolbar, etc.

Now, I am trying to figure out how to click on the appropriate coordinates.

thanks for this additional info.  I will review this in more depth.
 
In the meantime, since my last post I tried something different which is to find the internet explorer window using the, WindowsEnumerator class.   
- I find the appropriate top level window as you can see in the code I try to find a match on the string, crystal to find the IE popup.   
 
- Once I find the match, find the child window where the class name = ATL:07868280 (I used spy++ to find the lower level window and get the class name of where the export button is located.)
 
When I run the code it is able to find the window with that export button on it so it seems Ive narrowed the area that needs to be clicked on.   
 
Now, I am trying to figure out how to click on the appropriate coordinates.
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Select allOpen in new window

 

by: lchaPosted on 2009-11-03 at 12:34:36ID: 25733288

sorry, so you can see what I've done here's that code

Dim DialogWindows As List(Of ApiWindow)
            Dim windowflag As Boolean = False
 
 
While windowflag <> True
     Application.DoEvents()
     DialogWindows = we.GetTopLevelWindows("IEFrame")
     
     If DialogWindows.Count > 1 Then
          windowflag = True
          Debug.Print("windowflagloop count:" & DialogWindows.Count.ToString)
     End If
End While
           
Dim DialogRect As RECT
 
For Each aw In DialogWindows
   If aw.Text.ToLower.Contains("crystal") Then
       For Each ctl In we.GetChildWindows(aw.Handle)
       
            If ctl.ClassName = ("ATL:07868280") Then
                 Debug.Print(" Got ATL:07868280")
            End If
           
            GetWindowRect(aw.Handle, DialogRect)
            ClickAt(DialogRect.Left + 5, DialogRect.Top + 2, True, False)
            Debug.Print("clicked on window")
            
            Exit Sub
       Next
      
   Else
           Debug.Print("not the right window")
   End If
 
Next
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:

Select allOpen in new window

 

by: Idle_MindPosted on 2009-11-03 at 12:56:48ID: 25733522

Ok...so if you've got a handle to the ToolBar area then just use Spy++ to show you the bounding box with "highlight window" feature (or is it "show window"...not sure).  Anyhoo, it will show you the are that belongs to that window.  You can calculate the needed offset by taking a screenshot and then cropping the image so just that toolbar bounding box is visible.  Once you have the offset you pass the toolbar handle to GetWindowRect() as before and add the offset values to the x, y coords.

 

by: lchaPosted on 2009-11-03 at 13:37:51ID: 25734063

I am passing the handle of the childwindow (the toolbar area) to GetWindowRect.

So for example, using ClickAt(DialogRect.Left + 35, DialogRect.Top - 5, True, False)

DialogRect.Left + 15 thru + 35 appear to be clicking on the refresh button.   I can see the the window refreshing... there is a bar on the right side of that window that shows the refresh taking place.

Since the export button is to the left of the refresh button I have tried decreasing the #  + 0 to + 15 but it's not clicking on the export button.

Note: for DialogRect.Top I used a negative number because .Top gets the y-axis position of the top of the rectangle.   If I use a positive # I'm not able to make any contact with the buttons.
ClickAt(DialogRect.Left + 35, DialogRect.Top - 5, True, False)

 

by: lchaPosted on 2009-11-03 at 14:45:44ID: 25734708

I still a bit unclear on how to get the "offset".   When I enter + 50, how far to the right is this of the left side of the rectangle?    Does +50 mean 50 pixels and how much is that .. is it a millimeter, inch?

Does +50 move the position or coordinates from 771 to 821 on the x axis?

.Top - Gets the y-axis position of the top of the rectangle.  - Since the button is below the top, should this # be negative?

.Left - Gets the x-axis value of the left side of the rectangle.

   GetWindowRect(aw.Handle, DialogRect)
                        Debug.Print("left " & DialogRect.Left.ToString)
                        Debug.Print("top " & DialogRect.Top.ToString)
                        Debug.Print("top max val: " & DialogRect.Top.MaxValue.ToString())
                        Debug.Print("top min val: " & DialogRect.Top.MinValue.ToString())
                        Debug.Print("Left min val: " & DialogRect.Left.MinValue.ToString)
                        Debug.Print("Left max val: " & DialogRect.Left.MaxValue.ToString)

                        ClickAt(DialogRect.Left + 200, DialogRect.Top + 100, True, False)

I don't know if I'm interpreting this correctly or if it matters really but seems the range for that small rectangular tool bar is between -2147483648 and 2147483647?

Debug.print results:
left 771
top 174
top max val: 2147483647
top min val: -2147483648
Left min val: -2147483648
Left max val: 2147483647

 

by: Idle_MindPosted on 2009-11-03 at 15:22:06ID: 25735008

It's all in PIXELS and the Offsets should be positive to move the cursor to the right and down from the Top Left corner of the Rectangle.

I would take half of the Height and add that to the Top value to get the middle of the Toolbar.  Then it's just a matter of figuring out the X offset value.

Try 70 for the Left Offset:

    GetWindowRect(aw.Handle, DialogRect)
    ClickAt(DialogRect.Left + 70, DialogRect.Top + ((DialogRect.Bottom - DialogRect.Top) / 2), True, False)

 

by: lchaPosted on 2009-11-03 at 15:23:28ID: 25735017

I took a screenshot as you suggested and then cropped the image so just that toolbar bounding box is visible.

I took the screenshot in my snag it tool - when I highlighted over the image I can see the coordinates at the bottom of the screen

63,13
169X19X24 bit

I tried changing the code as follows:

        ClickAt(DialogRect.Left + 60, DialogRect.Top + 13, True, False)

but it doesn't appear to be clicking the right spot.

 

by: lchaPosted on 2009-11-03 at 15:24:27ID: 25735023

the 63,13 is when I put the mouse arrow over the "export" button

 

by: Idle_MindPosted on 2009-11-03 at 15:26:44ID: 25735035

I would display your actual computed coords and then compare those to an actual FULL screen shot to see what you're getting:

    Dim pt As New Point(DialogRect.Left + 60, DialogRect.Top + 13)
    MessageBox.Show(pt.ToString())

Take a FULL screen shot and see if the values match where the actual envelope is.

Are you running 32-bit or 64-bit?

 

by: Idle_MindPosted on 2009-11-03 at 15:35:01ID: 25735076

In the ClickAt() sub, after the "Cursor.Position = New Point(x, y)" line, is the cursor physically in the correct position onscreen?  If not, how far off is it?

 

by: lchaPosted on 2009-11-03 at 16:13:09ID: 25735299

I'm on 32 bit.  

I took the full screenshot and when i put the mouse over the envelope it shows 918, 438

When i ran the code with the code in the msg box you provided it shows 889, 245.

>>>In the ClickAt() sub, after the "Cursor.Position = New Point(x, y)" line, is the cursor physically in the >>>correct position onscreen?  If not, how far off is it?
sorry, I did not understand how to do this or what to check for here.   since the values above didn't match, I'm presuming this could be the problem?

I tried changing the values below until that message box popup you advised to put in displayed 918, 438 (these are the x, y values for the envelope on the full screenshot)
Dim pt As New Point(DialogRect.Left + 60, DialogRect.Top + 13) - CHANGED THESE VALUES

Used the new values  below to make the values in the message box popup match up w/ the coordinates of the full screenshot (918,438)
Dim pt As New Point(DialogRect.Left + 89, DialogRect.Top + 206)
- the message box popup displays 918, 438

 

by: lchaPosted on 2009-11-03 at 17:02:03ID: 25735548

fyi - sorry for any confusion, the moderator split the points on this because I have another thread on the same issue.   for your reference the link is below:

http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_24660287.html#a25735511

 

by: lchaPosted on 2009-11-04 at 16:04:31ID: 25745541

idlemind,I don't know how I missed this comment - 25735008

Anyhow, I tried what you suggested:

Try 70 for the Left Offset:

    GetWindowRect(aw.Handle, DialogRect)
    ClickAt(DialogRect.Left + 70, DialogRect.Top + ((DialogRect.Bottom - DialogRect.Top) / 2), True, False)

This didn't work so I tried different values for DialogRect.Left ranging from 0 - 145 (0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, etc. etc.) but for some reason it's still not clicking that button


 

by: lchaPosted on 2009-11-04 at 16:10:53ID: 25745572

DialogRect as I understand it should have the screen coordinates of the child window right since I passed it to the GetWindowRect method.

GetWindowRect(aw.handle, DialogRect)

With the code you provided, It seems as simple as finding the X coordinate now but i tried with what seems to be the logical left offsets ... many of them but none work? : /

 

by: Idle_MindPosted on 2009-11-04 at 22:03:01ID: 25747074

May need to tweak the mouse_event() calls to make sure it's actually hitting what we want.  We could add the MOUSEEVENTF_ABSOLUTE flag back in.  I think it's:

    Public Const MOUSEEVENTF_ABSOLUTE As Integer = &H8000
    Public Const MOUSEEVENTF_MOVE As Integer = &H1
    ...
       mouse_event(MOUSEEVENTF_ABSOLUTE Or MOUSEEVENTF_MOVE, x, y, 0, 0)
       mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
       mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)

We could also try adding a small delay (100 ms) between LeftDown and LeftUp to see if that makes a difference.

 

by: lchaPosted on 2009-11-04 at 22:10:43ID: 25747094

idlemind, thank you again for helping me out on this!  Will try it out tomm and let you know how it goes.

 

by: lchaPosted on 2009-11-05 at 11:59:25ID: 25753289

this morning I added the code you have there above.   IRan the code many times using values a range of values 0 - 145 for DialogRect.Left

ClickAt(DialogRect.Left + 145, DialogRect.Top + ((DialogRect.Bottom - DialogRect.Top) / 2), True, False)

In debug mode, i checked the x,y values when Clickat method is run.   For example, when using the code above, x value will be the offset or 145, and the y value is always 0.  

Also, added a sleep as you suggested.   Still no response though from the button.

 Private Sub ClickAt(ByVal x As Integer, ByVal y As Integer, ByVal LeftClick As Boolean, ByVal RestorePosition As Boolean)
        Dim pt As Point = Cursor.Position
        Cursor.Position = New Point(x, y)
 
        If LeftClick Then
            mouse_event(MOUSEEVENTF_ABSOLUTE Or MOUSEEVENTF_MOVE, x, y, 0, 0)
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
            System.Threading.Thread.Sleep(100)
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
        Else
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)
        End If
        If RestorePosition Then
            Cursor.Position = pt
        End If
    End Sub

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:

Select allOpen in new window

 

by: lchaPosted on 2009-11-05 at 12:21:27ID: 25753521

is the problem problem related what thelearnedone mentioned,
"It looks like you are trying to use relative coordinates, but that won't be from the Cursor.Position, but from the last call to mouse_event.  It is tough to know whether the event needs client or screen coordinates (client are relative to the form's position).  My guess is that it needs screen coordinates."

i'm having difficulty making sense of the types of coordinates
client coordinates - relative to form's position
screen coordinates
relative coordinates - looks like we are trying to use this one.

My understanding is that we got the dimensions of the bounding rectangle (assuming this is the child window - that tool bar with the export button in it?) using GetWindowRectFunction we passed the handle of the childwindow to it along with DialogRect which becomes a pointer to a structure that receives the screen coordinates.

So when we call the clickat method it presses where the cursor position is set.

cursor.position = new point (x,y)

Is the mouse then pressing relative to coordinates on the child window or the whole screen?   I'm a bit confused conceptually understanding this.

 

by: Idle_MindPosted on 2009-11-05 at 13:15:20ID: 25754120

We are working in screen coords as that is what is returned by GetWindowRect().

We also moved the cursor with mouse_event():

    mouse_event(MOUSEEVENTF_ABSOLUTE Or MOUSEEVENTF_MOVE, x, y, 0, 0)

So that the last position seen by mouse_event() is the correct position in screen coords.

Not sure why it isn't working...either it's hitting the wrong spot or he actual button doesn't see the MOUSEEVENTF_LEFTDOWN() and MOUSEEVENTF_LEFTUP() actions as a "click".

You could try switching to SendInput() instead and see if that makes a difference:
http://msdn.microsoft.com/en-us/library/ms646310(VS.85).aspx
 

 

by: lchaPosted on 2009-11-05 at 15:25:34ID: 25755236

i did some more troubleshooting and it looks like the code is not getting the child window so I think this is why it's not able to click

Apparently the ctl.ClassName isn't a static value

I'm not sure why earlier the code was able to find the child window which mislead me to think it was finding it all the time .... but now the class name for that child window appears to change every time.

I used spy++ to see if I could find another window where the classname doesn't change.   I'm using classname "ATL:STATIC" and made the code changes below.

Still not finding it when I run the code but that's where i'm at right now....

 For Each aw In DialogWindows
                Debug.Print(aw.Text.ToString)
                If aw.Text.ToLower.Contains("crystal") Or aw.Text.ToLower.Contains("xxxxs.rpt") Then
                    For Each ctl In we.GetChildWindows(aw.Handle)
                        If ctl.ClassName.ToLower = ("ATL:STATIC") Then
                            Debug.Print(" Got ATL:STATIC")
                            GetWindowRect(aw.Handle, DialogRect)
                            ClickAt(DialogRect.Left + 70, DialogRect.Top + ((DialogRect.Bottom - DialogRect.Top) / 2), True, False)
                            Debug.Print("got to childwindow and clicked")
                            'Exit Sub
                        Else
                            Debug.Print("Not right child window")
                        End If
                    Next
                Else
                    Debug.Print("not the right Top level window")
                End If
            Next

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:

Select allOpen in new window

  • toobar.png
    • 2 KB

    this is ATL:STATIC - encompasses a larger area

    this is ATL:STATIC - encompasses a larger area
 

by: lchaPosted on 2009-11-05 at 15:29:08ID: 25755255

here is ATL:STATIC

and

Spy++ properties for ATL:STATIC

Not sure if this could provide additional insight...

 

by: lchaPosted on 2009-11-05 at 18:18:31ID: 25756142

ok sorry in advance for any confusion on the previous msg, I should've waited to post

I went back to getting the child window by using class name for the window as follows:

  For Each aw In DialogWindows
                Debug.Print(aw.Text.ToString)
                If aw.Text.ToLower.Contains("crystal") Or aw.Text.ToLower.Contains("xxx.rpt") Then
                    For Each ctl In we.GetChildWindows(aw.Handle)
                        If ctl.ClassName.Contains("TabWindowClass") Then

"TabWindowClass" is the classname I'm using to retrieve a child window within the internet browser where the active x viewer displays the report.   It's a larger area (essentially the entire active x viewer area) vs. trying to get the smaller window (just the tool bar section).   It's Parent's classname is the IEFrame Class.

Maybe the problem before was I was trying to retrieve a child of a child window....

When I run the code, I can successfully get the child window again each time I run it.   Now again, it seems to be a matter of clicking on the right coordinates.

  • tabclass.png
    • 8 KB

    spy ++ - here you can see the windows (parent and children)

    spy ++ - here you can see the windows (parent and children)
 

by: lchaPosted on 2009-11-06 at 12:57:10ID: 25762972

Still not working with Sendinput either.  

I'm using the following now:
'Click on button
 ClickAt(DialogRect.Left + 85, DialogRect.Top + 32, True, False)

'Display coordinates
 Dim pt As New Point(DialogRect.Left + 85, DialogRect.Top + 32)
 MessageBox.Show(pt.ToString())

When running the code, the message box appears and displays the coordinates. I take a full screenshot, compare and then see that the coordinates in the msgbox {X=118,Y=237} match exactly the location of the export button on the full screenshot.   In the program that I view the full screenshot in, can see the coordinates of the export button as I put my mouse over it.   They match.

I am now using SendInput as suggested.   You can see the changes I made in the "ClickAt" method as shown in code snippet below but still no luck.

Private Sub ClickAt(ByVal x As Integer, ByVal y As Integer, ByVal LeftClick As Boolean, ByVal RestorePosition As Boolean) 
        Dim inputEvents(0) As INPUT_TYPE 
        Dim pt As Point = Cursor.Position
        Cursor.Position = New Point(x, y) 
        If LeftClick Then
            Debug.Print("Clicking export button now")
            inputEvents(0).xi.dx = 0
            inputEvents(0).xi.dy = 0
            inputEvents(0).xi.mouseData = 0
            inputEvents(0).xi.dwFlags = M_MOVE + M_LD + M_LU
            inputEvents(0).xi.dwtime = 0
            inputEvents(0).xi.dwExtraInfo = 0
            inputEvents(0).dwType = INPUT_MOUSE 
            Dim SI_returnval As Integer 
   SI_returnval = SendInput(1, inputEvents(0), Len(inputEvents(0)))
  
'SEND INPUT RETURNS SUCCESSFUL WITH A 1  
        Else
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)
        End If
        If RestorePosition Then
            Cursor.Position = pt
        End If
    End Sub

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:

Select allOpen in new window

 

by: lchaPosted on 2009-11-06 at 13:50:53ID: 25763387

Another relevant point I just realized is that after running the code my mouse arrow moves itself to the "export report" (the envelope)  .... it's pointing exactly to the right spot so this confirms to me that the coordinates I used are correct.

Somehow though, the button isn't getting pressed.

 

by: lchaPosted on 2009-11-06 at 13:52:35ID: 25763400

this behavior with the mouse arrow moving to the button is not happening with the "mouse_event" approach,only with "SendInput" so sendinput looks more promising.

 

by: lchaPosted on 2009-11-10 at 11:52:55ID: 25789049

In the above approach, the cursor seems to be in the right place.   The actual button though doesn't appear to see the MOUSEEVENTF_LEFTDOWN() and MOUSEEVENTF_LEFTUP() actions as a "click".

Is there anything else here that I can try or insight anyone has about why this doesn't work?   I've been searching the for web similar issues, examples, etc. but everything I have found so far has either been not specific enough, too confusing and or just doesn't work.

Note, I also tried another approach using PostMessage below but that didn't work either.

Dim pt As New Point(DialogRect.Left + 85, DialogRect.Top + 32)
MessageBox.Show(pt.ToString()) 
I assigned values to x, y below using the values that show in MessageBox.Show above. 

'USING POSTMESSAGE INSTEAD OF SENDINPUT 
Dim x As Integer = 321
Dim y As Integer = 440 
Dim pt As Point = Cursor.Position
Cursor.Position = New Point(x, y) 
Dim strResult As String 
strResult = PostMessage(ctl.Handle, MOUSEEVENTF_LEFTDOWN, 0, IntPtr.Zero) 
strResult = PostMessage(ctl.Handle, MOUSEEVENTF_LEFTUP, 0, IntPtr.Zero)
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:

Select allOpen in new window

 

by: lchaPosted on 2009-11-13 at 15:25:36ID: 25818544

I'm still struggling with this .... please see my latest update below and advise if there is anything you can think of.   I feel like I'm getting closeR here.

Before calling the "ClickAt" method to click on the export button, I retrieve the popup window and pass the handle of the window to GetWindowRect

Again, when the code runs, I can see the mouse arrow or cursor move itself to the correct coordinates, putting itself right on top of the export button to click it.  

If I can click on the button myself using a left click, there's no reason I shouldn't be able to do the same programatically right?

Would someone please look at my code below and provide feedback on possible other approaches or something I did wrong?   Thanks in advance.

*** code before calling the ClickAt method ***  
GetWindowRect(ctl.Handle, DialogRect)
ClickAt(DialogRect.Left + 85, DialogRect.Top + 32, True, False) 
*** Here is the ClickAt method ****** 
Private Sub ClickAt(ByVal x As Integer, ByVal y As Integer, ByVal LeftClick As Boolean, ByVal RestorePosition As Boolean) 
        Dim inputEvents(0) As INPUT_TYPE 
        Dim pt As Point = Cursor.Position
        'IF DURING DEBUG I STOP HERE THE VALUES FOR ARE X=89, Y=340
        Cursor.Position = New Point(x, y) 
        If LeftClick Then 
            Debug.Print("Clicking export button now")
            inputEvents(0).xi.dx = 0
            inputEvents(0).xi.dy = 0
            inputEvents(0).xi.mouseData = 0
       inputEvents(0).xi.dwFlags = MOUSEEVENTF_ABSOLUTE + M_LD + M_LU
            inputEvents(0).xi.dwExtraInfo = 0
            inputEvents(0).dwType = INPUT_MOUSE 
            SendInput(1, inputEvents(0), Len(inputEvents(0))) 
        Else
            mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
            mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)
        End If
        If RestorePosition Then
            Cursor.Position = pt
        End If
    End Sub 
HERE ARE THE RELEVANT STRUCTURE USED IN CLICKAT METHOD: 
Public Structure MOUSEINPUT
        Public dx As Integer
        Public dy As Integer
        Public mouseData As Integer
        Public dwFlags As Integer
        Public dwtime As Integer
        Public dwExtraInfo As Integer
    End Structure 
    Public Structure INPUT_TYPE
        Public dwType As Integer
        Public xi As MOUSEINPUT
    End Structure

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:

Select allOpen in new window

 

by: lchaPosted on 2009-11-13 at 16:46:29ID: 25818821

Sorry the code above is not formatted nicely.  Some additional information:

I noticed the SendInput return value only returns back 1.  

inputEvents(0).xi.dwFlags = MOUSEEVENTF_ABSOLUTE + M_LD + M_LU

Should it be returning 3 since there are 3 flags set as above in the MOUSE_INPUT structure

Also, note that although articles I have read say that it's rare for focus to be an issue I tried using both SetFocus,  SetForegroundWindow(ctl.Handle) & SetActiveWindow(ctl.Handle) and this didn't do anything.

Previously I had tried putting a sleep delay up to 500 ms between using M_LD AND M_LU (abbreviated) when using mouse_event

 Const M_LD = &H2
 Const M_LU = &H4

Here's an article with someone who had a similar issue that the Cursor needs to be above the button for the click to work.   I tried that also decreasing the offset for the y coordinate from 32 down to 17 or so but it didn't make a difference.

http://bytes.com/topic/c-sharp/answers/575589-simulate-mouse-click-without-focus


The article here suggests to use Send or PostMessage but the problem with that I can't get the button itself as a window.   I can only get a child window that contains the button.   If I'm using screen coordinates is there even a need for the child window of the window popup?

I am so stumped, this is really a tough one for me.

   

       

                                              
1:

Select allOpen in new window

 

by: lchaPosted on 2009-11-19 at 10:59:50ID: 25863654

Although, I'm not able to click on the button, I awarded points for the original question which was to get help to find the correct coordinates.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...