Click here to Skip to main content
Click here to Skip to main content

How to check for user inactivity with and without platform invokes in C#

By , 22 Dec 2004
 

Introduction

From time to time, someone comes up with the question 'How do I implement a timeout like that Show me as "Away" when I'm inactive feature in Windows Messenger?' One might think of other use cases for a feature like this but either way, it is an interesting question. And so I tried to find out how to do it right. The result is this article and this small collection of classes that should provide the long desired feature out of the box.

The Basics

There are basically two different approaches. First, you use a timer with the appropriate interval and reset it every time an event occurs. However, how to get your hands on the events is a little bit tricky and again there are several possibilities. Therefore, I created an interface and an abstract base class in order to be able to easily implement different ways to process mouse and keyboard events later. Second, you could still use a timer but this time with a short interval and check for console input every time the timer raises its Elapsed event. It is because of this different use of the timer that the class that uses polling is not derived from the base class. It implements the IInactivityMonitor interface directly.

The interface

The interface IInactivityMonitor consists of one method, five properties and two events. The method public void Reset() is used to reset the internal timer I mentioned before as well as some internal status information. The properties should be almost self-explanatory. public bool Enabled allows to determine whether an instance should raise events or not. public double Interval specifies the interval to wait for interaction. The only reason why the property is declared as double is because that's the type used for the Timer.Interval property of the Timer class. The properties public bool MonitorMouseEvents and public bool MonitorKeyboardEvents allow specifying if the instance should only monitor mouse events, keyboard events, or both. It is also possible to set both to false which has the same effect than setting Enabled to false. The last property is public ISynchronizeInvoke SynchronizingObject which allows providing a control for synchronization. If this property is null, events are not synchronized. If a synchronization object is provided, the execution of event handlers will be marshaled to the thread that owns the object. And finally, there are two events. event ElapsedEventHandler Elapsed is raised after an interval of inactivity. In addition, there is event EventHandler Reactivated which is raised when the user continues to interact with the monitored UI element after Elapsed has already been raised.

Using the interface

As the interface looks a lot like the interface of a timer, the usage is almost similar. The code snippet below is just an example. Of course, the correct call of the constructor depends on the concrete implementation. Regarding my own base class, the default value for MonitorKeyboardEvents and MonitorMouseEvents is true and the default value for Enabled is false. So, like with most timer classes, nothing will happen until Enabled is set to true.

private IInactivityMonitor inactivityMonitor = null;
inactivityMonitor = new ControlMonitor(this);
inactivityMonitor.SynchronizingObject = this;
inactivityMonitor.MonitorKeyboardEvents = false;
inactivityMonitor.MonitorMouseEvents = true;
inactivityMonitor.Interval = 600000;
inactivityMonitor.Elapsed += new ElapsedEventHandler(TimeElapsed);
inactivityMonitor.Reactivated += new EventHandler(Reactivated);
inactivityMonitor.Enabled = true;

The base class

The abstract base class MonitorBase implements the whole timer handling so that derived classes can focus on handling mouse and keyboard events. In conclusion, creating an instance of the timer is all that the constructor of the base class does.

protected MonitorBase()
{
  monitorTimer = new Timer();
  monitorTimer.AutoReset = false;
  monitorTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
}

Because derived classes might handle a lot of references as well as unmanaged handles, the interface IDisposable is implemented. The base deconstructor takes care of all previously registered event handlers and disposes the timer object.

protected virtual void Dispose(bool disposing)
{
  if (!disposed)
  {
    disposed = true;
    if (disposing)
    {
      Delegate[] delegateBuffer = null;

      monitorTimer.Elapsed -= new ElapsedEventHandler(TimerElapsed);
      monitorTimer.Dispose();

      delegateBuffer = Elapsed.GetInvocationList();
      foreach (ElapsedEventHandler item in delegateBuffer)
        Elapsed -= item;
      Elapsed = null;

      delegateBuffer = Reactivated.GetInvocationList();
      foreach (EventHandler item in delegateBuffer)
        Reactivated -= item;
      Reactivated = null;
    }
  }
}

The implementation of the properties is not really interesting. TimeElapsed and ReactivatedRaised are implemented as protected read-only properties as they are only needed for internal use in the derived classes. The other properties are declared as public virtual to allow overriding.

In case the object is enabled, Reset() resets the timer object by setting its Interval property to its current value. I admit, it looks strange, but it does exactly what it's supposed to do.

public virtual void Reset()
{
  if (disposed)
    throw new ObjectDisposedException("Object has already been disposed");

  if (enabled)
  {
    monitorTimer.Interval = monitorTimer.Interval;
    timeElapsed = false;
    reactivated = false;
  }
}

As derived classes can not invoke events declared in the base class, there are two protected methods to encapsulate the events. This is also because of the need to perform some additional checks to prevent unintended raising of events. Why is that? Well, the System.Timers.Timer used in the base class is a multithreaded timer. Therefore, it is possible that a timer thread calls the event handler although Enabled has been set to false (fortunately, this behavior is well documented).

protected void OnElapsed(ElapsedEventArgs e)
{
  timeElapsed = true;
  if (Elapsed != null && enabled && (monitorKeyboard || monitorMouse))
    Elapsed(this, e);
}

1. Monitoring mouse and keyboard events solely with managed code

Now that we've got a good basis, we can move on to the first derived class: ControlMonitor. This class was the result of the desire to use 100% managed code, no platform invokes, and not even managed methods that might make the class too platform dependent. Let's see how it works and what you can do with it.

public ControlMonitor(Control target) : base()
{
  if (target == null)
    throw new ArgumentException("Parameter target must not be null");
  targetControl = target;
  ControlAdded(this, new ControlEventArgs(targetControl));
  if (MonitorKeyboardEvents)
    RegisterKeyboardEvents(targetControl);
  if (MonitorMouseEvents)
    RegisterMouseEvents(targetControl);
}

The class has only one constructor which expects a Control object as its parameter (thus the name ControlMonitor). It calls up to three registration methods which are all based on the same principle. They first register an event handler for the control and then try to recursively register all child controls as well. For example, let's take a look at RegisterKeyboardEvents():

private void RegisterKeyboardEvents(Control c)
{
  c.KeyDown += new KeyEventHandler(KeyboardEventOccured);
  c.KeyUp   += new KeyEventHandler(KeyboardEventOccured);
  foreach (Control item in c.Controls)
    RegisterKeyboardEvents(item);
}

First, it registers event handlers for the KeyDown and the KeyUp events. After that, it uses a foreach loop and calls itself for every control in the Control.Controls collection. This ensures that our monitor object will be notified by every object in the hierarchy below the object that was passed to the constructor. Now, the question is does this really solve my problem?

Advantages

First, this approach has one big advantage. It does not use any platform specific functions or defines. Although I have not tested it, I think this class might have a good change to run on Mono without any modifications. This, however, might be the only advantage.

