How to be notified when your application is activated and deactivated
I recently had a requirement where a user was able to perform an action externally to my application, and my application then had to detect this for processing.
I could of course just had a poller running away in the background to check, but as the requirement also needed user input, why not just wait until the user switched back to my application, then check and deal with accordingly?
The Activated and Deactivate events
Your standard Form
object has an Activated
event and a
Deactivate
event that (very logically!) are fired when your
form is activated and deactivated.
Brilliant! Well, it would be - if your application is a single
form application that doesn't show any window ever. Including
message boxes. Still, you could do it that way, if your
processing was absolute and always done there and then. In my
case, I had to give the user a choice - if they said no, then I
would simply ask them again later (ie the next time the
application was activated). But if I stuck with the Activated
event it would mean they would get prompted after displaying
another dialog in my application... probably not the sort of
behaviour you want to exhibit.
The WM_ACTIVATEAPP message
So how does Windows do it? It does it via the use of the
WM_ACTIVATEAPP
(MSDN reference). Windows sends this
message when a window belonging to a different application than
the active window is about to be activated. It's also good
enough enough to send it to the window about to be deactivated
too, so this one message can cover both activation and
deactivation.
Overriding WndProc
Even after all these years of being a C# developer, I still marvel at just how easy this stuff is. In my VB6 days, I could (and did) do exactly the same thing, but it was difficult to implement and fun to debug.
To handle Windows Messages in C# we just need to override the
WndProc
method on your Form
. Then we can check for the
WM_ACTIVATEAPP
message arriving and handle it accordingly.
const int WM_ACTIVATEAPP = 0x1C;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_ACTIVATEAPP)
{
if (m.WParam != IntPtr.Zero)
{
// the application is getting activated
}
else
{
// the application is getting deactivated
}
}
base.WndProc(ref m);
}
According to the MSDN docs, lParam
contains the thread
identifier, however we can safely ignore this. wParam
(the
WParam
property on the Message
struct) is the important bit.
It's a simple true or false value (true for activation, false
otherwise) and so we just need to check it isn't zero and we're
good to go.
Add some events
You could just stick that override in your applications form and use it like that, but as always we should think a little bit about the future and promote some code re-use! In this case, I'm going to create a pair of events and add them (along with the override) to a base class, so next time I want this functionality the events are sitting there waiting.
public class BaseApplicationForm : Form
{
public event EventHandler ApplicationActivated;
public event EventHandler ApplicationDeactivated;
protected virtual void OnApplicationActivated(EventArgs e)
{
EventHandler handler;
handler = this.ApplicationActivated;
if (handler != null)
handler(this, e);
}
protected virtual void OnApplicationDeactivated(EventArgs e)
{
EventHandler handler;
handler = this.ApplicationDeactivated;
if (handler != null)
handler(this, e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == NativeMethods.WM_ACTIVATEAPP)
{
if (m.WParam != IntPtr.Zero)
this.OnApplicationActivated(EventArgs.Empty);
else
this.OnApplicationDeactivated(EventArgs.Empty);
}
base.WndProc(ref m);
}
}
A simple demonstration
You can download the demonstration code from the end of this post, but here's a simple example of the code in use:
public partial class MainForm : BaseApplicationForm
{
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
this.LogEvent("Activated");
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
this.LogEvent("Deactivate");
}
protected override void OnApplicationActivated(EventArgs e)
{
base.OnApplicationActivated(e);
this.LogEvent("ApplicationActivated");
}
protected override void OnApplicationDeactivated(EventArgs e)
{
base.OnApplicationDeactivated(e);
this.LogEvent("ApplicationDeactivated");
}
private void LogEvent(string text)
{
logTextBox.AppendText(string.Format("{0}\t{1}\n\n", DateTime.UtcNow.ToString("hh:mm:ss"), text));
}
}
The Activated
, Deactivate
, ApplicationActivated
and
ApplicationDeactivated
events are all being used (well, their
overrides are) to log information. If you run the example, you
will see that Activated
and Deactivate
are called whenever
the form itself is processed, ie from opening a dialog or
displaying a message box, whilst the ApplicationActivated
and
ApplicationDeactivated
events are only called when I switch to
another application.
Closing Thoughts
In the above example, the ApplicationActivated
and
ApplicationDeactivated
events are raised as expected -
including if you already have a modal dialog open in your
application. Just something to keep in mind if you use this sort
of functionality to prompt the user for an action. If your
events are showing their own modal dialog, that's fine, but if
they are trying to do something else, such as set focus to a
control, or open a floating window - then you're likely to run
into problems.
Update History
- 2013-12-29 - First published
- 2020-11-21 - Updated formatting
Downloads
Filename | Description | Version | Release Date | |
---|---|---|---|---|
AppActivationDemo.zip
|
Sample file for the article How to be notified when your application is activated and deactivated |
29/12/2013 | Download |
Leave a Comment
While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?
Comments
Daniel
#
Brilliant sollution, was looking or something like this and it worked perfectly. Thank you!
Mark
#
Very helpful solution. Thank you!