Creating Application time out routine?

My windows app needs a mechanism that will lock the application and pop up a form that forces the user to log back into the app. I have NO idea how to program this. The stupid Timer control always confuses me. Can someone please help me with this.

thanks!
BlakeMcKennaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jacques Bourgeois (James Burger)PresidentCommented:
Starting by stating that the Timer control is stupid is stupid in itself. It puts you in a state of mind where you cannot go very far.

Instead of saying that something is stupid, try to understand it. The Timer control is one of the useful tools there is to solve a lot of problems, yours included.

And the Timer is very simple to use. Simply set it's Interval property to the time you want, in milliseconds and then start the timer (by calling its Start method). If the Timer is not stopped before the specified time is reached (by calling its Stop method), it will fire it's Tick event. If you call Start again before the time as elapsed, it resets and start counting again for the specified time. That is all.

You do not specify in you question what is the condition that will require the application to be locked. Since you talk about the Timer, I suppose that you want to lock the application if it is idle for some time, but it is not clear. Could you be more specific?

If this is the case, then the solution is relatively easy if your application has only one form, but might be more complex if you work will multiple forms. One also has to define what "idle" means, because you have to detect that situation, and nothing that I know is built-in to do that for your.

This basically means that you have to start a timer for the desired period, detect all the keypresses, mouse clicks and long processes, and restart the Timer on each one. As long as you restart the Timer, it will not expire and its Tick event will never fire.

But if the user stops working and the application itself does not do some processing in the background, the Timer will not be restarted and will end up firing it's Tick event after the specified Interval. From there you can display the necessary messages and forms to lock the application and force the user to log back in.
0
BlakeMcKennaAuthor Commented:
James,

Thank you for the clear questions and explanation. My application is a multi-form Windows app. It consists of a main form which is a MDI form with many child forms. The application needs to "lock" by displaying a Login form when the expiration time has been reached.

I'm assuming that if this does happen, the Tick event is where I need to put code to check the expiration time against the Timer's Interval as well as display the Login form? If this is incorrect, then it truly shows my ignorance of how this tool works.
0
Jacques Bourgeois (James Burger)PresidentCommented:
Not exactly correct. You do not have to check for the expiration time in the Tick event. If you set the Timer Interval for the proper time, the Tick event will trigger at that time. This is where you will show your login form. All you have to do is to keep the timer alive by restarting when the user actually works in the application.

And that is the main problem. Ideally, you need to check for each operation the user does such as all the click, all the key presses, the form that moves, minimize and maximize, operations done in the form itself, and call Timer Start in each.

It's quite easy for the KeyPress because you can all catch them in one place. But not as much for everything else.

Depending on how the form is to be used, if you expect the user to mostly type information, you might consider that a KeyPress is sufficient to consider that the he is working.

To get all the KeyPress events, first set the KeyPreview property of your MDI form to True. This will make the form receive a KeyPress for all the controls it contains, you can then restart the Timer in that event. And thinking of it, it might be better to put it in the KeyDown instead, in case the user hits a key that does not trigger a KeyPress.
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

BlakeMcKennaAuthor Commented:
James,

I did what you suggested in that I removed the check for the Interval time. The KeyPreview property in my MDI form was already set to True. For test purposes, I set the Timer1 Interval to 5 seconds.

Upon initial startup of the app, all users are required to "Log In" using the Login form. So, when I started the app and logged in, I was then prompted again to log back in after 5 seconds. The Login form has a button that performs routine logic. In the same event, I execute Timer1.Start. After the Login form is closed, execution returns to the Tick event and it just keeps firing, constantly prompting me to Login again. Below is the Tick Event code:

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Try
            gblnSessionTimedOut = True
            Timer1.Stop()
            frmLogin.ShowDialog(Me)

        Catch ex As Exception
            EH.ErrorMessage = "frmMain/Timer1_Tick() - " & ex.Message & "~E"
        End Try

        EH.ProcessMessages(Me, sbr, EH.ErrorMessage)
    End Sub

Open in new window


What am I missing?