Disadvantages

As shown above, this class relies entirely on the Control class. This means that as soon as you've got an application with more than one form (which is most likely to be the normal case), you need to create one monitor object for every form. Also, there is this problem with message boxes. As showing a message box only involves calling a static method that is executed synchronously, you have absolutely no clue what happens when a message box is displayed. A rather weak workaround would be to generally consider 'message box time' as inactivity (or activity for that matter).

2. Using Application.AddMessageFilter to intercept messages

The Application class provides a convenient encapsulation to make subclassing easier. The method AddMessageFilter() can be used to register any object with an IMessageFilter interface as a message filter. Therefore, the ApplicationMonitor class is not only derived from MonitorBase but also implements IMessageFilter. This allows it to register itself rather than use a helper object. As the filter will be installed for the message queue of the thread in which AddMessageFilter() was called, the constructor does not need any parameters.

public ApplicationMonitor() : base()
{
  Application.AddMessageFilter(this);
}

The method PreFilterMessage() which is the only method define in the IMessageFilter interface is where we now can check for mouse and keyboard activity. If an incoming message indicates user input, we call ResetBase() to reset the timer in the base class. Although we are still using only managed code, this implementation already includes platform specific information because it needs to react on Windows messages with certain IDs.

public bool PreFilterMessage(ref Message m)
{
  if (MonitorKeyboardEvents)
    if (m.Msg == (int)Win32Message.WM_KEYDOWN ||
      m.Msg == (int)Win32Message.WM_KEYUP)
      ResetBase();
  if (MonitorMouseEvents)
    if (m.Msg == (int)Win32Message.WM_LBUTTONDOWN ||
      m.Msg == (int)Win32Message.WM_LBUTTONUP     ||
      m.Msg == (int)Win32Message.WM_MBUTTONDOWN   ||
      m.Msg == (int)Win32Message.WM_MBUTTONUP     ||
      m.Msg == (int)Win32Message.WM_RBUTTONDOWN   ||
      m.Msg == (int)Win32Message.WM_RBUTTONUP     ||
      m.Msg == (int)Win32Message.WM_MOUSEMOVE     ||
      m.Msg == (int)Win32Message.WM_MOUSEWHEEL)
      ResetBase();
  return false;
}

As you can see, PreFilterMessage() checks for the same events as the ControlMonitor class. However, if you expect that you now have a fully working application-level solution, I'll have to disappoint you. I also assumed that PreFilterMessage() would be called whenever a new message is dispatched to the thread's message queue before any other processing occurs. But for some (as it seems undocumented) reasons, there are two exceptions. The first one are message boxes. The message filter will not be called while a message box is displayed. Second, when you show a modal form by calling Form.ShowDialog(), you won't receive any messages which are related to the forms in the background (although a background form can't obtain the focus, there are still messages dispatched, for example, when you move the mouse cursor over the form).

Advantages

This solution is still not perfect but already features some improvements. Besides the problem with message boxes and modal forms, this class is able to track every user input on a whole thread. In addition, the code is much shorter as it does not need to register any event handlers. And of course, it still does not need to call any unmanaged code.

Disadvantages

Its major drawback is obviously that the class is not able to handle all messages of the thread because it simply does not receive all of them. In comparison with the ControlMonitor class, we gave up a lot of the platform independence as the messages which are processed by the message filter are 100% Windows specific.

3. Monitoring mouse and keyboard events with hooks

After discussing two solutions without any calls of unmanaged code, we will now take a look at the Win32 API. If one considers the use of platform invokes, he or she will certainly sooner or later think about hooks. According to the MSDN Library, Hooks are 'points in the system message-handling mechanism, where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure'. With the functions SetWindowsHookEx(), UnhookWindowsHookEx() and CallNextHookEx(), we've got everything we need to intercept mouse and keyboard events (there is also a detailed MSDN Magazine article about hooks and the .NET Framework, titled Windows Hooks in the .NET Framework).

Let's take a look at the constructor of the HookMonitor class:

public HookMonitor(bool global) : base()
{
  globalHooks = global;
  if (MonitorKeyboardEvents)
    RegisterKeyboardHook(globalHooks);
  if (MonitorMouseEvents)
    RegisterMouseHook(globalHooks);
}

This constructor does not seem to be too different from the one used in the ControlMonitor class. However, if you take a close look at the private methods RegisterKeyboardHook and RegisterMouseHook, you'll find out that they use the SetWindowsHookEx() function mentioned above. So the following line registers the hook for the mouse events:

mouseHookHandle = User32.SetWindowsHookEx(
                         (int)Win32HookCodesEnum.WH_MOUSE, mouseHandler,
                         (IntPtr)0, AppDomain.GetCurrentThreadId());

mouseHookHandle is the handle returned by SetWindowsHookEx(), or zero if the call failed. WH_MOUSE is the type of handle we want to install and mouseHandler a delegate (or function pointer from Windows' point of view) of the callback function. The last parameter is the ID of the current thread. This means, an application with more than one thread with its own message pump would have to install a hook in all these threads. The setup for the keyboard hook looks just the same. The only difference is that the first parameter is WH_KEYBOARD and that the keyboard hook also uses its own callback function. The callback functions itself are quite minimalist. As we just want to know if there is any activity on the thread (but we don't mind what kind of activity), the function checks if nCode is zero or larger. In that case, the message is supposed to be handled by the hook function, so it calls ResetBase(). Finally, it calls CallNextHookEx() to pass the message to the next function in the chain.

private int MouseHook(int nCode, IntPtr wParam, IntPtr lParam)
{
  if (nCode >= 0)
    ResetBase();
  return User32.CallNextHookEx(mouseHookHandle, nCode, wParam, lParam);
}

Advantages

In order to reach our goal with just a few lines of extra code, this approach is really great. Not only do we not have to worry about the controls in the application, we are actually independent from them and also receive every message which is dispatched to our thread. The thread in which the class is constructed needs a message pump and that's all.

Disadvantages

The drawbacks are almost all the advantages of the ControlMonitor class as this solution makes intense use of platform invokes. This means that even a port to 64-bit Windows might require some changes.

4. Monitoring activity with GetLastInputInfo()

Windows hooks allowed us to view all incoming messages of a thread no matter which window has the focus or whether it is a modal form or not. But what if we want to monitor the activity on the whole system? The easiest solution for this problem is a Win32 API function called GetLastInputInfo(). However, there is one major drawback. While the previous three approaches generally allow analyzing the user activity, this function only informs us about the point in time of the last user input. After calling it, we might know that something happened but we don't have a clue what. Although this is still enough to generally solve our problem, it renders the distinction between mouse and keyboard events useless. Therefore, the LastInputMonitor class will monitor any activity as long as at least one of the two properties MonitorMouseEvents and MonitorKeyboardEvents is set to true. As GetLastInputInfo() is a synchronous function, the LastInputMonitor class uses polling to periodically check for activity. This is the reason why it is not derived from the base class MonitorBase. However, it uses an instance of the same timer class with the default interval of 100 milliseconds.

