Hi, All,

I am instructed to develop a console application which monitors a process. It is now done but the problem is when I'm running it the CPU usage increases up to 100%, kindly check below code for some enhancement:

Console App:

Sub Main()
   While True
       System.Threading.Thread.Sleep(1000)
       If IsProcessExist() = False Then Exit While 
   End While
End Sub

Private Function IsProcessExist() As Boolean
   IsProcessExist = False
   Dim psList() As Process
   psList = Process.GetProcessesByName("pnavigator")
   For Each p As Process In psList
      If p.Id = CDbl(cid) Then
          IsProcessExist = True
          If p.MainWindowTitle.ToUpper.StartsWith("IDLE") Then
             IsProcessExist = False
          End If
          Exit For
      End If
   Next p
End Function

Thanks in advance.

Edited 1 Year Ago by renzlo: fix grammar

For starters, the program won't compile because of

If p.Id = CDbl(cid) Then

The variable cid is not defined.

Edited 1 Year Ago by Reverend Jim

Hi, Jim,

Sorry for posting incomplete codes, here's the full code:

Imports System.IO
Imports System.Threading
Imports System.Text
Imports System.Net.Sockets
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions

Module Module1
    Private ArgCommand As String()
    Private LogWatcher As FileSystemWatcher
    Private CurrentTrace As FileInfo
    Private LocalTracePath As String = "C:\Temp"
    Private LocalTraceFilePath As String = ""
    Private JavaDeploymentPath As String = String.Concat(Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), "\LocalLow\Sun\Java\Deployment")
    Private ctask As String
    Private cuser As String
    Private cid As String
    Private cpath As String
    Private cfile As String
    Private freeram As FreeMemory
    Private oldTotalImages As Integer = 0
    Private oldTotalCodingTimes As Decimal = 0
    Private rng As Random = New Random
    Private cprocess As String

#Region "Windows API"
    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    End Function
    Declare Sub mouse_event Lib "user32" Alias "mouse_event" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
