I'd like to detect if a program is being used and if its not i wanna terminate it, im out of ideas on how to detect if its being used or not, i dont even know if its possible to detect that, i dont want the program to be just opened without anyone using it, so there must be some input in it, if there is no input for like 5 minutes, i kill it. does anyone have any idea\API that i should lookup to do that ?

The Keeper
Posted on 2003-12-18 07:50:49 by The Keeper
FindWindow.. should work for finding the program
in win2k/xp you could use NtQuerySystemInformation to retrieve a list of running modules etc, or you could use toolhelp.dll or psapi.dll for 9x and 2k/xp/nt respectively, tho with 9x being dead now you might as well move over and use the 2k/xp/nt method ;)
Posted on 2003-12-18 08:10:40 by evlncrn8
Hey Keeper =)

I think what you might look into is the Mouse hook tutorial found on the site. You can create a mouse hook for the window and check if the mouse has gone over the dialog in the last 5 minutes and if not terminate it! Just a basic idea of how I think I would do it.

Note: Hooks tend to slow down the system because they increase the amount of processing the system must perform for each message. You should install a hook only when necessary, and remove it as soon as possible.

Ok, just thought of this after I posted.
If it's your program that you're trying to do this for, you could use WM_MOUSEMOVE in your window procedure and have a timer or something check if the mouse has been moved in last 5 minutes. If it's not your programs dialog window, SetWindowLong should work with it.
Posted on 2003-12-18 08:11:00 by ESP

evlncrn8, i know how to check if the program is opened, but i need to check if it is being used or not because my workers often leave this program opened when they go for dinner for example and dont close it

ESP, its not my program as you can see above, i guess the SetWindowLong is the best choice now, is your idea changing the windowproc of the other application ? btw, the OS i need my application to run is only Win98SE

The Keeper
Posted on 2003-12-18 09:04:30 by The Keeper
My plan for the SetWindowLong is setting a new address for the window procedure. If you didn't want to use SetWindowLong or doesn't work, try the hook. You can hook specific messages sent to the window procedure with SetWindowsHookEx if you want to.
Posted on 2003-12-18 12:37:23 by ESP

If you're willing to code a vxd, you might want to look into Timing Query Services. Once you've gotten the handle of the main thread of your application, you may be able to monitor its actual running time/usage with the services _GetThreadExecTime or _GetLastUpdatedThreadExecTime. From the DDK:

Time query services allow a virtual device to obtain information about how long the system, a virtual machine, or a thread has been executing, in milliseconds.
When the system creates a thread or virtual machine, it sets the execution time for the thread or virtual machine to zero. The system increases the execution time only when the thread or virtual machine actually runs. Therefore the execution does not reflect the length of time the thread or virtual machine has existed, but indicates the amount of time the thread or virtual machine has run. Note however that any code executed in the indicated thread or virtual machine contributes to the tally; it is not the case that one second of thread execution time or virtual machine execution time translates into one second of actual CPU time given to the application.

For each query service there are two variants, the standard form and the last updated form (for example, _GetThreadExecTime and _GetLastUpdatedThreadExecTime). The standard form returns the time to millisecond accuracy, whereas the last updated form returns the time only to an accuracy of approximately 50 milliseconds. The difference is that the standard form will ask the timer device to give the time to millisecond accuracy, and use the result to compute the value to return, whereas the last updated form returns the value most recently obtained by a standard form call, or by the timer device explicitly updating the system clock (which happens on every timer tick).

If the interval being measured is on the order of seconds or minutes, the last updated form is sufficient because a 50 milliseconds variation will not make a noticeable difference. If the interval being measured is less than one half second, you may be better off with the standard form.

VMMcall _GetThreadExecTime, <hThread>
mov , eax

Retrieves the amount of time that a particular thread has executed. The value returned indicates the amount of time the specified task has been the currently running thread.
This service can be called at interrupt time.

From the sounds of this, if I'm interpreting its usage correctly, you could set up your own timer to poll the vxd routine every 5 minutes or so and compare the returned for the thread to see if it has changed. (Or you could hook an interrupt for your own use and call _GetThreadExecTime from your ISR). If your user has clicked a couple of buttons or something since the last polling then the value should be different. I'm not sure though if the thread sitting in an idle message loop while the window still has focus (while your users are eating dinner) might contribute to the total execution time, in which case it might be hard to detect true usage by this method.

As for getting the proper thread to use in the call, there's probably various ways to do that. One might be to load your vxd when Windows starts and use GetVxDServiceOrdinal to hook some low level service that is always called when a user application starts (VMMCreateThread perhaps, or if the application itself loads a vxd, then VMM_Add_DDB), then use some other vxd service to get the name or path of the application to confirm this is the thread you want to monitor.

Doing it through a vxd might be the most efficient method because the only CPU time you'd be using is when you call the _GetThreadExecTime routine every 5 or 10 minutes or so. There may be other ways to monitor CPU usage of a specific thread as well, but these Timing Services may be cut out for job at least. Just an idea anyway.


EDIT: Lol, one other thought - make sure all your users are using a screensaver, then detect when it activates and close the background app...?
Posted on 2003-12-18 17:27:37 by Kayaker
how about polling wether a screensaver is running with GetSystemParameters? It requires a screensaver to be on the system of course...
Posted on 2003-12-18 17:36:20 by Hiroshimator
Alright I had time to test some stuff and I came up with this.

Use the SetWindowLong to get the windows procedure, then use WM_MOUSEMOVE

DetectEvent PROTO ; Our idle detection
dwTick dd ? ; Used for GetTickCount
dwThreadId dd ? ; Used for CreateThread
ThreadCreated dd ? ; Thread was created, create no more =)

; this will be in the new window's procedure.
mov eax,uMsg
.elseif eax==WM_MOUSEMOVE
invoke GetTickCount ; retrieves the number of milliseconds that have elapsed since Windows was started
mov dwTick, eax ; Move time into dwTick
add dwTick,300000 ; add 5 minutes idle time.
.if ThreadCreated == NULL ; Needed to make it not lagg the program
invoke CreateThread, NULL, NULL, ADDR DetectEvent, NULL, 0, ADDR dwThreadId
mov ThreadCreated,eax ; Get the return value

DetectThread proc
invoke GetTickCount ; Get time again
cmp dwTick,eax ; Check if it has been 5 minutes of inactivity.
jl GetTick ; if it has not been 5 minutes, check for new time.
; add your terminateprocess here...
DetectThread endp

*Edited in the Lagg Fix.*
Posted on 2003-12-18 22:59:41 by ESP