public LastInputMonitor()
{
  lastInputBuffer.cbSize = (uint)Win32LastInputInfo.SizeOf;
  pollingTimer = new Timer();
  pollingTimer.AutoReset = true;
  pollingTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
}

Without the help of a base class, the LastInputMonitor has the whole logic for event evaluation and event raising built in. The core of the class is the method TimerElapsed() which handles the Elapsed event of the timer object.

private void TimerElapsed(object sender, ElapsedEventArgs e)
{
  if (pollingTimer.SynchronizingObject != null)
    if (pollingTimer.SynchronizingObject.InvokeRequired)
    {
      pollingTimer.SynchronizingObject.BeginInvoke(
        new ElapsedEventHandler(TimerElapsed),
        new object[] {sender, e});
      return;
    }
  if (User32.GetLastInputInfo(out lastInputBuffer))
  {
    if (lastInputBuffer.dwTime != lastTickCount)
    {
      if (timeElapsed && !reactivated)
      {
        OnReactivated(new EventArgs());
        Reset();
      }
      lastTickCount = lastInputBuffer.dwTime;
      lastInputDate = DateTime.Now;
    }
    else if (!timeElapsed && (monitorMouse || monitorKeyboard))
      if (DateTime.Now.Subtract(lastInputDate).TotalMilliseconds > interval)
        OnElapsed(e);
  }
}

After checking if cross-thread marshaling is needed, the method calls GetLastInputInfo(). If it detects the first activity after IInactivityMonitor.Elapsed has been raised, it raises the Reactivated event. Otherwise, it updates the tick count information and the timestamp lastInputDate. If there is no activity for the time span specified by interval, it raises the Elapsed event.

Advantages

This class allows detecting inactivity on a system-wide level. Our problem has been solved completely (at least if you don't need to only monitor mouse or keyboard events).

Disadvantages

Well, I already wrote it twice: you can't distinguish between mouse and keyboard events. However, I guess that it won't bother most of the people. Apart from that, this approach uses polling which I think should be avoided if possible though the documentation explicitly refers to the possibility to use GetLastInputInfo() for input idle detection. And finally, this function is only available on Windows 2000 and higher.

4 1/2. Monitoring global events

I promised to show four and a half ways of implementing a timeout class. The last approach solves all our problems but does not help us to distinguish between mouse and keyboard events. The usage of the WH_MOUSE and WH_KEYBOARD hooks solved the problem on the application level, but isn't there something like global hooks to intercept all messages on a system? The short answer is yes. However, global hooks in .NET are a problem because they usually use code injection, and injecting managed code in unmanaged processes is no good idea. The popular workaround is to use a native Win32 DLL to achieve this (for details, see Michael Kennedy's article: Global System Hooks in .NET). However, George Mamaladze found out that there are two low-level hooks that don't need code injection and therefore can be used in a managed environment (see Processing Global Mouse and Keyboard Hooks in C#). And this is also the reason why my last suggestion is only a half solution.

As you probably noticed, the constructor of the HookMonitor class requires a bool as its parameter. If it's false, the class installs thread hooks as described above. However, if it is true, RegisterMouseHook() and RegisterKeyboardHook() will install the global hooks WH_MOUSE_LL and WH_KEYBOARD_LL. This results in a different call of SetWindowsHookEx():

keyboardHookHandle = User32.SetWindowsHookEx(
  (int)Win32HookCodesEnum.WH_KEYBOARD_LL,
  keyboardHandler,
  Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
  (int)0);

The thread ID is no longer needed. Instead, the function expects a handle of the library which contains the callback function. In our case, this is the current assembly.

Conclusion

Although I have to admit that I don't like the idea very much, using hooks seems to be the best way to achieve a timeout feature (at least at the moment). When future releases of Windows and the .NET Framework allow a more convenient solution, it should be easy to derive a new class from MonitorBase and use that instead of the HookMonitor. I hope you'll find the classes provided with this article useful, and let me know if there are any bugs left or you've got some ideas how to improve the code.

Change history

  • 2004-12-22: Corrected bug in the ControlMonitor class (the Control.MouseWheel event was not handled), renamed the enumeration with the hook defines (non-functional change), and included classes and paragraphs to demonstrate the use of the IMessageFilter interface and the Win32 API function GetLastInputInfo().
  • 2004-12-19: Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Dennis C. Dietrich
Web Developer
Ireland Ireland
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionArchitecturememberSUSHIL KUMAR BHATIA26 Nov '12 - 3:02 
Dear Dennis
 
Can you please send me Architecture of it in form of diagram. I m looking to use this tool for deploying tool data on Azure.
GeneralMy vote of 5memberSUSHIL KUMAR BHATIA26 Nov '12 - 3:00 
Hi Dennis can you please send me Architecture of the same.
QuestionDoes GetLastInputInfo identifies input from joystick Or only mouse and keyboard inputs?memberkirankumar27 Jul '12 - 11:00 
Hi I want to know if the GetLastInputInfo can identify the input from joystick.
GeneralUsing LastInputMonitor with WPFmemberbrunzefb21 Oct '09 - 8:06 
Hi,
 
just to mention if you use wpf: you need to use a CompatibilityAdapter, which you can find here:
http://geekswithblogs.net/robp/archive/2008/03/28/why-doesnt-dispatcher-implement-isynchronizeinvoke.aspx[]
 


GeneralSimpler Way - GetTickCountmemberjamiekitson30 Jun '09 - 1:09 
Rather than have all these globals you can compare GetLastInputInfo to GetTickCount to get the number of milliseconds of inactivity. Anyway, thanks for the info, just what I was after.
GeneralFilter mouse movemembercandps11 May '09 - 10:23 
I would like to use the Local Hook Monitor class. However, I seem to have a problem. It appears that a mouse move event is fired when the mouse is located over the main form even when the mouse is not moving! I read in another post that perhaps Windows is causing a mouse move event to occur when refreshes occur. I am not explicitly refreshing the form. I am developing under Visual Studio 2008, .NET 3.5, Vista x64. Any thoughts? I have hacked the code to look explicitly for the mouse move message and keep track of previous mouse location, but this seems to be a bit cumbersome. Thoughts about a more elegant solution would be nice. Otherwise, the classes work perfectly and I like their simplicity.
 
- Charlie
AnswerRe: Filter mouse movememberBrent R. Matzelle20 Sep '10 - 11:35 
The problem is caused by the "spurious WM_MOUSEMOVE messages" described on this post. The solution is to use the Control.MousePosition class and check if the position has changed between requests.
NewsAn easier waymembertimneu2218 Jun '08 - 1:16 
I have found an easier way to do this.
 