Thanks
0
Jacques Bourgeois (James Burger)PresidentCommented:
You are restarting the Time in the MDI form KeyDown, aren't you? Otherwise the Tick events fires 5 seconds after you Start it in your Login form. This is what you want, although probably not after only 5 seconds.
0
BlakeMcKennaAuthor Commented:
Yes, in the MDIForm_KeyDown Event, I execute Timer1.Start. However, it's still not working the way it should. I removed the Timer1.Start from the Login Form's Button Click Event just to see what that would do. After the Login form closed (which left me in the MDI Form) nothing happened...but when I hit a key, the Login form immediately popped back up.
0
Jacques Bourgeois (James Burger)PresidentCommented:
Start needs to be in the login form if you want to thing to work correctly.

The Timer is sometimes set for very short delays, so the Interval is in milliseconds. Could it be that you have set it to 5? In such case, the event fires after 5/1000 of a second.

If you want 5 seconds, you need to set the Interval to 5000, not 5.
0
BlakeMcKennaAuthor Commented:
Your right James, I did have the Interval set to 5. I will recheck things!
0
BlakeMcKennaAuthor Commented:
Unfortunately, this is still not working. Are there any canned routines out there in cyber-world that does what I'm seeking. I've yet to find any...
0
Jacques Bourgeois (James Burger)PresidentCommented:
Not that I know.

