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