I was looking to add an "auto timeout" feature to my application, so I looked at the hooks idea but it didn't realy do what I wanted. I decided to use a Timer on my main form; this timer is reset by any mouse movement or keypress. How do I detect these? Before running the application, add a message filter. If the message is of a certain type, call m_MainForm.RestartMonitor(), which is a function that restarts the timer.
 

static void RunProgram()
{
      // Run the app.
      IdleTimerWatcher idle = new IdleTimerWatcher();
      System.Windows.Forms.Application.AddMessageFilter( idle );
      System.Windows.Forms.Application.Run( m_MainForm );
}
 
private class IdleTimerWatcher : IMessageFilter
{
      // constants from WinUser.h (google is great!)
      private const int WM_MOUSEMOVE = 0x0200;
      private const int WM_LBUTTONDOWN = 0x201;
      private const int WM_RBUTTONDOWN = 0x204;
      private const int WM_MBUTTONDOWN = 0x207;
      private const int WM_MOUSEWHEEL = 0x20A;
      private const int WM_KEYDOWN = 0x100;
 
      public bool PreFilterMessage( ref Message m )
      {
         switch ( m.Msg )
         {
               case WM_MOUSEMOVE:
               case WM_LBUTTONDOWN:
               case WM_RBUTTONDOWN:
               case WM_MBUTTONDOWN:
               case WM_MOUSEWHEEL:
               case WM_KEYDOWN:
                  m_MainForm.RestartMonitor();
                  break;
         }
            return false;
      }
}

GeneralRe: An easier waymemberJon Patnode6 Aug '08 - 8:13 
Thanks...Much simpler and gives me what I need. I had to comment out the WM_MOUSEMOVE because it was firing every time Windows did a screen refresh...user was not doing anything, but screen refresh caused timer to restart. This was also happening to me using the original downloaded code on this thread. Decided to comment out WM_MOUSEMOVE as in my application I don't consider mouse movement alone as "activity" anyway.
 
RizzoTheRat
QuestionWould this work on a windows service?memberLuis Miguel Silva27 Feb '08 - 3:01 
I've been looking for a way to get the last input time (be it mouse or keyboard) from the system.
 
After digging a little bit i've found the GetLastInputInfo() win32 api function but, from what i've read, it doesn't work if the application isn't running on the user's desktop (example: if it is running as a windows service).
 
I need to check for the availability of the system to know if the machine is usable or not!
 
Can you help me with this?
 
Thanks in advance,
Luís Silva
QuestionForm freezes when Implemented in VB6memberspabhat9 Oct '06 - 21:13 
I have used the following method to implement this code in VB.Net.
When I try to open another form after the set interval, the second form freezes.
 
Could you please help me?
My code is as follows:
 
Dim spaInactivMonitor As UserInactivityMonitoring.IInactivityMonitor = Nothing
 
Private Sub startBtn_click(...) Handles startBtn.Click
            spaInactivMonitor.Enabled = True
End Sub
 
Private Sub timeElapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
            Dim frmNew As New Form2()
            Try
                  If Me.InvokeRequired Then                                               
                        frmNew.Show()
                        spaInactivMonitor.Enabled = False
                  End If
            Catch spEs As Exception
 
            End Try
End Sub
 
      Private Sub spa_Reactivated(ByVal sender As Object, ByVal e As System.EventArgs)
            Try
                  If Me.InvokeRequired Then
                        TextBox1.Text &= "Reactivated" & vbCrLf
                  End If
            Catch spEs As Exception
 
            End Try
      End Sub
 
Private Sub btnCreate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreate.Click
            spaInactivMonitor = MonitorCreator.CreateInstance(MonitorType.GlobalHookMonitor)
            spaInactivMonitor.MonitorKeyboardEvents = True
            spaInactivMonitor.MonitorMouseEvents = True
            spaInactivMonitor.Interval = 2000
            AddHandler spaInactivMonitor.Elapsed, AddressOf timeElapsed
            AddHandler spaInactivMonitor.Reactivated, AddressOf spa_Reactivated
End Sub
GeneralBug in MonitorBase.DisposememberKarel Kral26 Sep '06 - 1:42 
There is bug in MonitorBase.Dispose, which causes NullReferenceException, if delegates Elapsed or Disposed are null. The check against null is required, see bellow.
 
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
disposed = true;
if (disposing)
{
Delegate[] delegateBuffer = null;
 
monitorTimer.Elapsed -= new ElapsedEventHandler(TimerElapsed);
monitorTimer.Dispose();
 
if (Elapsed != null)
{
delegateBuffer = Elapsed.GetInvocationList();
foreach (ElapsedEventHandler item in delegateBuffer)
Elapsed -= item;
Elapsed = null;
}
 
if (Reactivated != null)
{
delegateBuffer = Reactivated.GetInvocationList();
foreach (EventHandler item in delegateBuffer)
Reactivated -= item;
Reactivated = null;
}
}
}
}
QuestionC# Windows Service containing hooks for mouse or keyboard, built with win32 callsmembergabipetrovay12 Jul '06 - 22:07 

Hi,
 
Do you know any way I can use keyboard hooks and mouse hooks from a windows service built in C# calling win 32 api funtions? The same application works just fine in a Console application.
 
I have tried with the Local System, and my administrative user account. It does not work. Hook handle IDs appear to be ok (non zero, non negative).
 
I don't know if "Allow service to interact with desktop" has anything to do with this. When I enable this for the local system account, and system reacts sluggish and responds very slow/late to mouse/key events (depends on which hook i enabled). So there must be something enabled, but my code in the callback is not called. The first line is to write to a file/log/DB. My code is not called.
 
Am I missing something?
 
Thanks!

GeneralImprovement to the polling methodmemberJesse0607 Mar '06 - 4:04 
I used the polling method that you described to implement a service that starts a new process after a defined period of inactivity. However, I did it slightly different and it greatly reduces the polling period needed. Here's what I did:
 
- Set Timer.interval to what the period of inactivity should be.
- Set a variable startOfTimer to Environment.TickCount once the Timer is started.
 
In the Timer.Elapsed event handler, I do the following:
- Stop the timer
- If lastInputInfo.dwTime - startOfTimer >= period of inactivity, then start my process.
- Else, set Timer.Interval = Peroid of inactivity - (Environment.TickCount - lastInputInfo.dwTime)
- Start the timer
 
This way, the Timer.Elapsed event only fires when there's a possibility that there has been no user activity during the last X minutes of inactivty.

 
Jesse
GeneralSimilar application using time poolingmemberksboy21 Dec '05 - 17:20 
Hi, i found a article which explain the same thing but using time pooling...
 
http://www.developer.com/net/cplus/article.php/3416271
 
D'Oh! | :doh: but not so sure abt its performance...
 
--ksboy--
GeneralGreat thought processesmemberHal Angseesing16 Dec '05 - 3:15 
Hi,
 