#End Region

    Sub Main()
        ArgCommand = Environment.GetCommandLineArgs
        cprocess = ArgCommand(0)
        cpath = ArgCommand(1)
        cid = ArgCommand(2)
        cuser = ArgCommand(3)
        ctask = ArgCommand(4)
        cfile = Path.GetFileName(cpath)
        Console.Title = cid
        LocalTraceFilePath = String.Concat(LocalTracePath & "\", GetCodingDate.Year, "\", GetCodingDate.ToString("yyyy-MM-dd"), "\", GetUserShift, "\", cuser, "\", ctask, "\PLUGIN", cid, rand, ".trace")
        StartLogWatcher(Path.GetDirectoryName(cpath), "*.trace")
        freeram = New FreeMemory
        While True
            System.Threading.Thread.Sleep(1000)
            freeram.FlushMemory()
            If IsProcessExist() = False Then
                LogWatcher.EnableRaisingEvents = False
                InsertToDB()
                freeram.Dispose()
                Exit While
            End If
        End While
    End Sub

#Region "LogWatcher"
    Private Sub StartLogWatcher(ByVal pat As String, ByVal extension As String)
        LogWatcher = New FileSystemWatcher
        LogWatcher.Path = pat
        LogWatcher.Filter = extension
        AddHandler LogWatcher.Changed, AddressOf LogChange
        LogWatcher.EnableRaisingEvents = True
    End Sub

    Private Sub LogChange(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
        If e.ChangeType = WatcherChangeTypes.Changed Then
            If cfile.ToUpper = e.Name.ToUpper Then
                My.Computer.FileSystem.CopyFile(cpath, LocalTraceFilePath, True)
            End If
        End If
    End Sub
#End Region

    Private Sub InsertToDB()
        Dim TotalImages As Integer = 0
        Dim TotalCodingTimes As Decimal = 0
        Dim CodingAverage As Double = 0
        TotalImages = CountCodedImages(LocalTraceFilePath)
        If TotalImages = 0 Then Return
        TotalCodingTimes = CalcCodingTimes(LocalTraceFilePath)
        CodingAverage = TotalCodingTimes / TotalImages
        If oldTotalImages = TotalImages Then Return
        SendMessageToStartMenu(String.Concat("mixed|", cid, "|", ctask, "|", cuser, "|", GetCodingDate.ToString("MM-dd-yyyy"), "|", Path.GetFileName(LocalTraceFilePath), "|", TotalImages, "|", Math.Round(CodingAverage, 0)), "PostNL Navigator")
        oldTotalImages = TotalImages
        oldTotalCodingTimes = TotalCodingTimes
        TransferLogs()
    End Sub

    Private Function CountCodedImages(ByVal cntPath As String) As Integer
        'count coded images
        Dim basa As New StreamReader(cntPath)
        Dim counter As Integer = 0
        While Not basa.EndOfStream
            Dim linya As String = basa.ReadLine
            If linya.Contains("Coding the image:") Then
                counter += 1
            End If
        End While
        basa.Dispose() : basa.Close()
        Return counter
    End Function

    Private Function CalcCodingTimes(ByVal cntpath As String) As Decimal
        'calculate coding times
        Dim basa As New StreamReader(cntpath)
        Dim counter As Double = 0
        Dim cal As Double
        While Not basa.EndOfStream
            Dim linya As String = basa.ReadLine
            If linya.Contains("Coding the image:") Then
                cal = New Double
                cal = CDbl(Trim(linya.Substring(linya.Length - 16)).Replace("msec.", ""))
                If cal.ToString.Length < 6 Then counter += cal
            End If
        End While
        basa.Dispose() : basa.Close()
        Return CDec(counter)
    End Function

    Private Function IsProcessExist() As Boolean
        IsProcessExist = False
        Dim psList() As Process
        psList = Process.GetProcessesByName("pnavigator")
        For Each p As Process In psList
            If p.Id = CDbl(cid) Then
                IsProcessExist = True
                If p.MainWindowTitle.ToUpper.StartsWith("IDLE") Then
                    IsProcessExist = False
                End If
                Exit For
            End If
        Next p
        freeram = New FreeMemory
        freeram.FlushMemory()
    End Function

    Public Function GetCodingDate() As Date
        Dim Codingdate As Date = Nothing
        Dim LagunaTime As Date = System.TimeZoneInfo.ConvertTime(DateAndTime.Now, TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"))
        If IsInDST() = False Then
            Select Case LagunaTime.Hour
                Case 0 To 5
                    Codingdate = DateAndTime.Now.AddDays(-1)
                Case 6 To 12, 13 To 23
                    Codingdate = DateAndTime.Now
            End Select
        Else
            Select Case LagunaTime.Hour
                Case 0 To 6
                    Codingdate = DateAndTime.Now.AddDays(-1)
                Case 7 To 13, 14 To 23
                    Codingdate = DateAndTime.Now
            End Select
        End If
        Return Codingdate
    End Function

    Public Function GetUserShift() As String
        Dim UserShift As String = ""
        Dim LagunaTime As Date = System.TimeZoneInfo.ConvertTime(DateAndTime.Now, TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"))
        If IsInDST() = False Then
            Select Case LagunaTime.Hour
                Case 0 To 5, 21 To 23
                    UserShift = "SHIFT 3"
                Case 6 To 12
                    UserShift = "SHIFT 1"
                Case 13 To 20
                    UserShift = "SHIFT 2"
            End Select
        Else
            Select Case LagunaTime.Hour
                Case 0 To 6, 22 To 23
                    UserShift = "SHIFT 3"
                Case 7 To 13
                    UserShift = "SHIFT 1"
                Case 14 To 21
                    UserShift = "SHIFT 2"
            End Select
        End If
        Return UserShift
    End Function

    Private Function IsInDST() As Boolean
        IsInDST = False
        Dim lagunatz As TimeZoneInfo
        Dim standardtime As Date
        Dim lagunatime As Date
        lagunatz = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time")
        lagunatime = TimeZoneInfo.ConvertTime(DateTime.Now, lagunatz)
        standardtime = lagunatime.AddHours(6)
        Dim postnltz As TimeZoneInfo
        Dim postnltime As Date
        postnltz = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time")
        postnltime = TimeZoneInfo.ConvertTime(lagunatime, postnltz)
        If standardtime.Hour = postnltime.Hour Then
            IsInDST = False
        Else
            IsInDST = True
        End If
    End Function

    Private Sub TransferLogs()
        Dim JavaLogStoragePath As String = String.Concat(My.Settings.JavaStorageLogPath)
        Dim EncDecFile As New EncryptDecrypt
        Dim javaKey As Byte() = EncDecFile.CreateKey("renz@5685647")
        Dim javaIV As Byte() = EncDecFile.CreateIV("renz@5685647")
        Dim OriginalFile As New FileInfo(LocalTraceFilePath)
        Dim EncryptedFile As String = String.Concat(OriginalFile.FullName.Replace(".", "_"), ".enc")
        EncDecFile.EncryptOrDecryptFile(OriginalFile.FullName, EncryptedFile, javaKey, javaIV, EncryptDecrypt.CryptoAction.ActionEncrypt)
        My.Computer.FileSystem.CopyFile(EncryptedFile, EncryptedFile.Replace(LocalTracePath, JavaLogStoragePath), True)
    End Sub

    Public Function rand() As String
        Dim sb As New StringBuilder
        ' Selection of pure numbers sequence or mixed one
        Dim pureNumbers = rng.Next(1, 11)
        If pureNumbers < 7 Then
            ' Generate a sequence of only digits
            Dim number As Integer = rng.Next(1, 1000000)
            Dim digits As String = number.ToString("000000")
            For i As Integer = 1 To 6
                Dim idx As Integer = rng.Next(0, digits.Length)
                sb.Append(digits.Substring(idx, 1))
            Next
        Else
            ' Generate a sequence of digits and letters 
            Dim s As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
            For i As Integer = 1 To 6
                Dim idx As Integer = rng.Next(0, 36)
                sb.Append(s.Substring(idx, 1))
            Next
        End If
        Return sb.ToString()
    End Function

    Private Function GetIPv4Address() As String
        GetIPv4Address = String.Empty
        Dim strHostName As String = System.Net.Dns.GetHostName()
        Dim iphe As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(strHostName)
        For Each ipheal As System.Net.IPAddress In iphe.AddressList
            If ipheal.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork Then
                GetIPv4Address = ipheal.ToString()
            End If
        Next
    End Function

#Region "SendWindowsMessage"
    Private WithEvents BS As New BuildString
    Private Sub SendMessageToStartMenu(ByVal emsg As String, ByVal wndname As String)
        Dim hwnd As Integer = FindWindow(vbNullString, wndname)
        If hwnd <> 0 And emsg <> "" Then
            BS.PostString(hwnd, &H400, 0, emsg)
        End If
    End Sub

#End Region
End Module

I want to try running this locally but I am getting

Type 'FreeMemory' us not defined
Type 'EncryptDecrypt' is not defined
Type 'BuildString' is not defined

What version of vb.net are you using?

What are the command line arguments for running it? Also, it seems like an awful lot of code just to monitor a process.

Edited 1 Year Ago by Reverend Jim

Yes it is. Can i just revise my question? Since i cant give you the arguments because it is on a restricted online video coding. I just want to monitor a process, check if its main window title contains an "idle" word if running. How can i do that without too much CPU usage?

For that sort of stuff I use AutoIt. It's free and very scriptable. For example

set aut = CreateObject("AutoItX3.Control")

aut.AutoItSetOption "WinTitleMatchMode",2

while True

    if aut.WinExists("TextPad") Then
    wscript.echo "textpad is open"
    end if

    wscript.Sleep 1000

wend

After you install AutoIt, copy the above and save it into WatchTextPad.vbs. The do the following, once from the command line

cscript //h:cscript //nologo //s

That makes cscript.exe the default engine. That way, writes (wscript.echo) go to the console window. Otherwise, vbs scripts get run by wscript.exe and writes get sent to a messagebox popup.

aut.AutoItSetOption "WinTitleMatchMode",2

says that when you are checking window titles, check for the given string anywhere in the title (there is a very good help file detailing all this). The rest of the script should be obvious.

If you want to do the same without using AutoIt you can still do it with vbScript by

do

    titles = GetTitles()
    if Contains(titles,"TextPad") Then
        wscript.Echo now, "TextPad is active"
    end if

    wscript.Sleep 1000

loop

Function GetTitles ()

    Dim cmd:  cmd = "tasklist /v /fi ""WINDOWTITLE ne N/A"" /fo list"
    Dim tasks: tasks  = Split(CreateObject("WScript.Shell").Exec(cmd).StdOut.ReadAll(), vbCrLf)

    GetTitles = Filter(tasks, "Window Title:")

End Function

Function Contains (titles, string)

    Dim title

    Contains = False

    for each title in titles
        title = Trim(Split(title, ":")(1))
        if instr(title, string) > 0 Then
            Contains = True
            Exit Function
        end if
    next

End Function

although executing TASKLIST is much less efficient than using AutoIt and it involves a lot more coding.

Edited 1 Year Ago by Reverend Jim

I used to do quite a lot of work in vbScript (great for admin stuff and even a lot of unattended applications) so let me know if you need anything.

This question has already been answered. Start a new discussion instead.