Results 1 to 8 of 8

Thread: Automation Help Needed (VB 2008 Express)

  1. #1

    Thread Starter
    New Member
    Join Date
    Jul 2017
    Posts
    6

    Automation Help Needed (VB 2008 Express)

    I am trying to automate a machine at work and am having some trouble getting some bugs worked out. I am using 2008 to control two programs. One is a camera program (temperamental as a mf) and the other is a program that moves a X,Y axis. It has been working ok but I'm hoping for better. It misses points from time to time and takes extra shots at the end of the run. I am new to programming and can understand if none of what I have written is how it should be written. I just need some help at this point. To explain the code below; it looks for active window 1 and runs commands, switches to active window 2 runs a command, switches to active window 3 runs command also looking for active window 4 that comes up at the end of the run. Then loops window 2 and window 3 commands until window 4 is found and runs command for window 4.
    Code:
    Imports System.Threading
    
    Public Class Form1
    
        Dim a As New Process
        'Faceplate Program.
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            'Start with Pax-it Quadrant A.
            AppActivate("QUADRANT A input")
            Thread.Sleep(1000)
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(1000)
            SendKeys.SendWait("{ENTER}")
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(1000)
            'Quadrant A Shot 1.
            SendKeys.SendWait("{ENTER}")
            Dim objShell
            objShell = CreateObject("WScript.Shell")
            Do
                If (objShell.AppActivate("QUADRANT A capture") = True) Then
                    'Switch to Galil.
                    AppActivate("GalilTools {default.project}, COM1 19200, DMC2122sH2a, 7110")
                    Thread.Sleep(1000)
                    SendKeys.SendWait("{ENTER}")
                    'Switch to Pax-it
                    AppActivate("QUADRANT A capture")
                    Thread.Sleep(3000)
                    SendKeys.SendWait("{TAB}")
                    Thread.Sleep(500)
                    SendKeys.SendWait("{ENTER}")
                    Thread.Sleep(500)
                ElseIf (objShell.AppActivate("FINISHED") = True) Then
                    Thread.Sleep(3000)
                    SendKeys.SendWait("{TAB}")
                    Thread.Sleep(500)
                    SendKeys.SendWait("{ENTER}")
                End If
            Loop
        End Sub
    Last edited by scoltran; Aug 1st, 2017 at 01:13 PM. Reason: added Code tags

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,352

    Re: Automation Help Needed (VB 2008 Express)

    SendKeys is rarely completely reliable and relying on specific timings in never a great idea. I'd suggest that you look into using the Windows API so that you can send specific messages to specific windows without having to care about focus or timing. You should check out the FindWindow, FindWindowEx and SendMessage functions at a minimum. Those three would be used, for instance, to send a click message to a button. You would call FindWindow to get the handle of a specific top-level window, then FindWindowEx to get the handle of a specific child window, then SendMessage to perform the click.

    You can use tools like Spy++, Winspector and WinID to determine the window hierarchy of an application on your own machine and then use that hierarchy to determine what arguments to pass to FindWindow and FindWindowEx and also how many times you need to call FindWindowEx. For instance, if you wanted to click the third button inside a panel that was after a text box, you'd have to call FindWindowEx a total of five times, using two different parent handles:

    1. Call FindWindow to get top-level window handle.
    2. Call FindWindowEx with top-level window handle as parent to get first child.
    3. Call FindWindowEx with top-level window handle as parent and first child as sibling to get second child.
    4. Call FindWindowEx with second child handle as parent to get first grandchild.
    5. Call FindWindowEx with second child handle as parent and first grandchild as sibling to get second grandchild.
    6. Call FindWindowEx with second child handle as parent and second grandchild as sibling to get third grandchild.
    7. Call SendMessage to click button.

  3. #3

    Thread Starter
    New Member
    Join Date
    Jul 2017
    Posts
    6

    Re: Automation Help Needed (VB 2008 Express)

    Jmcilhinney, Thank you for the information. I am looking into the FindWindow and FindWindowEX route. I got a copy of Winspector to find the different layers but am only showing the parent for controller program for the XY stage. Is there some way to figure out the how to click the buttons in that program? I am trying to select the run program (green box) execute the run program(blue box)
    and place the cursor in the terminal (red circle). Once the cursor is in the terminal all I have to do is send "enter".Name:  Galil.jpg
