[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Automated completion of interactive application from vb .net process

Posted on 2011-05-03
5
Medium Priority
?
298 Views
Last Modified: 2012-05-11
We have 50 seats of AutoCAD and want to automate the AutoCAD settings transfer wizard which has no OLE or command line overrides. I have been able to run it under a process in vb .net but even if when this has focus I can't get sendkeys to do the job. I have been trying to sendtext or sendmessage directly to the controls but again without success.

You can see the commented out sendmessage code which almost works and the PostMessageToWindow function which includes the handle of the edit control (obtained using Spy++) but displays the failure message.

Any suggestions?

Stephen Solt
IT Consultant
CZWG Architects
LONDON


<DllImport("user32.dll", CharSet:=CharSet.Ansi, SetLastError:=True, ExactSpelling:=True)> _
    Public Shared Function SetForegroundWindow(ByVal hwnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    <DllImport("User32.dll", CharSet:=CharSet.Auto, Entrypoint:="SendMessage")> _
    Public Shared Function SendMessageString(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wparam As Integer, _
    ByVal lparam As System.Text.StringBuilder) As IntPtr
    End Function
    <DllImport("user32.dll", CharSet:=CharSet.Ansi, SetLastError:=True, ExactSpelling:=True)> _
    Public Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As String, ByVal cch As Long) As Long
    End Function
    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function SetWindowText(ByVal hwnd As IntPtr, ByVal lpString As String) As Boolean
    End Function

    Private Sub PostMessageToWindow()
        Dim hwndEdit As IntPtr = &HA0E00 ' 30872
        Dim lpString As String
        lpString = Path.Combine(cSettingsFolder, cSettingsFile) '& vbNullChar
        SendText(hwndEdit, lpString)
    End Sub

    Public Sub SendText(ByVal ControlHandle As IntPtr, ByVal Text As String)
        Dim ptrRet As IntPtr
        SendMessageString(ControlHandle, WM_SETTEXT, 0, New System.Text.StringBuilder(Text))
        If ptrRet.Equals(IntPtr.Zero) Then MessageBox.Show("The SendMessage API call failed!")
    End Sub

    Private Sub CZWGSettings()
        Dim myProcess As Process = New Process()
        myProcess.StartInfo.WorkingDirectory = cSettingsFolder
        myProcess.StartInfo.FileName = IO.Path.Combine(cMigratorPath, cMigratorExe)
        myProcess.StartInfo.Arguments = "/i"
        myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal
        myProcess.Start()
        Me.ToolStripStatusLabel1.Text = "Applying your settings..."
        Me.ToolStripProgressBar1.Value = 70
        myProcess.WaitForInputIdle()
        SetForegroundWindow(myProcess.Handle)
        'GetChildWindows()
        PostMessageToWindow()
        'SendKeys.Send("%D")
        'myProcess.WaitForInputIdle()
        'Application.DoEvents()
        'SetForegroundWindow(myProcess.Handle)
        'SendKeys.Send(cSettingsFolder)
        'myProcess.WaitForInputIdle()
        'Application.DoEvents()
        'SetForegroundWindow(myProcess.Handle)
        'SendKeys.Send("{ENTER}")
        'myProcess.WaitForInputIdle()
        'Application.DoEvents()
        'myProcess.WaitForInputIdle()
        'SetForegroundWindow(myProcess.Handle)
        'SendKeys.Send("%N")
        'myProcess.WaitForInputIdle()
        'Application.DoEvents()
        'myProcess.WaitForInputIdle()
        'SetForegroundWindow(myProcess.Handle)
        'SendKeys.Send(cSettingsFile)
        'myProcess.WaitForInputIdle()
        'Application.DoEvents()
        'SetForegroundWindow(myProcess.Handle)
        SendKeys.Send("%O")
        myProcess.WaitForInputIdle()
        Application.DoEvents()
        SetForegroundWindow(myProcess.Handle)
        Me.ToolStripProgressBar1.Value = 60
        myProcess.WaitForExit()
        Console.WriteLine("Migrate Settings ended: " & myProcess.ExitTime & "." & NewLine & "Exit Code: " & myProcess.ExitCode)
        myProcess.Close()
        Me.ToolStripProgressBar1.Value = 100
    End Sub

Open in new window

SettingsWizard.jpg
0
Comment
Question by:czwg
  • 3
  • 2
5 Comments
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 2000 total points
ID: 35515544
At line #16 in PostMessageToWindow(), you CAN'T hard-code a window handle!

        Dim hwndEdit As IntPtr = &HA0E0

You have to determine the current handle value at run-time as it will be different every time the application is run.  Window handles are assigned by the operating system...

Spy++ is a good tool to determine the class name and window hierarchy of windows in the dialog.  Using that information can be useful in crafting the proper sequence of API calls to get the correct handle.  You can use APIs like FindWindow()/FindWindowEx(), GetWindow()/GetNextWindow(), or EnumWindows()/EnumChildWindows() to get the right handle value at run-time.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 35515573
Also, your GetWindowText() declaration should have Integer instead of Long.   (Long is used for VB6)
0
 

Author Comment

by:czwg
ID: 35688515
I had suspected that Windows handles were not constants but I wasn't looking forward to enumerating the windows hierarchy to get to the control I wanted. I have solved this in the dim distant past when I was a keen young VB5 programmer.

I'm inclined to accept Idle Mind's first comment as the solution - he has shown me the way forward, but I just wonder if my approach is the best solution to the objective?

What are the issues deciding whether to use SendMessageString or SetWindowText?

Steve
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 35689596
It really just depends on the target control you're automating.  Controls in different languages don't always respond as you might expect with one approach so you end up having to try another.  Just have to try it and see what happens...
0
 

Author Closing Comment

by:czwg
ID: 35704977
I was hoping that someone might spoon feed me a complete solution, but that's just lazy. Idle Mind has given me all I need to solve the task myself!
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signal…
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
Suggested Courses

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question