Jump to content

Close Idle Application


Recommended Posts

I'm setting up a kiosk computer for accessing a payroll site.  For privacy and security reasons, we would like to close the session after idling for some time.

I happened to find this script and modified it for my own use.  It does the following:

  • Check for an application windows with the tile starting with "PayDay"
  • It does not limit to a certain application.  So any browser opening the targeted site will be monitored.
  • Start counter when the window in not in focus
  • Close the window when time limit is reached

There is one problem, however.  If the previous user leaves while having the browser window in focus, the script will not count it as idle time.  I wonder if there is a way that we can overcome this.

Hope some experts there may have some insights for me.

 

Pete

 

; ================================================ 

Opt("WinTitleMatchMode", 1) ;1 = Start of String
Opt("TrayIconDebug", 1)

$S_running = "check-4-app" ;name the script
If WinExists($S_running) Then Exit
AutoItWinSetTitle($S_running)

$title = "PayDay"   ; "PayDay is the title of the site"
$count = 0
While 1
    $state = WinGetState($title)
    $count += 1

    If $state = 15 Or $state = 47 Or $state = 0 Then $count = 0

    If $count > 10 Then WinClose($title)  ;close after idling for 10 seconds

    ToolTip("count = " & $count, 0, 0, "state = " & $state)
    Sleep(1000)    ; reloop in 1 sec
WEnd

; ================================================ 

 

 

Link to comment
Share on other sites

Well, until the experts get here... my first thought was if you ran a screensaver to look for that .scr process and then kill your windows, but I did a quick search and ran across this old thread that might better suit your needs - especially jmon's and stormbreaker's posts.

 

Link to comment
Share on other sites

I once wrote a similar script. Will post after my vacation (27th Oct)

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

This seems to work well - if there is no keyboard or mouse input, it kills the window if it exists.

#include <WinAPISys.au3>
$title = "PayDay"   ; "PayDay is the title of the site"
$minutes = 15

While 1

    ;if the timer is more than X minutes then:
    If _WinAPI_GetIdleTime() >= $minutes * 60 * 1000 AND WinExists($title) Then
        MsgBox (0, "Time reached", "You have been idle for more than " & $minutes & " minutes.", 5)
        WinClose($title)
        ; Exit
    EndIf

    ;Sleep for 5 seconds before looping again:
    Sleep(5000)
WEnd

 

Edited by MuffinMan
Link to comment
Share on other sites

Wont that msgbox there allow the "NEXT user" to override the close process?

Looks like it will stay open until someone clicks on OK and then it will close...

...if you know what I mean.

Link to comment
Share on other sites

Yeah, the MsgBox was in the original code and I left it in just for testing / debugging purposes.  If the OP truly wants a popup, then the Msgbox needs to have a timeout on it.  I edited my earlier post to include a 5 second timeout on the MsgBox.  Thanks for keeping me straight, Bill! ;-)

Link to comment
Share on other sites

PeterPan8383,

has your problem been solved with the examples you got or do you want me to post my script too?

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

  • 1 year later...
  • 9 months later...
  • 10 months later...
Link to comment
Share on other sites

On 10/21/2016 at 9:36 PM, MuffinMan said:

This seems to work well - if there is no keyboard or mouse input, it kills the window if it exists.

#include <WinAPISys.au3>
$title = "PayDay"   ; "PayDay is the title of the site"
$minutes = 15

While 1

    ;if the timer is more than X minutes then:
    If _WinAPI_GetIdleTime() >= $minutes * 60 * 1000 AND WinExists($title) Then
        MsgBox (0, "Time reached", "You have been idle for more than " & $minutes & " minutes.", 5)
        WinClose($title)
        ; Exit
    EndIf

    ;Sleep for 5 seconds before looping again:
    Sleep(5000)
WEnd

 

I have a script paused for this one anyone have any idea ? 

I was changing the "payday" to the program name 

Link to comment
Share on other sites

