How to determine if another application is active?
-
I am working in VB.Net VS2005 (.NET 2.0).
I need a way to determine if another (third party) application on the PC is running and is active.
being active means, the user is actually using it(clicking on it, typing in it, scrolling ...etc).Background:
I have a project to monitor certain third party applications on users' PCs and determine if these applications are activley being used or if they are idle and not being used.
These are third party applications and the idea is to close down this application after a period of 10 minutes of being inactive so as to reclaim the license.I am working with the process class which exposes certain (basic) information about the process, however, i still can not figure out how to tell if there is a way to monitor if an application is being used (active/inactive).
Your help would be appreciated.
Thanks!
-
Well I'm not sure I'll be much help, but this is my idea. How you implement it I haven't a clue but maybe it will help get you started. You obviosly need to know which application are "running". By running I don't mean being used. Then you could create a timer for each application. The timer should be reset if a key is pressed or mouse is moved and that application is the active window. Whenever a timer hits 10 minutes you shut the program down. This of course assumes the types of programs you are monitoring aren't meant to just run in the background like encoding a movie or something. To monitor mouse and keyboard activity you'll need a system hook. I have know idea how it works but you should look up 'mouse hooks' or ask about them. I've done a little research in that area but never got anything working. Sorry, that's all I've got, just ideas and nothing of real great help but maybe what I said will help give you and idea about how it could be done.
-
I had an inspiration today. I found myself playing around with the 'process' object. I was looking at the methods and properties and noticed it had a wealth of information there. The most intriguing and I believe applicable to your problem is CPU usage. Applications that are being used need the CPU. Applications that aren't being used don't need it, or to be more accurate need very little of it. I figured you could monitor CPU usage over a period of time and if it's very low (a result of an idle application) you can kill it. So I set to work on a class that will monitor an applications processes using the principal already mentioned. It probably could use a bit of fine tuning but it works well as far as I can tell. I'd explain it but I think the comments should do most of the talking. If you have any questions, comments, or suggestions please post them. I kind of went overboard (I do that occasionally on these forums) but the topic intrigued me and I thought my solution would work. I really hope you can use it or at least the principal.
Here is the class code along with a single helper class.
'---Purpose: Monitor processes and terminate them if not in use--- 'A process is deemed idle (not in use) if it's CPU usage does not meet a certain mininum average Public Class ProcessMonitor '---DECLARATIONS--- Private WithEvents tmr As New Timer 'Timer to do the checking at set intervals Private m_NamesToMonitor As New List(Of String) 'Names of processes to monitor ie. iexplore (Internet Explorer) Private m_Processes As New Hashtable 'Data for every running process being monitored ' 'Key = Process.ID & ProcessName; Value = MonitorData Private m_Interval As Integer 'How often processes should be checked/updated (Milliseconds) Private m_KillTime As Integer 'When should a process be killed (Minutes) Private m_Threshold As Integer 'Minimum AVG. Milliseconds/minute of CPU time we consider to be active '---PROPERTIES--- '---Get or Set timers interval--- 'This interval determines how often new processes are checked for and how often we 'check if they should be killed. Public Property Interval() As Integer Get Return tmr.Interval End Get Set(ByVal value As Integer) tmr.Interval = value End Set End Property '---Get or Set the threshold time--- Public Property Threshold() As Integer Get Return m_Threshold End Get Set(ByVal value As Integer) m_Threshold = value End Set End Property '---Get or Set the time to Kill Public Property KillTime() As Integer Get Return m_KillTime End Get Set(ByVal value As Integer) If value > 0 Then m_KillTime = value End Set End Property '---Use default values--- Public Sub New() Interval = 5000 '5 second intervals KillTime = 1 'Kill after 1 minute (For testing I wanted quick) Threshold = 100 'Minimum AVG of 100 milliseconds/min of CPU time to consider active End Sub '---Adds a single process name to monitor--- Public Sub Add(ByVal processName As String) AddRange(New String() {processName}) End Sub '---Adds multiple process names to monitor--- Public Sub AddRange(ByVal processNames As String()) For Each name As String In processNames '---If we are monitoring the name already just move on--- If m_NamesToMonitor.Contains(name) Then Continue For '---Add name to list of names to be monitored--- m_NamesToMonitor.Add(name) AddProcesses(name) Next CheckMonitoring() End Sub '---Add running processes for monitoring that match the given name--- Private Sub AddProcesses(ByVal name As String) '---Loop through each process that has the given name--- For Each proc As Process In Process.GetProcessesByName(name) Dim key As String = ProcessKey(proc) '---If process is not already being monitored then add it--- If Not m_Processes.ContainsKey(key) Then m_Processes.Add(key, New MonitorData(proc)) '---Allow the process object to raise events--- proc.EnableRaisingEvents = True '---Add a handler for the Exited event so we know when a process is killed--- AddHandler proc.Exited, AddressOf ProcessExited End If Next End Sub '---Checks to see if there is a need to continue monitoring--- Public Sub CheckMonitoring() '---Stop if there are no names to monitor--- If m_NamesToMonitor.Count = 0 Then tmr.Stop() Form1.Text = "Stopped" ElseIf Not tmr.Enabled Then 'Start monitoring if we aren't tmr.Start() Form1.Text = "Running" End If End Sub '---Add any new processes that may have started--- Private Sub Refresh() For Each name As String In m_NamesToMonitor AddProcesses(name) Next End Sub '---A process was killed--- Private Sub ProcessExited(ByVal sender As Object, ByVal e As System.EventArgs) Dim proc As Process = CType(sender, Process) 'Process that was killed RemoveHandler proc.Exited, AddressOf ProcessExited 'Remove handler m_Processes.Remove(ProcessKey(proc)) 'Stop monitoring End Sub '---Returns a unique key that represents the process--- 'Format: ProcessID & ProcessName 'ID may have been sufficient but I wasn't sure Public Function ProcessKey(ByVal proc As Process) As String Return proc.Id.ToString & proc.ProcessName End Function '---The actual monitoring--- Private Sub tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tmr.Tick 'DEBUG PURPOSES ONLY Form1.ListBox1.Items.Clear() '---Check each process being monitored--- For Each data As MonitorData In m_Processes.Values '---Time elapsed since we last checked it (seconds) Dim elapsed As Integer = DateDiff(DateInterval.Second, data.LastChange, Now) 'DEBUG PURPOSES ONLY Form1.ListBox1.Items.Add(data.Proc.ProcessName & " (PID=" & data.Proc.Id & "): " & _ elapsed & " sec (AVG usage " & _ CInt(data.Proc.UserProcessorTime.Subtract(data.CPUTime).Milliseconds / elapsed * 60) & _ " ms)") '---If time elapsed has exceded our killtime then check the process for activity--- If elapsed >= KillTime * 60 Then Dim CPUTime As TimeSpan = data.Proc.UserProcessorTime Dim diff As TimeSpan = CPUTime.Subtract(data.CPUTime) '---Is the average CPU usage abover our threshold--- If CInt(diff.Milliseconds / elapsed * 60) > Threshold Then 'YES - Reset our times; the process appears active data.CPUTime = CPUTime data.LastChange = Now Else 'NO - Kill the process it does not appear to be active If Not data.Proc.HasExited Then data.Proc.Kill() End If End If Next Refresh() CheckMonitoring() End Sub End Class
Here is the code for the helper class which is required.'---Helper class--- 'Stores the the process being monitored as well as time a stamp and performance 'information so it can be monitored Public Class MonitorData Private m_lastChange As Date 'When this process was last checked Private m_CPUTime As TimeSpan 'The CPU usage the last time checked Private m_Proc As Process 'The actual process being monitored '---Constructor--- 'Accepts a single process object Public Sub New(ByVal proc As Process) m_Proc = proc Me.CPUTime = proc.UserProcessorTime LastChange = Now End Sub Public ReadOnly Property Proc() As Process Get Return m_Proc End Get End Property Public Property LastChange() As Date Get Return m_lastChange End Get Set(ByVal value As Date) m_lastChange = value End Set End Property Public Property CPUTime() As TimeSpan Get Return m_CPUTime End Get Set(ByVal value As TimeSpan) m_CPUTime = value End Set End Property End Class
Here is the code for a simple form I used to test my class'The form requires a listbox, two textboxes, and two buttons Public Class Form1 Dim monitor As New ProcessMonitor 'ProcessMonitor object 'Add name in Textbox1 for monitoring Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Add name for monitoring If TextBox1.Text.Trim <> String.Empty Then monitor.Add(TextBox1.Text.Trim) TextBox1.Clear() End If End Sub 'Get the ProcessName of the ID entered into TextBox2 Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim id As Integer If Integer.TryParse(TextBox2.Text, id) Then Try MsgBox(Process.GetProcessById(id).ProcessName) Catch ex As Exception MsgBox("ID not found") End Try End If End Sub Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load ' 'Button1 ' Me.Button1.Location = New System.Drawing.Point(160, 11) Me.Button1.Name = "Button1" Me.Button1.Size = New System.Drawing.Size(122, 20) Me.Button1.Text = "Monitor Name" ' 'TextBox1 ' Me.TextBox1.Location = New System.Drawing.Point(12, 12) Me.TextBox1.Name = "TextBox1" Me.TextBox1.Size = New System.Drawing.Size(142, 20) ' 'ListBox1 ' Me.ListBox1.Location = New System.Drawing.Point(12, 82) Me.ListBox1.Name = "ListBox1" Me.ListBox1.Size = New System.Drawing.Size(370, 121) ' 'Button2 ' Me.Button2.Location = New System.Drawing.Point(160, 55) Me.Button2.Name = "Button2" Me.Button2.Size = New System.Drawing.Size(122, 21) Me.Button2.Text = "Get ProcessName" ' 'TextBox2 ' Me.TextBox2.Location = New System.Drawing.Point(12, 55) Me.TextBox2.Name = "TextBox2" Me.TextBox2.Size = New System.Drawing.Size(142, 20) End Sub End Class
Post a reply
Quick links
Recent activity
- arif ahmad replied to How to receive data in web ...
- William Thompson replied to What is the name of the Win...
- Sameera Piyadigamage replied to Point of Sale Developers: H...
- Scott Carline replied to 4 x C# Developers for large...
- Rajendra Dhakal replied to Restore SQL Server text dat...
- cloud rainda replied to How to convert between TS f...
Enter your message below
Sign in or Join us (it's free).