How can I set up a many-formed WinForms application to know when it's being switched out to and in from another app, including possibly another instance of itself?

Robert Gustafson 606 Reputation points
2023-01-12T07:05:08.2333333+00:00

WHAT I HAVE:

Visual Basic 2019, WinForms, .NET Framework 4.6+

MY ISSUE:

I have a WinForms app with several forms where, in order to avoid behavioral conflicts with other apps, including other instances of itself (same program, different process), I need to be able to detect when the current instance of the program is about to be swapped out for another process or has just been swapped in from one. Unfortunately, Application events for a WinForms app doesn't support AppActivate and AppDeactivate events like a WPF app does. I know that the WM_ACTIVATEAPP message can be caught to detect this kind of thing, but I need to know how to properly do so.

Should I catch the message in every form of my app, in the main form (the MDI parent form), or the currently activate form at a given moment? Will it detect when the current instance of the app is being swapped with another instance of the same app (as my app supports multiple instancing)? Will it detect when the CPU switches to or from another app--once again, including another instance of itself--not because a window therein is suddenly being activated programmatically or via user action, but because, due to the preemptive nature of Win32/Win64 multitasking, it's decided that it's time for it to get a time-slice turn (or has had its turn)? (After all, an app doesn't have to be in an "idle" state to have to yield to another one!) I'm looking for the most foolproof solution that is still relatively simple. (I also imagine that it shouldn't be too difficult to deal with situations where my app invokes another one on purpose--i.e., using the Process class. Also, if there's an easier or more reliable technique than WM_ACTIVATEAPP for my WinForms project, please tell me.)

Please provide any answer ASAP, in VB.NET (if you show code, don't just include declares and constants--provide an actual, general-purpose example with executable [procedural] code), and as simply as possible.

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,825 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,569 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,118 questions
{count} votes

Accepted answer
  1. Reza Aghaei 4,936 Reputation points MVP
    2023-01-15T01:31:49.3066667+00:00

    To conclude the discussions in the comments under the question, I'd like to share this code sample based on my original answer in stackoverflow: Application got/lost focus event and add a few point to address some of your concerns.

    Use WM_ACTIVATEAPP to detect activated or deactivated of your App

    I'd suggest you rely on handling WM_ACTIVATEAPP, only in your main form, like this:

    Public Class MainForm
        Private Const WM_ACTIVATEAPP As Integer = &H1C
        Protected Overrides Sub WndProc(ByRef m As Message)
            MyBase.WndProc(m)
            If (m.Msg = WM_ACTIVATEAPP) Then
                If (m.WParam.ToInt32() = 0) Then
                    Me.Text = "Deactivated"
                Else
                    Me.Text = "Activated"
                End If
            End If
        End Sub
    End Class
    

    The other option that I suggested in my original answer and in the comments was Activated and Deactivated events; You may be able to use Activated and Deactivate event, but there are some caveats for that, one is you need to implement it in all your top-level forms; even though you mentioned you are using MDI, but there might be cases that in addition to MDI Children you show a modal as well, then in addition to the MDI Container form, you need the logic in those modals as well. Another caveat is showing system modals, like MessageBox, or SaveFileDialog, and etc. In these cases you cannot handle Activated/Deactovated events. So To have a reliable solution, I'd suggest you stick to the WM_ACTIVATEAPP.

    Do I need to handle it in all windows of my app?

    While all the top-level windows of your application receive WM_ACTIVATEAPP, but you do not need to handle the message in them all; just handle it in your main form.

    Multiple instance of my application may be running at the same time. Is there any chance for a problem when handling this message?

    Different instances of an app are different processed, so when one instance is activated, the other one will be deactivated. So, no, there's no chance for any problem.

    Is there any way to make the code reusable, like a dll, etc.?

    Yes, you can put the logic in a NativeWindow, like this:

    Public Class ApplicationHelper
        Inherits NativeWindow
        Sub New(MainForm As Form)
            Me.AssignHandle(MainForm.Handle)
        End Sub
        Private Const WM_ACTIVATEAPP As Integer = &H1C
        Public Event ActivateApp As EventHandler(Of Boolean)
        Protected Overrides Sub WndProc(ByRef m As Message)
            MyBase.WndProc(m)
            If (m.Msg = WM_ACTIVATEAPP) Then
                RaiseEvent ActivateApp(Me, Not (m.WParam.ToInt32() = 0))
            End If
        End Sub
    End Class
    

    Then use it in any application like this:

    Public Class MainForm
        Private helper As ApplicationHelper
        Protected Overrides Sub OnHandleCreated(e As EventArgs)
            MyBase.OnHandleCreated(e)
            helper = New ApplicationHelper(Me)
            AddHandler helper.ActivateApp, AddressOf Helper_ActivateApp
        End Sub
        Private Sub Helper_ActivateApp(sender As Object, e As Boolean)
            Me.Text = e.ToString()
        End Sub
    End Class
    
    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 55,366 Reputation points
    2023-01-13T19:58:21.9533333+00:00

    the AppActivate is just the WCF handling of the WM_ACTIVATEAPP event in windows.

    this event has nothing to do with the O/S process scheduler. It's an event from the windowing system that your app window got the focus and input queues. in the windowing system there is one active app that has the focus (input is directed to this app). the active app can be swapped out of memory for any background process or other app that want to update its own window.

    a sample from the docs:

    [https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.wndproc?view=windowsdesktop-7.0