Just wanted to drop a note and say nice article. The different layers and thinking you went through to arrive at the different solutions are often something that I face in my day to day managed code programming. I have quite extensive Win32 background so when I was reading I was asking myself "why doesn't he just hook the mouse/keyboard" but then of course that wouldn't have been managed only. I still struggle to develop managed only code and invariable fall back to p/invoke when I simply can't think of/find any other way to do it.
It was just nice to see your thought processes as you attempted the same thing.
 
Cheers,
Hal.
 

GeneralRe: Great thought processesmemberrihdus27 Dec '05 - 19:01 
ya, nice article, i too struggled a lot in my early projects.
and implemented through timer and eventhandler for each and every events.
 
I knew that there is this.. but could not prepare myself.
 
so thanks to the author.
 

 
Any systematic work reflects its significance for a long time, Though I m not totally against "The Prototyping".So let's discuss in depth...
QuestionIt doesn't work on framework 2.0?memberparadise806 Nov '05 - 2:10 
Hi, thanks for your article very much, it is really great!
Using SetWindowsEx to set global hooks perfectly work in vs.net 2003(framework 1.1, Win2003), but recently I am working on vs 2005(framework 2.0, Win2003), global hooks install failed! SetWindowsEx method alwasy return 0.
Of course, application level hooks still work well, but vs 2005 gives warning about 'AppDomain.GetCurrentThreadId()' method, vs 2005 treat this method deprecated -_-!.
 
I just wondered is there any way to install global hook in .net 2.0.
 
Thank you again, and sorry for my poor English.
 
Donny
AnswerRe: It doesn't work on framework 2.0?memberBrentLak30 Nov '05 - 13:36 
In 2.0 you can use
 
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName)
 
since the AppDomain method is deprecated
 
Brent
QuestionHow to use this in a Windows ServicememberFilipe Marcelino21 Sep '05 - 6:47 
Hi,
 
first of all great article. Now, I would like to know if it's possible to implement this in a Windows Service. I already tried it but it seems to me that this lib need 'System.Windows...' for several tasks. It's possible to do this in a windows service?
 
thanks in advance for your attention.
 
Regards,
Filipe Marcelino
QuestionRe: How to use this in a Windows Servicememberetggg2w14 Nov '05 - 9:59 
I am doing the same thing, trying to implement an inactivity monitor in a windows service. It works great as a form it catches everything whether the form has focus or not. The only problem that I am having with the windows service is this one line of code:
 
inactivityMonitor.SynchronizingObject = this;
 
Visual Studio says 'Cannot implicitly convert type 'Service1' to 'System.ComponentModel.ISynchronizeInvoke'
 
Any help would be greatly appriciated I am not sure how to allow the service to synchronize.
 
Thanks,
 
etggg2w

AnswerRe: How to use this in a Windows ServicememberBrentLak30 Nov '05 - 13:33 
I ran into the same problem. I just defined my own eventargs and eventhandler so I don't have to use the ones in the System.Windows.Forms namespace.
 
Brent
GeneralRe: How to use this in a Windows Servicememberdragomir14 Mar '06 - 20:09 
Hello,
 
I am also trying to write a Windows service to monitor keyboard and mouse activity, but it seems that without an event handler like in a Windows Forms app this is not possible. Please let me know if you achieve any result with that. Thanks in advance!
QuestionRe: How to use this in a Windows Servicemembergabipetrovay12 Jul '06 - 21:42 
Hi,
 
Do you know any way I can use keyboard hooks and mouse hooks from a windows service?
 
I have tried with the Local System, and my administrative user account. It does not work. Hook handle IDs appear to be ok (non zero, non negative).
 
I don't know if "Allow service to interact with desktop" has anything to do with this. When I enable this for the local system account, and system reacts sluggish and responds very slow/late to mouse/key events (depends on which hook i enabled). So there must be something enabled, but my code in the callback is not called. The first line is to write to a file/log/DB. My code is not called.
 
Am I missing something?
 
Thanks!
QuestionHow efficient is it?memberGary Wolfe25 Apr '05 - 7:00 
Dennis, I agree with you when you say that you would rather not have to poll. However, I obviously didn't research as thoroughly as you did, and decided on polling. Fortunately, my timer function is very simple (at least until triggered!), and does not seem to impact performance noticably.
 
Is polling really that much worse than hooking into mouse movements? For example, if you poll 10 times per second, it probably won't be noticed by the user any more than if mouse movements generated 10 moves per second. Obviously, any background processes still are delayed for a polling solution, but as far as the GUI is concerned, if more mouse movements are generated than your timer solution, then hooking into the mouse might actually appear to the user to be more sluggish.
 
I guess my point is, I, too, prefer to avoid polling when possible, but if you need to do it, as long as it doesn't poll too often, it may not be so bad. (Seems like there used to be an option to view CPU time used for processes, but I can't find it now.) I would think that if it doesn't use much CPU time anyway, it is not worth obsessing about. Either way, as the other poster found out, the timer routine has to at least run more quickly than your timer (or mousemove) interval, and preferably as fast as possible.
 
Also, kind of analogous to how in managed code you're forced to poll, I have found situations in the past where polling just made a system-independent solution easy, and with virtually no impact on any system. It's sometimes hard to argue with something that works so well. Smile | :)
 
Gary W.
AnswerRe: How efficient is it?memberDennis C. Dietrich26 Apr '05 - 7:33 
Gary Wolfe wrote:
Is polling really that much worse than hooking into mouse movements? For example, if you poll 10 times per second, it probably won't be noticed by the user any more than if mouse movements generated 10 moves per second.
 
The way you are asking the question I'd say, no. Regarding performance (meaning measured ticks, not the user experience), hooking might be even worse.
 
Gary Wolfe wrote:
Obviously, any background processes still are delayed for a polling solution, but as far as the GUI is concerned, if more mouse movements are generated than your timer solution, then hooking into the mouse might actually appear to the user to be more sluggish.
 
I agree with this as a general statement. However, regarding the inactivity monitor implementation I don't expect any impact on the UI performance on a modern PC as long as the application installing the hook is well-design (e.g. is multithreaded in order not to block the message pump). And as hooking most likely won't impact the overall performance on the system in this scenario I'd rather use that in order to keep my software entirely event-based than using polling.
 
Gary Wolfe wrote:
Seems like there used to be an option to view CPU time used for processes, but I can't find it now.
 
You can use either the Task Manager[^] by adding the CPU Time performance counter (see Specify process counter column headings[^]) or the Process Class[^] to get the information programmatically including milliseconds (see Process.TotalProcessorTime Property[^]).
 
Gary Wolfe wrote:
I would think that if it doesn't use much CPU time anyway, it is not worth obsessing about.
 