Views: 166
Size:  42.3 KB

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,047

    Re: Automation Help Needed (VB 2008 Express)

    I haven't used Winspector, but I have used Spy++....though several years back. Spy++ gives you a window that shows all windows currently in existence, so close everything other than Spy++ (including the program you want to look at), and take a look at the list of windows. Most of it will be hard to understand, you just want to look it over. Then open the target program and you will see new stuff on the window in Spy++.

    Note that this is ALL the windows. Every control is a window. A button is a window, a control is a window, a form may be several, nested, windows. The key is that they are always in the same relationship to one another. So, you may not be able to identify what every window is (though the crosshairs tool may help with that), but if you find that the button is the 4th sibling of the third nested child of the form, then it will ALWAYS be the 4th sibling of the third nested child of the form, which is what JMC was talking about.

    The trick is to figure out which window is the button. Sometimes this is easy, sometimes it isn't. Opening and closing the program while watching what Spy++ is showing will usually suffice. Winspector may do something similar.
    My usual boring signature: Nothing

  5. #5

    Thread Starter
    New Member
    Join Date
    Jul 2017
    Posts
    6

    Re: Automation Help Needed (VB 2008 Express)

    Ok, I have gone through Spy++ and Winspector to locate the parent and children windows. The program pictured in my last post seems to be used as (for lack of a better term) a "docking station." I am able to separate each window by double clicking it. This causes a new window to appear outside of the initial window. Once that happens I am able to get the parent for that window. I have rewritten my code and am still having issues.

    First: I cannot hit "enter" unless I use sendkeys.
    Second: I cannot switch between windows unless I use appactivate.


    Code:
    Imports System.Threading
    Public Class Form1
    #Region "Methods And Functions Declaration"
        Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32
        Public Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Int32) As Int32
        Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32
    #End Region
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim Pax1 As Integer = FindWindow(Nothing, "QUADRANT A input")
            Dim Pax2 As Integer = FindWindow(Nothing, "QUADRANT A capture")
            Dim Pax3 As Integer = FindWindow(Nothing, "FINISHED")
            Dim Galil As Integer = FindWindow(Nothing, "Terminal")
            'This section works.
            SetForegroundWindow(Pax1) 
            Start()
            SetForegroundWindow(Pax2)
            Thread.Sleep(1000)
            Image()
            'This section does not work.
            Do 
                If ((Not Pax2 = 0) = True) Then
                    SetForegroundWindow(Galil)
                    Move1()
                    SetForegroundWindow(Pax2)
                    Image()
                End If
                If ((Not Pax3 = 0) = True) Then
                    SetForegroundWindow(Pax3)
                    Finish()
                End If
            Loop
    
        End Sub
        Sub Start()
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(1000)
            SendKeys.SendWait("{ENTER}")
            Thread.Sleep(1000)
        End Sub
        Sub Image()
            Thread.Sleep(1000)
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(500)
            SendKeys.SendWait("{ENTER}")
            Thread.Sleep(500)
        End Sub
        Sub Move1()
            Thread.Sleep(500)
            SendKeys.SendWait("{ENTER}")
            Thread.Sleep(500)
        End Sub
        Sub Finish()
            Thread.Sleep(3000)
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(500)
            SendKeys.SendWait("{ENTER}")
            Close()
        End Sub
    End Class

  6. #6

    Thread Starter
    New Member
    Join Date
    Jul 2017
    Posts
    6

    Re: Automation Help Needed (VB 2008 Express)

    UPDATE:
    I was able to hit "Enter" using:
    Code:
    SendMessage(Pax2, WM_KEYDOWN, 13, 1)
    SendMessage(Pax2, WM_KEYUP, 13, 1)
    Instead of:
    Code:
     SendKeys.SendWait("{ENTER}")
    Now I need to figure out how to do it with "Tab."

    Note:
    I been testing this out in a smaller form of the code I posted earlier. I am only accessing on of the programs right not to make sure sendmessage is working. So I still don't know if any of the full code works yet.

  7. #7

    Thread Starter
    New Member
    Join Date
    Jul 2017
    Posts
    6

    Re: Automation Help Needed (VB 2008 Express)

    I found out through trial and error, mostly error, that I am working with two different types of windows. One is a textbox and the other is a window. I was able to figure out that I needed two different codes to essentially do the same thing.

    My issue now is each part works individually, send "ENTER, click "OK", but as a whole it is not working. If the first section is not omitted then it works then hangs before the "Do". If I omit the first section the loop works but skips shots because the window is not always there.

    I need a way for it to start and stop based on when a window is active. Ideally, if window is there, preform actions, if not then stop. Then when/if window shows up again preform actions.

    Code:
    Imports System.Threading
    Public Class Form1
    #Region "Methods And Functions Declaration"
    
        Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32
        Public Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Int32) As Int32
        Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32
        Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByRef lParam As Int32) As Int32
        Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByRef lParam As String) As Int32
    
    
        Public Const BM_CLICK As Long = &HF5&
        Public Const WM_KEYDOWN As Long = &H100
        Public Const WM_KEYUP As Long = &H101
    
    
    #End Region
        Dim a As New Process
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim QuadA As Integer = FindWindow(Nothing, "QUADRANT A input")
            Dim QuadOk As Integer = FindWindowEx(QuadA, Nothing, "Button", "OK")
            Dim CapA As Integer = FindWindow(Nothing, "QUADRANT A capture")
            Dim CapOk As Integer = FindWindowEx(CapA, Nothing, "Button", "OK")
            Dim FinA As Integer = FindWindow(Nothing, "FINISHED")
            Dim FinOk As Integer = FindWindowEx(FinA, Nothing, "Button", "OK")
            Dim Galil As Integer = FindWindow(Nothing, "Terminal")
    
            If (Not QuadA = 0) Then
                'Click "OK" "QUADRANT A input"
                SetForegroundWindow(QuadA)
                SendMessage(QuadOk, BM_CLICK, 0, 0)
                Thread.Sleep(1000)
                'Click "OK" "QUADRANT A capture"
                SetForegroundWindow(CapA)
                SendMessage(CapOk, BM_CLICK, 0, 0)
                Thread.Sleep(1000)
                'Start Loop
                Do
                    If (Not CapA = 0) Then
                        'Send "ENTER" to Terminal
                        SetForegroundWindow(Galil)
                        SendMessage(Galil, WM_KEYDOWN, 13, 1)
                        SendMessage(Galil, WM_KEYUP, 13, 1)
                        Thread.Sleep(3000)
                        'Click "OK" "QUADRANT A capture"
                        SetForegroundWindow(CapA)
                        SendMessage(CapOk, BM_CLICK, 0, 0)
                        Thread.Sleep(3000)
                    End If
                    'FINISH
                    If (Not FinA = 0) Then
                        'Click "OK" "FINISHED"
                        SetForegroundWindow(FinA)
                        SendMessage(FinOk, BM_CLICK, 0, 0)
                    End If
                Loop
            End If
        End Sub
    End Class

  8. #8

    Thread Starter
    New Member
    Join Date
    Jul 2017
    Posts
    6

    Re: Automation Help Needed (VB 2008 Express)

    Here is what I ended up with. It is a combination of sendkeys and key presses. Each program required a different one. The text wanted the buttons and the window wanted the sendkeys.
    Code:
    Imports System.Threading
    Public Class Form1
    #Region "Methods And Functions Declaration"
    
        Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32
        Public Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Int32) As Int32
        Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32
        Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByRef lParam As Int32) As Int32
        Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByRef lParam As String) As Int32
    
    
        Public Const WM_KEYDOWN As Long = &H100
        Public Const WM_KEYUP As Long = &H101
    
    #End Region
    
        Dim a As New Process
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            
            Dim Galil As Integer = FindWindow(Nothing, "Terminal")
            Dim objShell
    
            objShell = CreateObject("WScript.Shell")
    
    
            AppActivate("QUADRANT A input")
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(1000)
            SendKeys.SendWait("{ENTER}")
            Thread.Sleep(1000)
           
            AppActivate("QUADRANT A capture")
            SendKeys.SendWait("{TAB}")
            Thread.Sleep(1000)
            SendKeys.SendWait("{ENTER}")
            Thread.Sleep(1000)
    
            Do
    
                If (objShell.AppActivate("QUADRANT A capture") = True) Then
    
                    Do
                        SetForegroundWindow(Galil)
                        SendMessage(Galil, WM_KEYDOWN, 13, 1)
                        SendMessage(Galil, WM_KEYUP, 13, 1)
                        Thread.Sleep(3000)
    
                        AppActivate("QUADRANT A capture")
                        SendKeys.SendWait("{TAB}")
                        Thread.Sleep(1000)
                        SendKeys.SendWait("{ENTER}")
                        Thread.Sleep(3000)
                        Exit Do
                    Loop Until (objShell.AppActivate("FINISHED") = True)
                End If
            Loop Until (objShell.AppActivate("FINISHED") = True)
    
            Do
                If (objShell.AppActivate("FINISHED") = True) Then
                    AppActivate("FINISHED")
                    SendKeys.SendWait("{TAB}")
                    Thread.Sleep(1000)
                    SendKeys.SendWait("{ENTER}")
                    Application.Exit()
                End If
            Loop
        End Sub
    End Class

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