Search code examples
vb.netpinvoke

Give focus to application control when application loses focus


I have an application which is designed to run full screen constantly. This works fine normally, however, when things run in the background, for example, an antivirus update this can bring that window above my app. Thats fine because I can use things like:

  • SetForegroundWindow
  • ShowWindow
  • SwitchToThisWindow

All of which allow me to bring my application back to the front. However, inside the application is a hidden text box which when the application loads is focussed. When I use one of the pInvoke calls above whilst the application is brought back to front, the focus is still on the existing application.

I am currently struggling with the best way of giving focus back to the control.

I could use Control.FromHandle but seems fairly complicated to get the controls I need and offer focus if a specific tab page is at the front. Is there a better way, any thoughts / ideas welcome.


Solution

  • I was running this on a Windows 10 LTSB unit and as previously mentioned SetForegroundWindow and Show functions were not working along with many other functions I found on pInvoke. I managed to select the correct process and bring it to the forefront if something else takes its place to the top. The issue was that it would never activate no matter what I tried.

    In the end, I implemented the following code which checks every 5 seconds, if my app is not the foremost and not maximised then minimise / maximise the window and this reactivates and refocuses the app:

    Public Declare Function FindWindow Lib "user32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    
        Public Declare Function ShowWindowAsync Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As IntPtr
    
        Private Declare Function GetWindowPlacement Lib "user32.dll" (ByVal hWnd As IntPtr, ByRef lpwndpl As WINDOWPLACEMENT) As Boolean
    
        Private Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr
    
        <Serializable>
        Friend Structure WINDOWPLACEMENT
            Public length As Integer
            Public flags As Integer
            Public showCmd As ShowWindowCommands
            Public ptMinPosition As System.Drawing.Point
            Public ptMaxPosition As System.Drawing.Point
            Public rcNormalPosition As System.Drawing.Rectangle
        End Structure
    
        Friend Enum ShowWindowCommands
            Hide = 0
            Normal = 1
            Minimized = 2
            Maximized = 3
        End Enum
    
        Private Async Function CheckCurrentApp() As Task
    
            Try
    
                ' Try and locate the core process
                Dim coreHandle = FindWindow(Nothing, "Name of window")
                If coreHandle = IntPtr.Zero Then
                    ' Can't find the core. Exit here.
                    Exit Try
                End If
    
                ' Get information about the Core window
                Dim currentWindowInfo As WINDOWPLACEMENT
                GetWindowPlacement(coreHandle, currentWindowInfo)
    
                ' If the core is not the foreground window or isn't maximised then send a minimise (6) and maximise (3) request.
                ' Activate functions in user32 don't work - I spent a day trying to make it so. I could get the foreground window as the core but the input would 
                ' remain in a different application.
                If coreHandle <> GetForegroundWindow() OrElse currentWindowInfo.showCmd <> ShowWindowCommands.Maximized Then
                    ShowWindowAsync(coreHandle, 6)
                    ShowWindowAsync(coreHandle, 3)
                End If
    
            Catch ex As Exception
                ' DO SOMETHING WITH THE EXCEPTION.
            End Try
    
            Await Task.Delay(TimeSpan.FromSeconds(5))
            Await CheckCurrentApp()
        End Function