Well, maybe I am a little bit obsessed with not using polling but I can tell you why. As long as people evaluate the pros and cons of polling and event handling like you just did everything is fine. However, people keep on using polling where it is definitely inappropriate. For example, I was installing a commercial standard application two months ago which used polling to trace file system changes instead of a FileSystemWatcher[^] object (and, yes, it was a .NET application). I usually don't slander like this but as the license for that application wasn't cheap and it also included other flaws I couldn't help but to wonder if some programmers are just unable to understand event handling. And that's why I tend to "preach" event-based approaches.
 
Gary Wolfe wrote:
Either way, as the other poster found out, the timer routine has to at least run more quickly than your timer (or mousemove) interval, and preferably as fast as possible.
 
I'm not too sure what exactly you mean. Mind to repeat this a little bit more detailed? Smile | :)
 
Gary Wolfe wrote:
Also, kind of analogous to how in managed code you're forced to poll, I have found situations in the past where polling just made a system-independent solution easy, and with virtually no impact on any system. It's sometimes hard to argue with something that works so well.
 
First, in which case does managed code force you to poll? Second, I'm also a fan of the idea of system-independent software. However, it always comes with certain disadvantages (forces you to use a certain technology/framework, doesn't allow to use platform specific features, etc.) and personally I think it is often overrated (I'm not talking about solutions that have to be platform-independent). Now, no offense (especially since I have never taken a look at your source code) but from my experience I can say that the argument "but it works" is still used far too often to excuse bad designs and awful spaghetti code.
 
Well, I hope you don't get me wrong on this. These are just my thoughts on the subject and I really enjoy the discussion. And thanks for your feedback! Smile | :)
 
Best regards
Dennis
GeneralRe: How efficient is it?memberGary Wolfe26 Apr '05 - 18:20 
Thanks for the tips on the CPU Time counter. I've been running for a while, and my mouse-polling app. has yet to register a second. I'm pretty satisfied that the impact is low.
 
Dennis C. Dietrich wrote:
First, in which case does managed code force you to poll?
 
Your article mentions polling being the only option when working with managed calls, or did I misread? I had come to the same conclusion, and resorted to examining the Cursor position.
 
I am not against calling Win32 functions, but I did not see the MOUSE..._LL event you documented. So, now that you've written this article, I can go back and replace the timer.
 
In the meantime, I think it's worth questioning if the current design is all that bad. You seem to imply that polling always is, by default, poor design, which just seems overly limiting.
 
Polling is a valid technique, but dangerous, and should only be done if one is willing to carefully consider the impact on the system.
 
Dennis C. Dietrich wrote:
..but from my experience I can say that the argument "but it works" is still used far too often to excuse bad designs and awful spaghetti code.
 
This reminds me of an article on Joel On Software (http://joelonsoftware.com/[^]). He writes that too many programmers look at code, decide that it's spaghetti code, and that it should be rewritten. He says usually those programmers are wrong. A lot of those weird patches are in there for a reason, to make something work. If you were to start over and recode everything, you'd have bugs, and the fixes for some of those bugs would not-so-coincidentally resemble some of those patches. Smile | :) Reading someone else's code is hard! Well, you really should read it in his words and not mine. I have seen this attitude in others and sometimes myself.
 
As for the file polling code I was recalling, it's decade-old code written by someone else, so I can't remember exactly, but perhaps it was done that way for something as simple as the file notification event not being available in 16-bit Windows, or at least the library that was being used. If I agree that I wouldn't have done it that way today, can we drop the need to examine any code? Poke tongue | ;-P Regardless, it has not been a support problem, so it is a successful design, if not ideal.
 
Dennis C. Dietrich wrote:
Well, I hope you don't get me wrong on this. These are just my thoughts on the subject and I really enjoy the discussion. And thanks for your feedback!
 
I feel like we have painted me into a corner where I must try to defend polling, which I'm not really interested in doing. I'm interested in getting things to work. If I must resort to polling, I'll do it, and I know enough to not drag a system to its knees while doing it. Hmmm | :|

GeneralRe: How efficient is it?memberDennis C. Dietrich27 Apr '05 - 11:22 
Gary Wolfe wrote:
Your article mentions polling being the only option when working with managed calls, or did I misread?
 
Only the ControlMonitor and the ApplicationMonitor do not call any unmanaged code. The HookMonitor makes use of the several hook[^] functions and the LastInputMonitor (which relies on polling) calls GetLastInputInfo()[^] which is also unmanaged.
 
Gary Wolfe wrote:
I am not against calling Win32 functions, but I did not see the MOUSE..._LL event you documented.
 
Again, WH_MOUSE_LL (see LowLevelMouseProc()[^]) is not a message but a hook (see also About Hooks[^]).
 
Gary Wolfe wrote:
You seem to imply that polling always is, by default, poor design, which just seems overly limiting.
 
Not really. There are situations where polling is the only way to go because your information source does not support sending messages. All I'm saying is that event-based models have some advantages compared to polling-based models and that I prefer event-handling for implementing a user inactivity monitor as it integrates seamlessly in the event-driven OS on which the software is running (see also About Messages and Message Queues[^]). Besides, as I also mentioned in the article, polling GetLastInputInfo()[^] is completely useless when you need more details about the activity (e.g. you're only interested in keyboard events).
 
Gary Wolfe wrote:
He writes that too many programmers look at code, decide that it's spaghetti code, and that it should be rewritten.
 
My point had nothing to do with too much or too less refactoring[^] but with excuses for bad code (which often is "but it works"). Besides, I wasn't only referring to coding. Whether to use polling or event handling can be a design question with no impact on the programmability.
 
Gary Wolfe wrote:
He says usually those programmers are wrong.
 
Good thing that I'm not those programmers but only one.
 
Gary Wolfe wrote:
I feel like we have painted me into a corner where I must try to defend polling, which I'm not really interested in doing.
 
It was definitely not my intention to paint you into a corner. However, it was my intention to paint polling into a corner. Well, I guess you know what I mean. Besides, polling doesn't need to be defended. Let it rest in peace. Wink | ;)
 
Best regards
Dennis
GeneralRe: How efficient is it?memberGary Wolfe27 Apr '05 - 15:45 
For the record, I ended up on this page because I wasn't happy with having to resort to polling the mouse, and I couldn't understand why there wasn't a better solution! I do understand the disadvantages of polling. So, I do appreciate your article pointing out the alternatives, and the detailed explanation.
 
Having said that, I'm proud of what I did with polling the mouse thus far. If nothing else, it was an interesting exercise, seeing that it can be done without impacting the system adversely. But it's not enough for me to stop there -- I do want to improve my code, as time permits, so I do want to try the hook solution.
 
On the other example I mentioned (with the old code), the more I think about it, it really wasn't the polling that made it flexible enough to operate in different environments, but the reliance on the use of files for interprocess communication instead of a particular messaging system (IPC) which may have limited it to a specific platform. So, never mind my original statement on that. The fact that it was polled was probably a limitation of the programmer or the library we were using at the time, but the fact that it polled was stuck in my mind. Sigh | :sigh: Sorry for the confusion.

GeneralRe-codedmemberGary Wolfe4 Jun '05 - 5:11 
In case anyone is curious, I finally got around to recoding my app to use the mouse hook. Works great. It does exactly the same thing as before, but I have the satisfaction of knowing that it's done the "right" way. Smile | :) By the way, thanks Dennis for mentioning the MSDN article, as that was very helpful.

GeneralMouse Hooks make my mouse very slowmemberSTSC30 Mar '05 - 23:55 
I do have a small issue to monitor the mouse with hooks.
Because when my application runs a method for a couple seconds (like when it tries to download something from the web) mouse movement gets very slow. Is there a way to set priorities to the event handler or something like that?
GeneralRe: Mouse Hooks make my mouse very slowmemberDennis C. Dietrich31 Mar '05 - 2:38 
STSC wrote:
Because when my application runs a method for a couple seconds (like when it tries to download something from the web) mouse movement gets very slow.
 
First, let's take a look at why this is happening. Whenever you run a Windows Forms Application it has one thread that is responsible for handling UI related messages (see also Multithreaded Windows Forms Control Sample[^]). When I install a WH_MOUSE_LL Hook[^] for this UI thread I tell Windows that I want it to call my LowLevelMouseProc()[^] function every time a mouse event occurs by sending a message to the thread that installed the hook. Now, you wrote that you call a method (presumably in your UI thread) that takes a couple of seconds to execute. However, as long as your method is executed, the thread is obviously unable to process any messages in the message queue. As this could prevent messages from being ever processed (just imaging that you might have an infinite loop) there is a timeout which can be specified in the registry with the LowLevelHooksTimeout value in the HKEY_CURRENT_USER\Control Panel\Desktop key (unfortunately, I wasn't able to find out the default value, yet). So, this problem can obviously also occur with the WH_KEYBOARD_LL Hook[^].
 
