Introduction
Please remember that this code has not been super heavily tested, and may contain bugs. Also, I am a bit of a newbie when it comes to programming with Windows messages, so please don't be overly harsh.
Background
Recently, I was asked to add an "auto-logout" type feature to an existing Windows desktop application. It didn't seem like a big deal, but when I sat down to think about it, I realized that it would be quite a bit of work. The reason for this is that the desktop application in question has many different modal forms and each form is significantly different from all the others, and... the point is that it would have been incredibly messy to try to do some ad-hoc event handling of all events that would make us consider the application "active".
Early on in my research, I found a suggestion to look into Windows hooks. I didn't know a lot about hooks (and I still don't, honestly), so it seemed a little intimidating. But I found a few good reference implementations, pieced them together, and did a little bit of tweaking. I guess now would be a good time to document those code snippets I got:
- Even though I didn't use low-level hooks, the code I found on Steven Toub's blog was useful.
- Also, I got quite a bit from a Windows KB page.
Using the Code
The activity monitor object is a disposable object that can be declared in whatever scope you would like. In the attached demo application, it is declared as a member of the main form:
ActivityMonitor.ActivityMonitor _am = new ActivityMonitor.ActivityMonitor();
Then, within the constructor, it is initialized:
_am.WarningMinutes = 0.9;
_am.MaxMinutesIdle = 1;
_am.Idle += new EventHandler(am_Idle);
...where am_Idle
is the handler for when the application becomes idle:
void am_Idle(object sender, EventArgs e)
{
Application.Exit();
}
Points of Interest
One thing that I did have some trouble with was that my little component was intercepting Windows mouse messages even when the mouse wasn't doing anything (not moving or clicking). I finally noticed that they seemed to be firing when the mouse was over my form. To me that doesn't count as being active, so I worked around this by only intercepting "clicking" messages:
private int MouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
MouseMessages mouseInfo = (MouseMessages)wParam;
if (nCode >= 0 &&
((mouseInfo == MouseMessages.WM_LBUTTONDOWN) || (
mouseInfo == MouseMessages.WM_RBUTTONDOWN)))
_lastActivity = DateTime.Now;
return CallNextHookEx(_mouseHookID, nCode, wParam, lParam);
}
Anyway, I'd appreciate any feedback, and I hope someone can find this to be of some use.
History
- 14 January, 2008 -- Original version posted.
- 18 January, 2008 -- Downloads updated.