Home > Software design >  FindWindowEx random failures getting child window handle
FindWindowEx random failures getting child window handle

Time:07-06

I have a VB.NET 4.6.1 desktop app that has been using FindWindow and FindWindowEx for over 2 years with no issue to locate a MDI child window and capture the window caption text, it has worked flawlessly until recent.
The behavior now is my app can only successfully obtain the MDI client window handle if I go back to either the parent window or MDI client and click anywhere on either window, then return to my app and the process succeeds.

I have tried adding threading sleep events, running the action continuously in a loop multiple times, calling AppActivate method using process ID (thinking I just needed to execute again), my next workaround thought is to try and send a click event to the parent window prior to my action being executed or maybe to use Enumerate all child windows of the parent, hope someone can suggest something because I am at a roadblock, been doing this for years but this one doesn't make sense to me, I have the suspicion that it is related to recent ownership of the software company and them revising this section, but I have no idea why it would interfere with these root level API methods.

Sample Code:

MDIhWnd = FindWindowEx(ParenthWnd, IntPtr.Zero, "WindowsForms10.MDICLIENT.app.0.34f5582_r7_ad1", Nothing)
'Threading.Thread.Sleep(100)
'AppActivate(proc(0).Id)
If MDIhWnd = 0 Then
    Threading.Thread.Sleep(100)
    'Dim hw = GetTopWindow(ParenthWnd)
    For i = 0 To 500
        AppActivate(proc(0).Id)
        MDIhWnd = FindWindowEx(ParenthWnd, IntPtr.Zero, "WindowsForms10.MDICLIENT.app.0.34f5582_r7_ad1", Nothing)
        If MDIhWnd <> 0 Then
            Exit For
        End If
    Next
End If

CodePudding user response:

The solution for me was, based on the above suggestion, to use UI Automation, I had never worked with it before, however after looking it over I gave a go and found that it did indeed simplify my needs to capture window text from a 3rd party application window with MDI Client Interface.

Below is a lessor version in VB.NET of the process for anyone needing to do the same thing:

Imports System.Windows.Automation
' You will also need references to UIAutomationClient, and UIAutomationTypes

Private Sub test_ui_automation()        
Dim ParenthWnd As Integer = 0
Dim _AutomationElementA As System.Windows.Automation.AutomationElement = Nothing
Dim _AutomationElementB As System.Windows.Automation.AutomationElement = Nothing
Dim _AutomationElementC As System.Windows.Automation.AutomationElement = Nothing
Dim propCondition As Condition

Try
   'Parent Windows Process Stuff
   ParenthWnd = FindWindow(Nothing, "Application to Find")
   _AutomationElementA = AutomationElement.FromHandle(ParenthWnd)

If _AutomationElementA Is Nothing Then  
   NotifyIcon1.BalloonTipIcon = ToolTipIcon.Error
   NotifyIcon1.BalloonTipText = "Couldn't Locate Parent Window."
   NotifyIcon1.Visible = True
   NotifyIcon1.ShowBalloonTip(3000)
   Exit Sub
End If

' MDI Client Stuff
' I used ClassNameProperty but other conditions are available
propCondition = New PropertyCondition(AutomationElement.ClassNameProperty, "WindowsForms10.MDICLIENT.app.0.34f5582_r7_ad1", PropertyConditionFlags.IgnoreCase)
_AutomationElementB = _AutomationElementA.FindFirst(TreeScope.Element Or TreeScope.Children, propCondition)    

If _AutomationElementB Is Nothing Then
   NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning
   NotifyIcon1.BalloonTipText = "Application warning MDIClient not Available!"
   NotifyIcon1.Visible = True
   NotifyIcon1.ShowBalloonTip(3000)
   Exit Sub
End If  

' Final Stage Stuff Locate Window Containing Class with Caption   
propCondition = New PropertyCondition(AutomationElement.ClassNameProperty, "WindowsForms10.Window.8.app.0.34f5582_r7_ad1", PropertyConditionFlags.IgnoreCase)
_AutomationElementC = _AutomationElementB.FindFirst(TreeScope.Element Or TreeScope.Children, propCondition)

If _AutomationElementC Is Nothing Then
   NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning
   NotifyIcon1.BalloonTipText = "Automation warning, MDI Details are open."
   NotifyIcon1.Visible = True
   NotifyIcon1.ShowBalloonTip(3000)
   Exit Sub
End If

Caption = _AutomationElementC.Current.Name  
' If needed you can now parse/strip any data needed from the Caption text.
' I had other processes here but could not include in the post.

Catch ex As Exception
    MsgBox(ex.Message)
End Try

End Sub
  • Related