STSC wrote:
Is there a way to set priorities to the event handler or something like that?
 
I know that this isn't easy, but I think you should change the threading model of your application. When you have something that takes a few seconds have it executed in its own thread rather than you UI/main thread. This makes your program more complicated but it improves the user experience as it also prevents your UI from freezing during the execution of those "long running" methods.
 
Best regards
Dennis
GeneralRe: Mouse Hooks make my mouse very slowmemberSTSC31 Mar '05 - 3:25 
You are right it also occurs with WH_KEYBOARD_LL. Actually it is a windows service and I also have to know when a method exits.
The only possibilty for me seems to be that I call the long methods in a new thread and raise an event when it's finished.
 
Is there also a way to run the hook monitor in a new thread, but I don't know how I could call the methods of the hook monitor class from the main thread of the UI.
 
I really almost think that GetLastInputInfo might be a better solution?
GeneralRe: Mouse Hooks make my mouse very slowmemberDennis C. Dietrich11 Apr '05 - 11:17 
First of all, apologies for the delay but for the last couple of days I had no internet access at home and I still don't know when that's going to change.
 
STSC wrote:
Is there also a way to run the hook monitor in a new thread, but I don't know how I could call the methods of the hook monitor class from the main thread of the UI.
 
Well, I never tried that so all I can say is that in theory it should be possible. In order to use low-level hooks you need a message queue on the thread that processes the messages. So, if you created a new thread and then executed Application.Run()[^] on that thread you should be able to use it for installing hooks.
 
STSC wrote:
I really almost think that GetLastInputInfo might be a better solution?
 
Well, not in general. I still dislike it because it relies on polling. However, in your case it might be the better solution. Also, as long as you don't synchronize the event handlers either by using the InactivityMonitor.SynchronizingObject property or by synchronizing the execution yourself you get some kind of build in multithreading as the implementation uses a System.Timers.Timer[^] object. In this case you just have to make sure that everything you do in your event handler is indeed thread safe.
 
Best regards
Dennis
GeneralMainForm freeze if Global Mouse Hook Monitor is enabledmemberj.d. liau15 Mar '05 - 11:09 
If you use "Hook Monitor (global) and check "Monitor Keyboard". The main form freezes after you click on "Minimize" button on titlebar toolbox couple times. The code always stops at MonitorBase.cs inside ResetBase(). Anyone knows what causes this? Global keyboard hook is working perfectly!
GeneralRe: MainForm freeze if Global Mouse Hook Monitor is enabledmemberDennis C. Dietrich31 Mar '05 - 1:37 
j.d. liau wrote:
If you use "Hook Monitor (global) and check "Monitor Keyboard". The main form freezes after you click on "Minimize" button on titlebar toolbox couple times. The code always stops at MonitorBase.cs inside ResetBase(). Anyone knows what causes this?
 
First, apologies for taking so long to answer your question, but I'm relocating to Ireland right now so I'm quite busy at the moment.
 
Regarding your problem, I tried to reproduce the behavior you're describing with both the release build and the debug build (in this case even with the debugger attached) of my Inactivity Monitor Test Application. However, the program didn't freeze. Maybe you can describe the steps it takes on your computer to reproduce the problem in full detail. Also, some information about your environment (OS, Framework version, etc) might help to find a solution.
 
Best regards
Dennis
GeneralRe: MainForm freeze if Global Mouse Hook Monitor is enabledmembernicidemous15 Jun '05 - 9:23 

I get the same kind of application freezing but it happens when I use an Alt-Tab from my application to another and back. I go into VS and break the code and it is always on the line
 
timeElapsed = false;
 
with the comment "This code has called into another function. When that function is finished, this is the next statement that will be executed."
GeneralRe: MainForm freeze if Global Mouse Hook Monitor is enabled [modified]memberCentralUnit7 Jul '06 - 8:55 
Recently I found out that my application (pure win32), using low level keyboard hook, also freezes when you click on the minimize button so I googeld for a solution and found this post.
 
I downloaded your demo and was able to reproduce the freeze. If you hold down left CTRL and click on the minimize button the program will freeze for about 30s - 1min.
 
Im using WindowsXP SP2 with .NET 2.0 non beta. Perhaps it's a thread priority bug of some kind.
 
Anyone have a solution or simular experience with keyboard hooks ?
 

EDIT: The application does not freeze if you have not started a monitor hook (keyboard).
 

GeneralKudos and Implementation TipmemberBrent R. Matzelle11 Mar '05 - 10:00 
This article is truly excellent. Great job!
 
Quick tip: I only needed the the HookMonitor class for my program so I combined Win32Hook.cs, User32.cs, and Win32LastInputInfo.cs into HookMonitor.cs and dropped the IInactivityMonitor interface from MonitorBase.cs. This reduced the code to two source files (HookMonitor.cs and MonitorBase.cs).

GeneralAddMessageFilter - one questionmemberLuis Alonso Ramos13 Feb '05 - 7:29 

Hello,
 
First, excellent article, really!! It was awesome! Smile | :)
 
