Automatic Logoff of CW App after Inactivity

Hi all…

Does anyone know of a template or embeds to automatically log someone off a CW app
after a period of inactivity? I need to update some apps once in a while,
but everybody stays logged on and makes it very difficult. Having a way to
have them “drop off” automatically would be a great help.
Thanks for any help.

Wawa

Look at: AutoCloseServer:
http://www.capesoft.com/docs/NetTalk8/NetTalk2.htm#CloseAppControls

See the IDLE command in the language reference

Ok… pbouma & Mark thank’s…

As I understand, the requirement is to log people out or kill the application if there was inactivity for a stipulated period.
Just to check IDLE, I created a test app with an IDLE(Procedure,5) in program setup. This gets called every 5 seconds even though I was moving my mouse. Therefore, I think IDLE itself might not be sufficient.

I had a similar requirement to log off user based on user inactivity. I did that using window API calls:

GetTickCount or GetTickCount64
GetLastInputInfo

The GetLastInputInfo returns the last time there was a user activity on the PC.

Global Data

LIF GROUP()
cbSize  UNSIGNED
dwTime  ULONG
 END

Inside Global Map

MODULE('WIN32')
    GetTickCount(),ULONG,PASCAL
    GetLastInputInfo(LONG),ULONG,PASCAL
END

NOTE: GetLastInputInfo(LONG), where Long is ADDRESS(LIF).

You could call these procedures in your IDLE procedure to detect last user activity take actions accordingly

Inactivity Timeout is one of many features in our Super Security templates. You can get more info here: https://boxsoft.net/prod-sec.htm. It’s also smart enough not to timeout while running long tasks like Reports.

Mike Hanson
www.boxsoft.net

Well, it depends on the environment. On a terminal server, I set everyone’s session to 20 minutes of idle time. Windows will end their session after 20 minutes of being idle. I don’t have to do anything in the program.
Then again, if the requirement is not to automatically log someone off but to be able to update an app, then all you need to do is rename the exe and put the updated app in its place. Users can continue working (or stay idle) and you can go home. I do this several times some days with 100’s of active users. (Of course this won’t work very well if you are changing any file definitions).

I was able to do this using GetLastInputInfo API but it works for the whole OS not just for current app.

Anyone know how to get inactivity for my Application only (per “my application instance”)???

I’m curious to know whey your update requires users to log off. Is it because you need to change the database, or replace the EXE?

FWIW:-

I have a site that uses a MS SQL database and MS Access clients. The client “knows” its current version, and checks this in a Version table on the server whenever the user starts the program. If they differ then it exits and runs a batch file to copy the new client code to the workstation.

If I need to update the data structure it’s easy enough to add new fields, or even increase the field size, but deleting a field becomes more of a problem. In that case it is best to prepare the new code file and update the clients before removing the field from the live database.

Most of the updates are done outside normal office hours, so I have a background routine that will automatically quit the program after 11pm, to cater for people who leave work without closing the program.

Perhaps instead of checking for user inactivity, you could do a regular check for a new program version, and then ask the user to exit? The ask dialog could have a timer to answer “Yes” by default if the user doesn’t respond after a few minutes.

I’ve got a timer event on my app frame. Every few seconds I check a flag on the database and if set, a waning is displayed and shuts the program down. All you need to do then is set the flag, wait a minute and everyone is out. The program check the flag on startup and won’t start till the flag is reset.

Bertus

I have used the same technique as Bertus, but added a feature where I can remotely set to close down and prevent opening from an administrators’ program. That allows us to close everyone down, deploy an upgrade, then reset to allow opening again. We can then do a minor upgrade as long as database changes are minimal very quickly (3-5 min) during working hours. Obviously any larger database alterations still get have to be done outside busy working hours.

The CleanCloseDown templates support this really well (see Clarion help pages)

Regards, Jim

2 Likes

I just need the app to auto-shutdown if no one is touching it. It should happen if it’s in any procedure. Of course any mouse movement etc must reset the timer. It’s a tablet app btw. Also there’s a chance the SQL database becomes unavailable at some point (don’t ask why) so I cannot use any database-related trick.

Any cool and simple ideas?

Thx
Bostjan

You may have to deal with an open MESSAGE(). The Capesoft Message Box replacement allows for a timeout to choose the default button. Its also a regular Clarion window procedure so you can add any logic you’d like to deal with inactivity.

I usually pay attention to the Message() that show during the login and start up, e.g. Message('Login or Password Invalid') or Message('You must update'). It seems like users leave those open while they try to figure out what’s wrong, then go to lunch making things difficult.

Hi,

What I have done for applications where patient data cannot be left on the screen is use the CleanCloseDown extension which can then get called from a monitoring ROUTINE on Event Timer on the Main Frame. Then set up a Global to keep track of activity by simple counting and resetting.
I include a global BYTE called CloseNow which gives me another Yes/No signal to close, and run a window so the user can see closing is about to happen and stop it. I can then use the CloseNow to remotely shut down the program for updating etc. Whatever way closing happens there is a countdown window but the text changes depending on if it is timing out or administrator shutdown.

