Controlling Child Windows of external apps

Woody

Member
Joined
Apr 8, 2005
Messages
7
Programming Experience
Beginner
Hello everyone,

I am hoping someone may be able to assist me with this issue. I have an application which launches another and has to send keystrokes etc to the external application.

I am having trouble gathering the child window information.

Here's where I am so far.

VB.NET:
 Module ApplicationAutomation 

Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd _

As Integer) As Integer

Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal _

hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 _

As String) As Long

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _

(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function SendMessage Lib "user32" Alias "SendMessageA" _

(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _

ByVal lParam As Long) As Long

Public Function ApplicationAutomation()
 
Dim appPID As Integer = Shell("..\main.exe", AppWinStyle.NormalFocus)

Threading.Thread.Sleep(5000)

SetForegroundWindow(appPID)
 
'Get the main window handle
Dim MWnd As Long = FindWindow("MainClass", vbNullString)
 
'Get the child window handle
Dim CWnd As Long = THIS IS WHERE I GET CONFUSED
SetForegroundWindow(CWnd) ????

SendKeys.Send(vbCrLf)  <--- Need to send a carriage return to the child

End Function
End Module


 
Does anyone not have any advise? I am writting an application containing the abilty to automate several different applications which ultimately automates a handful of weekly tasks.

Thanks
 
Hi Woody,
May I ask you a favour,
Do you have the codes on monitoring a child window and top level window?
Need help urgently!!!
 
Child Windows

I had searched high and low for code examples, explainations, and anything I could come up with for an affective way to control child windows in VB.NET. At most I was able to pick up bits and pieces here and there and puzzle them all together to come up with the following:

First lets import system.diagnostics and interopservices

VB.NET:
Imports[size=2] System.Diagnostics[/size]
Imports[size=2] System.Runtime.InteropServices
[/size]

Next declare your variables
VB.NET:
Public hWndTmp As Integer
Public hWndChild As Integer

Next import the user32.dll to utilize the windows API call.
VB.NET:
<DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi, CharSet:=CharSet.Auto)> _
	Public Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
	End Function
	<DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi, CharSet:=CharSet.Auto)> _
	Public Function FindWindowEx(ByVal hWnd1 As Integer, _
	ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
	End Function

Find the main window by calling the API as follows:

findwindow(WINDOW CLASS NAME,WINDOW TITLE)

This example will return the handler id of the notepad window titled "Untitled"
VB.NET:
hWndTmp = FindWindow("Notepad","Untitled - Notepad")
or
This example will return the window handler id of the first instance of notepad.
VB.NET:
hWndTmp = FindWindow("Notepad", VBNullString)

Getting the child window....
This exampled returns the handle id of the "edit" child window of notepad
The function is findwindowex(PARENT CLASS,START POS,CHILD CLASS,CHILD TITLE)
VB.NET:
hWndChild = FindWindowex(hWndTmp,0,"Edit","")
in this example the edit window in notepad does not have a title. We start at the 0 position to insure all child windows are searched for the class and or title. in this case both. Again this can be obtained by using the following as well.
VB.NET:
hWndChild = FindWindowex(hWndTmp,0,"Edit",vbnullstring)

of course if you need to get the child id of a child window then you would continure to utilze the findwindowex function as such:

hWndChild = FindWindowEx(hWndChild,0,GRANDCHILDCLASS,GRANDCHILDTITLE)

hope this helps and gives an explanation of how to go about getting the handle ids.

As far as "monitoring" the windows. Simply write a function that will utilze these APIs for the changes your looking for.

 
Hi woody thanks for your help. But I stil new to this. Hope you can guide me through...
Below is the full code that I've written:

VB.NET:
 Imports System.Diagnostics 
Imports System.Runtime.InteropServices
Public Class Form1
Inherits System.Windows.Forms.Form
Friend WithEvents MainMenu1 As System.Windows.Forms.MainMenu
Public hWndTmp As Integer
Public hWndChild As Integer
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
End Sub
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer. 
'Do not modify it using the code editor.
 
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Private Sub InitializeComponent()
Me.MainMenu1 = New System.Windows.Forms.MainMenu
 
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(160, 240)
Me.Button1.Name = "Button1"
Me.Button1.TabIndex = 1
Me.Button1.Text = "Notepad"
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(80, 240)
Me.Button2.Name = "Button2"
Me.Button2.TabIndex = 0
Me.Button2.Text = "Child"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Menu = Me.MainMenu1
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
#End Region
 
<DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi, 
harSet:=CharSet.Auto)> _
Public Function FindWindow(ByVal lpClassName As String, ByVal 
IpWindowName As String) As Integer
End Function
 
<DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi, 
CharSet:=CharSet.Auto)> _
 
Public Function FindWindowEx(ByVal hWnd1 As Integer, _
ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As 
Integer
End Function
 
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As 
System.EventArgs) Handles Button1.Click
hWndTmp = FindWindow("Notepad", "Untitled - Notepad")
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As 
 
System.EventArgs) Handles Button2.Click
hWndChild = FindWindowEx(hWndTmp, 0, "Edit", "")
End Sub
 
End Class

I've created a button each for the hWndTmp & hWndChild in order to handle them. But after I start debugging and pressed the corressponding buttons, This error occurs: An unhandled exception of type 'System.InvalidProgramException' occurred in monitor.exe
Additional information: Error: PInvoke item (field,method) must be Static.
 
Re: Getting the child handlers

Zack,

Add a new module to your solution in the example below I have named it WndHnd.vb.

Use the following code in the module:

VB.NET:
[size=2][color=#0000ff]Imports[/color][/size][size=2] System.Diagnostics[/size]
[size=2][color=#0000ff]Imports[/color][/size][size=2] System.Runtime.InteropServices[/size]
[size=2][color=#0000ff]Module[/color][/size][size=2] WndHnd[/size]
[size=2][/size] 
[size=2]<DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi, CharSet:=CharSet.Auto)> _[/size]
[size=2][color=#0000ff]Public[/color][/size][size=2] [/size][size=2][color=#0000ff]Function[/color][/size][size=2] FindWindow([/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] lpClassName [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]String[/color][/size][size=2], [/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] IpWindowName [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]String[/color][/size][size=2]) [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]Integer[/color][/size]
[size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Function[/color][/size]
[size=2][color=#0000ff] 
[/color][/size][size=2]<DllImport("user32.dll",CallingConvention:=CallingConvention.Winapi,_
CharSet:=CharSet.Auto)> [/size][size=2][color=#0000ff]Public[/color][/size][size=2] [/size][size=2][color=#0000ff]Function[/color][/size][size=2] FindWindowEx([/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] hWnd1 [/size][size=2][color=#0000ff]As _[/color][/size]
[size=2][color=#0000ff]Integer[/color][/size][size=2], [/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] hWnd2 [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]Integer[/color][/size][size=2], [/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] lpsz1 [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]String[/color][/size][size=2], _[/size]
[size=2][color=#0000ff]ByVal[/color][/size][size=2] lpsz2 [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]String[/color][/size][size=2]) [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]Integer[/color][/size]
[size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Function
End[/color][/size][size=2] [/size][size=2][color=#0000ff]Module[/color][/size]
[size=2][color=#0000ff]
[/color][/size]

Next, modify your code for form1.vb

VB.NET:
[/color]
[size=2][color=#0000ff][size=2][color=#0000ff]Public[/color][/size][size=2][color=#000000] [/color][/size][size=2][color=#0000ff]Class[/color][/size][size=2][color=#000000] Form1[/color][/size][/color][/size]
[size=2][color=#0000ff][size=2][color=#0000ff]Inherits[/color][/size][size=2] System.Windows.Forms.Form[/size][/color][/size]
[size=2][color=#0000ff][size=2][color=#0000ff]Friend[/color][/size][size=2] [/size][size=2][color=#0000ff]WithEvents[/color][/size][size=2] MainMenu1 [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.Windows.Forms.MainMenu[/size][/color][/size]
[size=2][color=#0000ff][/color][/size] 
[size=2][color=#0000ff][size=2][color=#0000ff]Public[/color][/size][size=2] hWndTmp [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]Integer[/color][/size][/color][/size]
[size=2][color=#0000ff][size=2][color=#0000ff]Public[/color][/size][size=2] hWndChild [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]Integer[/color][/size][/color][/size]
[size=2][color=#0000ff][/color][/size] 
[size=2][color=#0000ff][size=2]#[/size][size=2][color=#0000ff]Region[/color][/size][size=2] " Windows Form Designer generated code "[/size]
[size=2][color=#0000ff]Public[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub[/color][/size][size=2] [/size][size=2][color=#0000ff]New[/color][/size][size=2]()[/size]
[size=2][color=#0000ff]MyBase[/color][/size][size=2].New()
[/size][size=2][color=#008000]'This call is required by the Windows Form Designer.

[/color][/size][size=2]InitializeComponent()

[/size][size=2][color=#008000]'Add any initialization after the InitializeComponent() call

[/color][/size][size=2][/size][size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub

[/color][/size][size=2][/size][size=2][color=#008000]'Form overrides dispose to clean up the component list.

[/color][/size][size=2][/size][size=2][color=#0000ff]Protected[/color][/size][size=2] [/size][size=2][color=#0000ff]Overloads[/color][/size][size=2] [/size][size=2][color=#0000ff]Overrides[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub[/color][/size][size=2] Dispose([/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] disposing [/size][size=2][color=#0000ff]As[/color][/size][size=2] [/size][size=2][color=#0000ff]Boolean[/color][/size][size=2])

[/size][size=2][color=#0000ff]MyBase[/color][/size][size=2].Dispose(disposing)

[/size][size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub

[/color][/size][size=2][/size][size=2][color=#008000]'NOTE: The following procedure is required by the Windows Form Designer

[/color][/size][size=2][/size][size=2][color=#008000]'It can be modified using the Windows Form Designer. 

[/color][/size][size=2][/size][size=2][color=#008000]'Do not modify it using the code editor.

[/color][/size][size=2][/size][size=2][color=#0000ff]Friend[/color][/size][size=2] [/size][size=2][color=#0000ff]WithEvents[/color][/size][size=2] Button1 [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.Windows.Forms.Button

[/size][size=2][color=#0000ff]Friend[/color][/size][size=2] [/size][size=2][color=#0000ff]WithEvents[/color][/size][size=2] Button2 [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.Windows.Forms.Button

[/size][size=2][color=#0000ff]Private[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub[/color][/size][size=2] InitializeComponent()

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].MainMenu1 = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Windows.Forms.MainMenu

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button1 = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Windows.Forms.Button

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button2 = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Windows.Forms.Button

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].SuspendLayout()

[/size][size=2][color=#008000]'

[/color][/size][size=2][/size][size=2][color=#008000]'Button1

[/color][/size][size=2][/size][size=2][color=#008000]'

[/color][/size][size=2][/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button1.Location = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Drawing.Point(160, 240)

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button1.Name = "Button1"

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button1.TabIndex = 1

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button1.Text = "Notepad"

[/size][size=2][color=#008000]'

[/color][/size][size=2][/size][size=2][color=#008000]'Button2

[/color][/size][size=2][/size][size=2][color=#008000]'

[/color][/size][size=2][/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button2.Location = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Drawing.Point(80, 240)

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button2.Name = "Button2"

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button2.TabIndex = 0

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button2.Text = "Child"

[/size][size=2][color=#008000]'

[/color][/size][size=2][/size][size=2][color=#008000]'Form1

[/color][/size][size=2][/size][size=2][color=#008000]'

[/color][/size][size=2][/size][size=2][color=#0000ff]Me[/color][/size][size=2].AutoScaleBaseSize = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Drawing.Size(5, 13)

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].ClientSize = [/size][size=2][color=#0000ff]New[/color][/size][size=2] System.Drawing.Size(292, 266)

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Controls.Add([/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button2)

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Controls.Add([/size][size=2][color=#0000ff]Me[/color][/size][size=2].Button1)

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Menu = [/size][size=2][color=#0000ff]Me[/color][/size][size=2].MainMenu1

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Name = "Form1"

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].Text = "Form1"

[/size][size=2][color=#0000ff]Me[/color][/size][size=2].ResumeLayout([/size][size=2][color=#0000ff]False[/color][/size][size=2])

[/size][size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub

[/color][/size][size=2]#[/size][size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Region

[/color][/size][size=2][/size][size=2][color=#0000ff]Private[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub[/color][/size][size=2] Button1_Click([/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] sender [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.Object, [/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] e [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.EventArgs) [/size][size=2][color=#0000ff]Handles[/color][/size][size=2] Button1.Click

hWndTmp = FindWindow("IEFrame", vbNullString)

MsgBox(hWndTmp)

[/size][size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub

[/color][/size][size=2][/size][size=2][color=#0000ff]Private[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub[/color][/size][size=2] Button2_Click([/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] sender [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.Object, [/size][size=2][color=#0000ff]ByVal[/color][/size][size=2] e [/size][size=2][color=#0000ff]As[/color][/size][size=2] System.EventArgs) [/size][size=2][color=#0000ff]Handles[/color][/size][size=2] Button2.Click

hWndChild = FindWindowEx(hWndTmp, 0, "Edit", "")

[/size][size=2][color=#0000ff]End[/color][/size][size=2] [/size][size=2][color=#0000ff]Sub

End[/color][/size][size=2][color=#000000] [/color][/size][size=2][color=#0000ff]Class[/color][/size]
[size=2][color=#0000ff]
[/size]

Hope this helps!
[/color][/size]
 
Thanks Woody you are very kind to spare me your codes :)
There are no errors now in my codes.

But all it does is return the id of the notepad window. Is it possible for you to help me bring out that particular window that corressponds to the button?
 
Zack,


The same will occur for ANY window you are attempting to get the handler id for.

For example, Under the TOOLS menu of .NET studios select the Spy++ tool.

This tool will show you the windows class name and handler id's of any window.

obtain the class name of your window and use it in the findwindow function.

FindWindow("<Class from Spy++", "<Title of Window>")

Spy++ will also show you all the child windows and controls. Again use them with FindWindowEx

FindWindowEx("<HANDLE ID FROM FINDWINDOW>","<CHILD CLASS>","<CHILD TITLE>")

Once you have the handle ID you can do several things with it. Most importantly you can verify if a specific child window exists or even use SendMessage API to send clicks and keystrokes to the windows.

VB.NET:
Dim HwndTMP as integer = FindWindow("Monitor","Monitor")
if not FindWindowEx(HwndTMP,"Monitor Child Class","Child Title") = nothing then
'DO SOMETHING
Else
'DO SOMETHING ELSE
e.g treading.thread.sleep(500) ' Sleep for 1/2 a second
End if
 
Back
Top