I have one question about the Application.AddMessageFilter solution. You state that:
 
Second, when you show a modal form by calling Form.ShowDialog(), you won't receive any messages which are related to the forms in the background
 
So, if my app displays a modal form, the monitor *will* get messages for the dialog? that's enough to reset the timer, isn't it?
 
Anyway, I think I'll use the hooks solution.
 
Thanks!
 
-- LuisR
 


Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
 
Not much here: My CP Blog!

GeneralRe: AddMessageFilter - one questionmemberDennis C. Dietrich13 Feb '05 - 7:55 
Luis Alonso Ramos wrote:
First, excellent article, really!! It was awesome!
 
Thank you! Smile | :)
 
Luis Alonso Ramos wrote:
I have one question about the Application.AddMessageFilter solution. You state that: "Second, when you show a modal form by calling Form.ShowDialog(), you won't receive any messages which are related to the forms in the background." So, if my app displays a modal form, the monitor *will* get messages for the dialog? that's enough to reset the timer, isn't it?
 
Yes. The only situation I know about in which the Application Monitor won't receive any messages is when a message box is displayed. While I was creating the monitor classes I used an early version of the demo application to examine the behavior of the different solutions. I suggest you play a little bit with it yourself to get a feeling for the pros and cons of the four monitor implementations.
 
Luis Alonso Ramos wrote:
Anyway, I think I'll use the hooks solution.
 
That's what I still recommend for most scenarios as it's the only solution that will receive any mouse and keyboard related message regardless of the state of the application.
 
Best regards
Dennis
GeneralRe: AddMessageFilter - one questionmemberLuis Alonso Ramos13 Feb '05 - 8:43 
Dennis C. Dietrich wrote:
That's what I still recommend for most scenarios as it's the only solution that will receive any mouse and keyboard related message regardless of the state of the application.
 
And one more question, licensing issues? A simple "Portions Copyright (c) by you" is enough?? it is a custom application for a client. (That means I'm using your code Smile | :) )
 
-- LuisR
 


Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
 
Not much here: My CP Blog!

GeneralRe: AddMessageFilter - one questionmemberDennis C. Dietrich13 Feb '05 - 9:34 
Luis Alonso Ramos wrote:
And one more question, licensing issues? A simple "Portions Copyright (c) by you" is enough??
 
Not really. I published the code under the BSD License[^] which includes some more conditions. However, since the copyright notice is what really matters to me and you've asked before using the code, the notice you mentioned shall be enough (given that you replace "by you" with "by me" Wink | ;) ).
 
Luis Alonso Ramos wrote:
That means I'm using your code
 
Well, I don't know if you're the first one to use my code within your own production code but at least you're the first one I know about and I really appreciate it. Smile | :)
 
Best regards
Dennis
GeneralRe: AddMessageFilter - one questionmemberLuis Alonso Ramos13 Feb '05 - 11:04 
Dennis C. Dietrich wrote:
the notice you mentioned shall be enough
 
Thanks! My software will be used only by the customers that I'm developing it for. It won't be distributed outside of their company.
 
Dennis C. Dietrich wrote:
but at least you're the first one I know about and I really appreciate it.
 
I'm sure there are several other people using it, it's just that it's so good! Smile | :)
 
-- LuisR
 


Luis Alonso Ramos
Intelectix - Chihuahua, Mexico
 
Not much here: My CP Blog!

GeneralRe: AddMessageFilter - one questionsusskunkos28 Jul '05 - 20:32 
Chupalo!
GeneralMDI IssuesussEricRitzie6 Jan '05 - 9:59 
Like the others I thank you for this article, it was very helpful. On the down side I having a bit of an issue I hope you can help me resolve. I'm using the Application monitor in MDI application, here are the process steps and the exception I am getting:
 
1) Load MDI app and load MDI child for user login.
2) Process login and close & dispose MDI login form.
3) Load subsequent MDI child forms.
4) Enable Application monitor functionality.
5) Activity Timeout executes.
6) Unload all MDI child forms and controls.
7) Load Login form and set .MDIParent = this;.
** Excetion Thrown **
"Controls created on one thread cannot be parented to a control on a different thread."
"Parameter name: value"
 
Can you help me out here? I hope I'm just over looking something. Everything working in a non MDI app.
 
Thank you,
Eric Ritzie

GeneralRe: MDI IssuememberDennis C. Dietrich6 Jan '05 - 10:57 
EricRitzie wrote:
I'm using the Application monitor in MDI application, here are the process steps and the exception I am getting:
 
[...]
 
** Excetion Thrown **
"Controls created on one thread cannot be parented to a control on a different thread."
"Parameter name: value"

 
Now, this seems to be a thread issue (so it is not MDI specific). The problem is that all classes introduced in this article use a System.Timers.Timer[^] object internally. This timer uses a worker thread to raise the Timer.Elapsed[^] event. Accordingly your event handler will not be executed in the thread that created the inactivity monitor and this is a problem when your event handler is supposed to work with controls as controls have to be accessed only from the thread that originally created them (see also Multithreaded Windows Forms Control Sample[^] for details). So in order to solve this problem you need to marshal the execution of the event handler to the thread that created your UI. Fortunately the inactivity monitor does this for you. All you need to do is to tell it which control to use for synchronization by setting the IInactivityMonitor.SynchronizingObject property. Just use any control that you don't want to dispose while using the inactivity monitor (for example your main form). For example (replace this by the correct object if you're not using the monitor in the form that's supposed to be the synchronization object):
IInactivityMonitor inactivityMonitor = null;
inactivityMonitor = MonitorCreator.CreateInstance
                    (MonitorType.GlobalHookMonitor);
inactivityMonitor.SynchronizingObject = this;
Best regards
Dennis
GeneralRe: MDI IssuesussAnonymous10 Jan '05 - 3:26 
Dennis,
Thanks for our help! That sovled the problem I was having! I figured it would be sometihng simple that I was just over looking. Thanks again.
 
-Eric Ritzie
GeneralRelease note supplementmemberDennis C. Dietrich23 Dec '04 - 6:37 
One fact somehow did not make it into the last article update (most likely because I forgot to mention it Wink | ;-) ): The implementation of the Dispose pattern (see Implementing Finalize and Dispose to Clean Up Unmanaged Resources[^]) was incorrect in the original version of the derived classes. This has been fixed with the last update.
 
Best regards
Dennis
GeneralIdea for application level without hooksmemberbiba7620 Dec '04 - 23:43 
Hi!
First of all: thank you for very usefull article, ideas and implementation!
But what about the following approach:
using "Application.AddMessageFilter" technique for application level idle monitoring.
Such way must be much more platform-specific-free than using windows Hooks,
since it needs only in knowning messages ids (and therefore can be easily adopted for new platform).

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 22 Dec 2004
Article Copyright 2004 by Dennis C. Dietrich
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid