Solved

How to implement security timeout in C# Forms project?

Posted on 2009-07-10
5
642 Views
Last Modified: 2012-05-07
Experts,

I am implementing the security portion of a project that has a requirement for a password screen to get into the Security mode, as well as a requirement for that password prompt to activate after a timeout period.  So once the user passes the login screen, I have to start timing for inactivity, and reset the timer as soon as there is any interaction at all with the app.  If the timer reaches a certain point (say, a minute), I need to pop up the password dialog again.

My first thought is that I'll have to have event handlers in everything that can be acted upon, and then reset the timer when those events are fired.  However, this seems like an inelegant solution that will be costly to maintain.  Is there an easy way to catch click and keystroke events all in one place, and not in individual forms?  Has anyone done anything like this before?  Any suggestions will be appreciated.  If it helps to know, I am using SmartParts and the CAB, as well as Infragistics 9.1 with a ribbon tool.

Thanks,
J
0
Comment
Question by:jammerms
  • 3
  • 2
5 Comments
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 300 total points
ID: 24827540
You can implement IMessageFilter() to get messages for your ENTIRE application BEFORE they get routed to the currently active form/control.

See my example here for a start:
http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_23822485.html
0
 

Author Comment

by:jammerms
ID: 24852314
Sorry for the delay, Idle_Mind, I have been implementing your solution in C# for my project in between working Support calls--it is not that I have ignored your response.

Thank you for your excellent input, I will update this question as soon as I am able.

Thanks,
J
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24852391
Take your time...and ask questions as necessary.

Sorry it's in VB.Net...C# syntax is SLOWLY growing on me....haha.  =)
0
 

Author Comment

by:jammerms
ID: 24882556
Here is my C# implementation.  I ignore double-click messages as the MSDN documentation states that each one occurs after four messages of down-up-down-up have already happened.  I'm using a singleton that multiple other objects can listen in on using the public event.  The trace and throw code in the catch block is just my company's development standard, it's certainly not intended as best practice.

Feel free to comment on this to let me know what I've done wrong, I'm always looking to get better.  I'll leave this open for a day or so and then accept the solution from Idle_Mind linked above.

Thanks,
J
	public delegate void UserInputTimerDelegate(object sender, EventArgs e);
 
	/// <summary>
	///This is a singleton object intended to notify anyone listening on the
	///available public event that the user has not interacted with the application.
	///  
	///Interaction is defined by keydown, keyup, syskeydown, syskeyup, down and up
	///events for all mousebuttons, and the mousewheel.  Polling is done every second.
	///
	/// </summary>
	public sealed class UserInputTimer : IMessageFilter
	{
		#region Member Variables
 
		//public event for wiring into timeouts
		public event UserInputTimerDelegate TimedOut = null;
 
		private const int WM_LBUTTONDOWN = 0x201;
		private const int WM_LBUTTONUP = 0x202;
		//private const int WM_LBUTTONDBLCLK = 0x203;
		private const int WM_RBUTTONDOWN = 0x204;
		private const int WM_RBUTTONUP = 0x205;
		//private const int WM_RBUTTONDBLCLK = 0x206;
		private const int WM_MBUTTONDOWN = 0x207;
		private const int WM_MBUTTONUP = 0x208;
		//private const int WM_MBUTTONDBLCLK = 0x209;
		private const int WM_MOUSEWHEEL = 0x20A;
		private const int WM_KEYDOWN = 0x100;
		private const int WM_KEYUP = 0x101;
		private const int WM_SYSKEYDOWN = 0x104;
		private const int WM_SYSKEYUP = 0x105;
		
		private int _iIdleTimeInSeconds = 9000;
 
		private System.Timers.Timer _timer = new System.Timers.Timer(1000);
		private DateTime _dateTargetTime;
 
		private static UserInputTimer _uniqueInstance = null;
 
		#endregion
 
		#region Constructor / Instance Property
 
		private UserInputTimer(int timeoutInSeconds)
		{
			_iIdleTimeInSeconds = timeoutInSeconds;
			_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
		}
 
		public static UserInputTimer Instance
		{
			get
			{
				if (_uniqueInstance == null)
				{
					_uniqueInstance = new UserInputTimer(SecurityDAO.GetTimeoutInMinutes() * 60);
					System.Windows.Forms.Application.AddMessageFilter(_uniqueInstance);
				}
 
				return _uniqueInstance;
			}
		}
 
		#endregion
 
		#region Methods
 
		public void Start()
		{
			try
			{
				_dateTargetTime = DateTime.Now.AddSeconds(_iIdleTimeInSeconds);
				if (!_timer.Enabled)
					_timer.Start();
			}
			catch (Exception ex)
			{
				Trace.WriteLine("Exception in UserInputTimer.Start:  " + ex.Message);
				throw ex;
			}
		}
 
		/// <summary>
		/// If the no one's listening (i.e., TimedOut event is null), then
		/// stop the timer and remove it from the Application Message Filter
		/// collection.
		/// </summary>
		public void Stop()
		{
			try
			{
				if (this.TimedOut == null)
				{
					_timer.Stop();
					Application.RemoveMessageFilter(_uniqueInstance);
				}
			}
			catch (Exception ex)
			{
				Trace.WriteLine("Exception in UserInputTimer.Stop:  " + ex.Message);
				throw ex;
			}
		}
 
		private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			try
			{
				if (_dateTargetTime.Subtract(DateTime.Now).TotalMilliseconds < 0)
				{
					_timer.Stop();
					if (TimedOut != null)
					{
						TimedOut(this, new EventArgs());
					}
				}
			}
			catch (Exception ex)
			{
				Trace.WriteLine("Exception in ApplicationTimeout._timer_Elapsed:  " + ex.Message);
				throw ex;
			}
		}
 
		#region IMessageFilter Members
 
		public bool PreFilterMessage(ref Message m)
		{
			try
			{
				switch (m.Msg)
				{
					case WM_KEYDOWN:
					case WM_KEYUP:
					case WM_LBUTTONDOWN:
					case WM_LBUTTONUP:
					case WM_MBUTTONDOWN:
					case WM_MBUTTONUP:
					case WM_RBUTTONDOWN:
					case WM_RBUTTONUP:
					case WM_SYSKEYDOWN:
					case WM_SYSKEYUP:
					case WM_MOUSEWHEEL:
						_dateTargetTime = DateTime.Now.AddSeconds(IDLE_TIME_IN_SECONDS);
						break;
 
					default:
						break;
				}
 
				return false;
			}
			catch (Exception ex)
			{
				Trace.WriteLine("Exception in UserInputTimeout.PreFilterMessage:  " + ex.Message);
				throw ex;
			}
		}
 
		#endregion
 
		#endregion
	}

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24882641
Looks good...though I didn't look that closely as C# is ugly...   ;)

I'll just throw this last thought out there...

...we could also set the Timer Interval to the actual TimeOut duration (instead of polling every second to see if we have passed the target DateTime).  So if you wanted a 30 second timeout:

    _timer.Interval = (int)TimeSpan.FromSeconds(30).TotalMilliseconds; // syntax may not be quite right

Then, whenever you get an "input" just stop and restart the Timer:

    _timer.Stop();
    _timer.Start();

Now, if the Timer ever fires (because no inputs were received in the last XXX seconds) then you should take action.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Keyboard 2 41
VB.NET 2008 Winforms Signing 13 32
bound data table problem 2 33
C#.net split string and then check appropriate checkboxlist 4 27
Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question