OF EVENT:Timer
! [Priority 5000]
GLO:IdleTime += 1 ! Increase count of idle time by one min every min (Reset occurs by user action elsewhere)

! [Priority 5000]
DO MonitorClosedown ! ROUTINE to check status of globals and call forced closing as needed

I have other things in my ROUTINE to set up a log audit trail etc and open the countdown window but the closing lines are in a called procedure that sets up recording automatic closing happened for recording in the log

  IF TimeLeft = 0 ! Once timeout reached close POW+ else just close window
    IF GLO:CloseNow ! Mark method by which close was triggered
       GLO:CloseBY = Close:SysAdmin
    ELSE
       GLO:CloseBy = Close:Timer
    END
    CleanCloseDown()
  END

Then on every window at TakeAccepted Priority 4100, (must be after the IF ELSE END) rest the timer unless closing has been called:

IF ~GLO:CloseNow THEN GLO:IdleTime = 0. ! Reset idle counter on any user accepted action

I think using the CleanCloseDown extension rather than a simple event(closedown) to Close is important to ensure everything gets cleared up properly in the multi threaded system.

It isn’t fool proof because if someone just closes a laptop I won’t get proper recording (I can still see who had it open before the lid was shut though) but nobody can leave the programs running and break our strict UK data protection laws, which is the main thing here.

I hope that helps.

Regards, Jim

1 Like

GetTickCount function (sysinfoapi.h) - Win32 apps | Microsoft Learn

GetLastInputInfo function (winuser.h) - Win32 apps | Microsoft Learn

   LastInputInfo   Group,Type
   cbSize          Uint !ulong
   dwTime          Dword !long
                   End
    Module('GetLastInputInfo')
    IS_GetLastInputInfo(*LastInputInfo),Bool,Pascal,Raw,Name('GetLastInputInfo')
    End

    Module('Win32')
    IS_GetTickCount(),Dword,Pascal,Raw,Name('GetTickCount')
    End
    Code
Loc:LastInputInfo.cbSize = Len(Loc:LastInputInfo)
Loc:rvGetLastInputInfo = IS_GetLastInfputInfo(Loc:LastInputInfo)

Loc:GetTickCount = IS_GetTickCount()
Loc:SystemUptime = Loc:GetTickCount / 10
If Loc:SystemUptime > 8640000
    Loc:SystemUpDays = (Loc:GetTickCount / 10) / 8640000
    Loc:SystemUpTime = (Loc:GetTickCount / 10) - (Loc:SystemUpDays * 8640000)
End
Loc:ClarionClock = Clock()
Loc:SystemStartDate = Today() - Loc:SystemUpDays
If Loc:SystemUpTime < Loc:ClarionClock
    Loc:SystemStartTime = Loc:ClarionClock - Loc:SystemUpTime
Else
    Loc:SystemStartTime = (8640000 - Loc:SystemUpTime) + Loc:ClarionClock
End
Loc:LastInputTime = (Loc:LastInputInfo.dwTime /10) + Loc:SystemStartTime
Loc:IdleTime = Clock() - Loc:LastInputTime

Then just Post and event or send a Notify.

I think that should work.

Regardless which method to detect program’s inactivity to be used do not forget to disable it if the program runs under debugger. See the IsDebuggerPresent API function.

From the Devil’s Advocate … I had this situation of a corporate windows setup screen saver knocking me out for inactivity every 10 minutes to make me re-enter my password. I didn’t like it and found the below link that uses GetLastInputInfo() to check for 9 minutes of inactivity then used keybd_event() to send a SHIFT Up key event to reset Last Input. Worked great! I mostly used it working from home, and I never had sensitive info anyway.

VK_SHIFT            EQUATE(10h)   !or VK_CONTROL         EQUATE(11h)
KEYEVENTF_KEYUP     EQUATE(2)
  CODE
  keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)  !go up on the shift key to trigger activity


  MAP
  MODULE('WinAPI')
keybd_event    PROCEDURE( |    !VOID WINAPI keybd_event(
    BYTE       bVk         , | !BYTE bVk,
    BYTE       bScan       , | !BYTE bScan,
    UNSIGNED   dwFlags     , | !DWORD dwFlags,
    UNSIGNED   dwExtraInfo   | !ULONG_PTR dwExtraInfo
    ),PASCAL,DLL(1),RAW

https://www.willhaley.com/blog/delay-windows-idle-timer/

Pretty basic corporate windows setup then if it couldnt detect the app sending the SHIFT Up key every 9 mins.

There’s lots of parameters to get metrics from, this one SHQueryUserNotificationState function (shellapi.h) - Win32 apps | Microsoft Learn and these states QUERY_USER_NOTIFICATION_STATE (shellapi.h) - Win32 apps | Microsoft Learn although normally used with systray icons can be used to find out if the app is idle because there is some other app like powerpoint or youtube running max screen or maybe they are gaming.

I’d be surprised if the Will Haley blog trick works now a days.

Is that because the debugger will “hang” or suspend the app and then there is a risk of the shutdown-if-idle code kicks in, making debugging more difficult or something else?

In my Embedded Screensaver template after some user inactivity a local screensaver (inside the app window) is running. Instead of screensaver HALT command could be called to terminate the app.