18 hours ago, Nine said:

$title is the window title not the program name...

well, i will be very happy if you helped me i was trying all the scripts but im always having the script paused problem 

 

#include <Array.au3>
#include <Timers.au3>
#include <WinAPIProc.au3>
Global $sProductFilePath = @WindowsDir
Global $sProductFileName = "Notepad.exe"
Global $sProductName = FileGetVersion($sProductFilePath & "\" & $sProductFileName, "ProductName")
Global $hProcessWnd, $aProcessList, $idMsgBox
Global $iTimerInit = TimerInit()
Global $iIdleTime = _Timer_GetIdleTime()
While 1
    $aProcessList = ProcessList($sProductFileName)
    If $aProcessList[0][0] >= 2 Then
        $idMsgBox = MsgBox(48, $sProductName, "Multiple Licenses Detected" & @CRLF & @CRLF & "Due to license limitations only one copy of " & $sProductName & " is allowed." & @CRLF & @CRLF & "Please close additional copies of " & $sProductName)
        $iTimerInit = TimerInit()
        ContinueLoop
    EndIf
    $iProcessId = ProcessExists($sProductFileName)
    If $iProcessId Then
        $iIdleTime = _Timer_GetIdleTime()
        $hProcessWnd = _GetHwndFromPID($iProcessId)
        If WinActive($hProcessWnd ) Then
            $iTimerInit = TimerInit()
        EndIf
        ;~ If the timer is more than 40 minutes then send message to user and close the process, otherwise it closes within 5 minutes
        If TimerDiff($iTimerInit) >= 40 * 60 * 1000 Or $iIdleTime >= 40 * 60 * 1000 Then
            $idMsgBox = MsgBox(48, $sProductName, $sProductName & " has been idle for more than 40 minutes and will be closed in 5 minutes if no activity is detected.", 300)
            If $idMsgBox = -1 Then ProcessClose($sProductFileName)
        EndIf
    EndIf
    Sleep(100)
WEnd

;Function for getting HWND from PID
Func _GetHwndFromPID($_iProcessId)
    Local $_hProcessWnd
    Local $iWinList, $_aWinList = WinList()
    For $i = 1 To $_aWinList[0][0]
        If $_aWinList[$i][0] <> "" Then
            $iWinList = WinGetProcess($_aWinList[$i][1])
            If $iWinList = $_iProcessId Then
                $_hProcessWnd = $_aWinList[$i][1]
                ExitLoop
            EndIf
        EndIf
    Next
    Return $_hProcessWnd
EndFunc;==>_GetHwndFromPID

 

Link to comment
Share on other sites

Alright, I modified the above script to solve a minor bug, and I made it more generic in terms of the displayed message :

#include <Timers.au3>
#include <FileConstants.au3>

Global Const $IDLE_MINUTES = 1, $TIME_WAITING = 10, $TIME_DESC = Not Mod ($TIME_WAITING, 60) ? "Minutes" : "Seconds"
Global Const $sProductFilePath = @WindowsDir
Global Const $sProductFileName = "Notepad.exe"
Global Const $sProductName = FileGetVersion($sProductFilePath & "\" & $sProductFileName, $FV_INTERNALNAME)

Global $hProcessWnd, $aProcessList, $idMsgBox
Global $iTimerInit = TimerInit()
Global $iIdleTime = _Timer_GetIdleTime()
While 1
  $aProcessList = ProcessList($sProductFileName)
  If $aProcessList[0][0] >= 2 Then
    $idMsgBox = MsgBox(48, $sProductName, "Multiple Licenses Detected" & @CRLF & @CRLF & "Due to license limitations only one copy of " & $sProductName & " is allowed." & @CRLF & @CRLF & "Please close additional copies of " & $sProductName)
    $iTimerInit = TimerInit()
    ContinueLoop
  EndIf
  $iProcessId = ProcessExists($sProductFileName)
  If $iProcessId Then
    $iIdleTime = _Timer_GetIdleTime()
    $hProcessWnd = _GetHwndFromPID($iProcessId)
    If WinActive($hProcessWnd) Then $iTimerInit = TimerInit()
    If TimerDiff($iTimerInit) >= $IDLE_MINUTES * 60 * 1000 Or $iIdleTime >= $IDLE_MINUTES * 60 * 1000 Then
      $idMsgBox = MsgBox(48, $sProductName, $sProductName & " has been idle for more than " & $IDLE_MINUTES & " minutes and will be closed in " & _
          $TIME_WAITING & " " & $TIME_DESC & " if no activity is detected.", $TIME_WAITING)
      If $idMsgBox = -1 Then
        ProcessClose($sProductFileName)
      Else
        $iTimerInit = TimerInit()
      EndIf
    EndIf
  EndIf
  Sleep(100)
WEnd

;Function for getting HWND from PID
Func _GetHwndFromPID($_iProcessId)
  Local $_hProcessWnd
  Local $iWinList, $_aWinList = WinList()
  For $i = 1 To $_aWinList[0][0]
    If $_aWinList[$i][0] <> "" Then
      $iWinList = WinGetProcess($_aWinList[$i][1])
      If $iWinList = $_iProcessId Then
        $_hProcessWnd = $_aWinList[$i][1]
        ExitLoop
      EndIf
    EndIf
  Next
  Return $_hProcessWnd
EndFunc   ;==>_GetHwndFromPID

Tested and works perfect.  Just adjust the Const to fit the timers you want.

Enjoy !

Edited by Nine
Link to comment
Share on other sites

  • 3 years later...

Hi,

Thanks for the code. I have been working on it solve the problem my company has with an ERP software. There are limited number of licenses and people just leave the software open logged in which prevents others to use it. So, I've wanted to automatically close the software on user PCs after a certain period of being idle. 

The problem I have; the ERP software obviously predicted people would try this so they have a way of not logging the user off when the software is closed from task manager. Or using ProcessClose/WinKill commands. The only way to close the software and successfully log out is by pressing the "X" on the window and then clicking "Yes" in the pop-up window. Pressing "e" should also work. ChatGPT suggested using WinClose with exact window name. I can go as far as the little pop-up window but then things go haywire. Either it can't click "Yes" and the pop-up window stuck or somehow all the menus disappear on the window and I have to use the task manager to close the software. 

I'm attaching the code I have used. I'm also open to other ideas and maybe there is a different command which would force close the software meanwhile logging it off. Thanks in advance.

#include <Timers.au3>
#include <WinAPI.au3>

Global Const $IDLE_MINUTES = 1
Global Const $sWindowTitle = "ERP Software"

Global $hProcessWnd, $aProcessList, $sWindowClass
Global $iTimerInit = TimerInit()
Global $iIdleTime = _Timer_GetIdleTime()

; Disable Pause hotkey (Ctrl+Pause) to prevent users from pausing the script
HotKeySet("^{Pause}", "NoPause")

; Hide the tray icon
#NoTrayIcon

Func NoPause()
    ; Do nothing
EndFunc

While 1
    $hProcessWnd = WinGetHandle($sWindowTitle)
    If $hProcessWnd <> 0 Then
        $iIdleTime = _Timer_GetIdleTime()
        $sWindowClass = WinGetClassList($hProcessWnd)
        If WinActive($hProcessWnd) Then $iTimerInit = TimerInit()
        If TimerDiff($iTimerInit) >= $IDLE_MINUTES * 60 * 1000 Or $iIdleTime >= $IDLE_MINUTES * 60 * 1000 Then
            ; Forcefully close the main window
            WinKill($hProcessWnd)

            ; Wait for the small window to appear (adjust the sleep time if needed)
            Sleep(1000)

            ; Send "Enter" key to the small window to select the default option ("Yes")
            Send("{ENTER}")
        EndIf
    EndIf

    Sleep(100)
WEnd

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...