Can you show the code in your MDI KeyDown event and in the Tick event of the Timer?
0
BlakeMcKennaAuthor Commented:
Here is the KeyDown Event code:

    Private Sub frmMain_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
        'Debug.Print("frmMain_KeyDown")

        Try
            Timer1.Start()

            If gblnLoggedIn Then
                Dim mdiFrm As Form = Me.ActiveMdiChild
                Dim strForm As String = String.Empty
                Dim iFound As Integer = 0

                EH.ErrorMessage = String.Empty

                If Not IsNothing(mdiFrm) Then   'No Form is being displayed at the moment
                    strForm = mdiFrm.Name
                End If

                If gblnF9Key Then
                    sbr.Items(1).Text = gFKeys2
                Else
                    sbr.Items(1).Text = gFKeys
                End If

                Me.Cursor = Cursors.WaitCursor

                InitializeErrorClass(EH)

                Select Case e.KeyCode
                    Case CType(27, Keys)    'Escape Key
                        For Each frm As Form In Me.MdiChildren
                            frm.Close()
                        Next

                        stcFormSize.Width = 0
                        stcFormSize.Height = 0
                        sbr.Items(1).Text = gFKeys

                    Case CType(112, Keys)   'F1 Key was pressed - Login
                        frmLogin.ShowDialog()

                    Case CType(113, Keys)   'F2 Key was pressed - Log out
                        If gblnChangesMade Then
                            Dim strWarning As String = "You have unsaved changes! If you continue, all changes will be aborted." & vbCrLf & "Continue?"
                            Dim answer As Integer = MessageBox.Show(strWarning, "User Notification", MessageBoxButtons.YesNo, MessageBoxIcon.Question)

                            If answer = vbNo Then
                                Me.Cursor = Cursors.Default
                                GoTo ProcessMessage
                            End If
                        End If

                        gblnLoggedIn = False
                        Me.Cursor = Cursors.Default
                        gUser = String.Empty
                        gUser_ID = 0
                        Me.sbr.Items(2).Text = "Network ID: "
                        frmLogin.ShowDialog()

                    Case CType(114, Keys)    'F3 Key was pressed - Exit Program
                        Me.Close()
                        End

                    Case CType(115, Keys)    'F4 Key was pressed - Custom Settings
                        frmCustomSettings.MdiParent = Me
                        frmCustomSettings.Show()
                        frmCustomSettings.BringToFront()

                    Case CType(116, Keys)    'F5 Key was pressed - Certificates
                        CheckFunctionalityPermission(CStr(CertificatesToolStripMenuItem.Tag), gUser_ID, EH)
                        If EH.ErrorMessage = String.Empty Then
                            If CBool(gblnViewPermission) Or gblnSuperUser Then
                                frmCertificates.MdiParent = Me
                                frmCertificates.Show()
                                frmCertificates.BringToFront()
                            End If
                        Else
                            GoTo ProcessMessage
                        End If

                    Case CType(117, Keys)    'F6 Key was pressed - User Setup
                        CheckFunctionalityPermission(CStr(LookupTablesToolStripMenuItem.Tag), gUser_ID, EH)
                        If EH.ErrorMessage = String.Empty Then
                            If CBool(gblnViewPermission) Or gblnSuperUser Then
                                frmUserSetup.MdiParent = Me
                                frmUserSetup.Show()
                                frmUserSetup.BringToFront()
                            End If
                        Else
                            GoTo ProcessMessage
                        End If

                    Case CType(118, Keys)    'F7 Key was pressed - Lookup Tables
                        'AddHandler frmLookups.EnableDataRefresh, AddressOf frmCalibration_3.EnableDataRefreshButton

                        CheckFunctionalityPermission(CStr(LookupTablesToolStripMenuItem.Tag), gUser_ID, EH)
                        If EH.ErrorMessage = String.Empty Then
                            If CBool(gblnViewPermission) Or gblnSuperUser Then
                                frmLookups.MdiParent = Me
                                frmLookups.Show()
                                frmLookups.BringToFront()
                            End If
                        Else
                            GoTo ProcessMessage
                        End If

                    Case CType(119, Keys)    'F8 Key was pressed - Equipment Verify
                        CheckFunctionalityPermission(CStr(EquipmentVerificationToolStripMenuItem.Tag), gUser_ID, EH)
                        If EH.ErrorMessage = String.Empty Then
                            If CBool(gblnViewPermission) Or gblnSuperUser Then
                                frmEquipVerify.MdiParent = Me
                                frmEquipVerify.Show()
                                frmEquipVerify.BringToFront()
                            End If
                        Else
                            GoTo ProcessMessage
                        End If

                    Case CType(121, Keys)    'F10 Key was pressed - Calibration Houses
                        CheckFunctionalityPermission(CStr(EquipmentVerificationToolStripMenuItem.Tag), gUser_ID, EH)
                        If EH.ErrorMessage = String.Empty Then
                            If CBool(gblnViewPermission) Or gblnSuperUser Then
                                frmCalibrationHouse.MdiParent = Me
                                frmCalibrationHouse.Show()
                                frmCalibrationHouse.BringToFront()
                            End If
                        Else
                            GoTo ProcessMessage
                        End If

                    Case CType(122, Keys)    'F11 Key was pressed - Sensor Calibration
                        rcMessage.Visible = True

                        ShowLoadStatusMessage("Loading Form...", True)
                        If EH.ErrorMessage > String.Empty Then
                            GoTo ProcessMessage
                        End If

                        CheckFunctionalityPermission(CStr(SensorCalibrationToolStripMenuItem.Tag), gUser_ID, EH)
                        If EH.ErrorMessage = String.Empty Then

                            Application.DoEvents()

                            If CBool(gblnViewPermission) Or gblnSuperUser Then
                                frmCalibration_3.MdiParent = Me
                                frmCalibration_3.Show()
                                frmCalibration_3.BringToFront()
                            End If
                        Else
                            GoTo ProcessMessage
                        End If

                        ShowLoadStatusMessage("", False)

                    Case CType(123, Keys)
                        'F12 Key is unassigned
                End Select
            Else
                Select Case e.KeyCode
                    Case CType(112, Keys)    'F1 Key was pressed - Login                   
                        frmLogin.ShowDialog()

                        If gblnLoggedIn Then
                            SetNavigationPermissions(MenuStrip1, ts1)
                            If EH.ErrorMessage > String.Empty Then
                                GoTo ProcessMessage
                            End If
                        End If
                End Select
            End If

            Me.Cursor = Cursors.Default

ProcessMessage:

        Catch ex As Exception
            EH.ErrorMessage = "frmMain/frmMain_KeyDown() - " & ex.Message & "~E"
        End Try

        EH.ProcessMessages(Me, sbr, EH.ErrorMessage)
    End Sub

Open in new window



Here is the Timer1_Tick Event code:

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Try
            Timer1.Stop()
            gblnSessionTimedOut = True
            frmLogin.ShowDialog(Me)

        Catch ex As Exception
            EH.ErrorMessage = "frmMain/Timer1_Tick() - " & ex.Message & "~E"
        End Try

        EH.ProcessMessages(Me, sbr, EH.ErrorMessage)
    End Sub

Open in new window

0
Jacques Bourgeois (James Burger)PresidentCommented:
Looking at your code, everything looks OK. So I tried simulating it on my system. It does not work.

But I nailed it... and I learned something at the same time. Strange that in my 20 years of working with Timers in Windows Forms (VB6 and .NET), I never encountered that situation.

I was under the impression that when you Start the Timer, it cancelled the current run if it was not finished. But it does not. So, when you hit multiple keys, you end up starting multiple runs of the same timer.

The solution is simply to Stop the timer in the KeyDown, to kill the current run, and then restart it:

Timer1.Stop
Timer1.Start
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
For a multiform project, I'd use IMessageFilter so you can trap messages in one place across all forms.

Something like:
Public Class Form1
    Implements IMessageFilter

    Private Const WM_LBUTTONDOWN As Integer = &H201
    Private Const WM_LBUTTONUP As Integer = &H202
    Private Const WM_LBUTTONDBLCLK As Integer = &H203
    Private Const WM_RBUTTONDOWN As Integer = &H204
    Private Const WM_RBUTTONUP As Integer = &H205
    Private Const WM_RBUTTONDBLCLK As Integer = &H206
    Private Const WM_MBUTTONDOWN As Integer = &H207
    Private Const WM_MBUTTONUP As Integer = &H208
    Private Const WM_MBUTTONDBLCLK As Integer = &H209
    Private Const WM_MOUSEWHEEL As Integer = &H20A
    Private Const WM_KEYDOWN As Integer = &H100
    Private Const WM_KEYUP As Integer = &H101
    Private Const WM_SYSKEYDOWN As Integer = &H104
    Private Const WM_SYSKEYUP As Integer = &H105

    Private TargetDateTime As DateTime
    Private IdleTimeInMinutes As Integer = 10
    Private WithEvents tmr As New System.Windows.Forms.Timer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        TargetDateTime = DateTime.Now.AddMinutes(IdleTimeInMinutes)
        tmr.Interval = 1000
        tmr.Start()
        Application.AddMessageFilter(Me)
    End Sub

    Private Sub tmr_Tick(sender As Object, e As EventArgs) Handles tmr.Tick
        Dim TS As TimeSpan = TargetDateTime.Subtract(DateTime.Now)
        If TS.TotalMilliseconds > 0 Then
            ' optional: show much time to the timeout trigger somewhere
            Me.Text = TS.ToString("hh\:mm\:ss")
        Else
            ' idle timeout reached
            tmr.Stop()

            ' do something:
            Application.Exit()
        End If
    End Sub

    Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
        Select Case m.Msg
            Case WM_MOUSEWHEEL, WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, _
                    WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, _
                    WM_RBUTTONDOWN, WM_RBUTTONUP, WM_RBUTTONDBLCLK, _
                    WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MBUTTONDBLCLK

                TargetDateTime = DateTime.Now.AddMinutes(IdleTimeInMinutes)
        End Select
        Return False
    End Function

End Class

Open in new window

0
BlakeMcKennaAuthor Commented:
Mike,

The above code...do I need to place the procedural code in all of my forms?

Form1_Load()
tmr_Tick()
PreFilterMessage()
0
BlakeMcKennaAuthor Commented:
My application consists of a single MDI Form with many child forms. Can the code go in just the MDI or does it need to be in all the child forms as well?

Thanks!
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
You only need to place it once, in the main MDI Parent Form.  It will trap messages across your entire application, including other forms, whether they are MdiChildren or not.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
BlakeMcKennaAuthor Commented:
Thanks Mike!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.