Jump to content

_ProcessListProperties()


PsaltyDS
 Share

Recommended Posts

I tried adding this after the For/Next loop for "; Get PerfProc data" in the original:

; Get PerfProc data
        For $oProc In $colProcs
        ; ...
        Next

    ; Release Refresher object
        $oRefresher.DeleteAll
        $oRefresher = 0
        $colProcs = 0
Still had the memory leak. ;)

I moved the creation of $oWMI to a Global variable where it is only created once - and there was still a memory leak. :lmao:

Then I moved the creation of $oRefresher outside the loop to a Global - the leak went away. :D

This does not show the memory leak:

#include <Array.au3>; Only for _ArrayDisplay()

; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process
; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros
Global $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & @ComputerName & "\root\cimv2")
Global $oRefresher = ObjCreate("WbemScripting.SWbemRefresher")
Global $colRefProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet
$oRefresher.Refresh

HotKeySet("{ESC}", "_Quit")

; Loop to watch for memory leak
While 1
    _ProcessListProperties()
    Sleep(20)
WEnd

Func _Quit()
    Exit
EndFunc  ;==>_Quit

;===============================================================================
; Function Name:    _ProcessListProperties()
; Description:   Get various properties of a process, or all processes
; Call With:       _ProcessListProperties( [$Process [, $sComputer]] )
; Parameter(s):  (optional) $Process - PID or name of a process, default is "" (all)
;          (optional) $sComputer - remote computer to get list from, default is local
; Requirement(s):   AutoIt v3.2.4.9+
; Return Value(s):  On Success - Returns a 2D array of processes, as in ProcessList()
;            with additional columns added:
;            [0][0] - Number of processes listed (can be 0 if no matches found)
;            [1][0] - 1st process name
;            [1][1] - 1st process PID
;            [1][2] - 1st process Parent PID
;            [1][3] - 1st process owner
;            [1][4] - 1st process priority (0 = low, 31 = high)
;            [1][5] - 1st process executable path
;            [1][6] - 1st process CPU usage
;            [1][7] - 1st process memory usage
;            [1][8] - 1st process creation date/time = "MM/DD/YYY hh:mm:ss" (hh = 00 to 23)
;            [1][9] - 1st process command line string
;            ...
;            [n][0] thru [n][9] - last process properties
; On Failure:      Returns array with [0][0] = 0 and sets @Error to non-zero (see code below)
; Author(s):        PsaltyDS at http://www.autoitscript.com/forum
; Date/Version:   07/02/2008  --  v2.0.2
; Notes:            If an integer PID or string process name is provided and no match is found,
;            then [0][0] = 0 and @error = 0 (not treated as an error, same as ProcessList)
;          This function requires admin permissions to the target computer.
;          All properties come from the Win32_Process class in WMI.
;            To get time-base properties (CPU and Memory usage), a 100ms SWbemRefresher is used.
;===============================================================================
Func _ProcessListProperties($Process = "", $sComputer = ".")
    Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate
    Local $avProcs[1][2] = [[0, ""]], $n = 1

; Convert PID if passed as string
    If StringIsInt($Process) Then $Process = Int($Process)

; Connect to WMI and get process objects
; $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & $sComputer & "\root\cimv2")
    If IsObj($oWMI) Then
    ; Get collection processes from Win32_Process
        If $Process = "" Then
        ; Get all
            $colProcs = $oWMI.ExecQuery("select * from win32_process")
        ElseIf IsInt($Process) Then
        ; Get by PID
            $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process)
        Else
        ; Get by Name
            $colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'")
        EndIf

        If IsObj($colProcs) Then
        ; Return for no matches
            If $colProcs.count = 0 Then Return $avProcs

        ; Size the array
            ReDim $avProcs[$colProcs.count + 1][10]
            $avProcs[0][0] = UBound($avProcs) - 1

        ; For each process...
            For $oProc In $colProcs
            ; [n][0] = Process name
                $avProcs[$n][0] = $oProc.name
            ; [n][1] = Process PID
                $avProcs[$n][1] = $oProc.ProcessId
            ; [n][2] = Parent PID
                $avProcs[$n][2] = $oProc.ParentProcessId
            ; [n][3] = Owner
                If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName
            ; [n][4] = Priority
                $avProcs[$n][4] = $oProc.Priority
            ; [n][5] = Executable path
                $avProcs[$n][5] = $oProc.ExecutablePath
            ; [n][8] = Creation date/time
                $dtmDate = $oProc.CreationDate
                If $dtmDate <> "" Then
                ; Back referencing RegExp pattern from weaponx
                    Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)"
                    $dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6")
                EndIf
                $avProcs[$n][8] = $dtmDate
            ; [n][9] = Command line string
                $avProcs[$n][9] = $oProc.CommandLine

            ; increment index
                $n += 1
            Next
        Else
            SetError(2); Error getting process collection from WMI
        EndIf
    ; release the collection object
        $colProcs = 0

        $oRefresher.Refresh

    ; Get PerfProc data
        For $oProc In $colRefProcs
        ; Find it in the array
            For $n = 1 To $avProcs[0][0]
                If $avProcs[$n][1] = $oProc.IDProcess Then
                ; [n][6] = CPU usage
                    $avProcs[$n][6] = $oProc.PercentProcessorTime
                ; [n][7] = memory usage
                    $avProcs[$n][7] = $oProc.WorkingSet
                    ExitLoop
                EndIf
            Next
        Next
    Else
        SetError(1); Error connecting to WMI
    EndIf

; Return array
    Return $avProcs
EndFunc  ;==>_ProcessListProperties

So, if you have to repeat the function in a tight loop, this code might help - but it doesn't explain why the $oRefresher Swbemrefresher object leaks so bad in a loop.

;)

 

 

Is above bold information still valid? Then I moved the creation of $oRefresher outside the loop to a Global - the leak went away

Because I put it on the tight loop and face the same problem.

If by create the $oRefresher outside the loop to a global solve the problem, I'm going to code it that way

Link to comment
Share on other sites

Also I found this occasionary cause an error:

If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "" & $sUserName
If $oProc.GetOwner($sUserName, $sUserDomain) ^ ERROR

Since I dont know how to solve it and I dont use that information, I comment that line

Link to comment
Share on other sites

Also I found this occasionary cause an error:

If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "" & $sUserName

If $oProc.GetOwner($sUserName, $sUserDomain) ^ ERROR

Since I dont know how to solve it and I dont use that information, I comment that line

I did get that  same error as you reported but just hung till you pressed ESC. I noticed that it did not output the process list so I some code from the original post and integrated the last posted code change for testing. See if it works for you.

#include <Array.au3>; Only for _ArrayDisplay()
; Author: PsaltyDS - _ProcessListProperties
; Status: Demo

; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process
; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros
Global $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & @ComputerName & "\root\cimv2")
Global $oRefresher = ObjCreate("WbemScripting.SWbemRefresher")
Global $colRefProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet
$oRefresher.Refresh

; Globals - Install a custom error handler - added
Global $oMyError = ObjEvent("AutoIt.Error","MyErrFunc"), $f_COMError = False
Global $avRET, $iPID

HotKeySet("{ESC}", "_Quit")

; Loop to watch for memory leak
While 1
    _ProcessListProperties()
   $avRET = _ProcessListProperties() ; added
   _ArrayDisplay($avRET, "All Processes") ; added
    Sleep(20)
WEnd

Func _Quit()
    Exit
EndFunc  ;==>_Quit

;===============================================================================
; Function Name:    _ProcessListProperties()
; Description:   Get various properties of a process, or all processes
; Call With:       _ProcessListProperties( [$Process [, $sComputer]] )
; Parameter(s):  (optional) $Process - PID or name of a process, default is "" (all)
;          (optional) $sComputer - remote computer to get list from, default is local
; Requirement(s):   AutoIt v3.2.4.9+
; Return Value(s):  On Success - Returns a 2D array of processes, as in ProcessList()
;            with additional columns added:
;            [0][0] - Number of processes listed (can be 0 if no matches found)
;            [1][0] - 1st process name
;            [1][1] - 1st process PID
;            [1][2] - 1st process Parent PID
;            [1][3] - 1st process owner
;            [1][4] - 1st process priority (0 = low, 31 = high)
;            [1][5] - 1st process executable path
;            [1][6] - 1st process CPU usage
;            [1][7] - 1st process memory usage
;            [1][8] - 1st process creation date/time = "MM/DD/YYY hh:mm:ss" (hh = 00 to 23)
;            [1][9] - 1st process command line string
;            ...
;            [n][0] thru [n][9] - last process properties
; On Failure:      Returns array with [0][0] = 0 and sets @Error to non-zero (see code below)
; Author(s):        PsaltyDS at http://www.autoitscript.com/forum
; Date/Version:   07/02/2008  --  v2.0.2
; Notes:            If an integer PID or string process name is provided and no match is found,
;            then [0][0] = 0 and @error = 0 (not treated as an error, same as ProcessList)
;          This function requires admin permissions to the target computer.
;          All properties come from the Win32_Process class in WMI.
;            To get time-base properties (CPU and Memory usage), a 100ms SWbemRefresher is used.
;===============================================================================
Func _ProcessListProperties($Process = "", $sComputer = ".")
    Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate
    Local $avProcs[1][2] = [[0, ""]], $n = 1

; Convert PID if passed as string
    If StringIsInt($Process) Then $Process = Int($Process)

; Connect to WMI and get process objects
; $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & $sComputer & "\root\cimv2")
    If IsObj($oWMI) Then
    ; Get collection processes from Win32_Process
        If $Process = "" Then
        ; Get all
            $colProcs = $oWMI.ExecQuery("select * from win32_process")
        ElseIf IsInt($Process) Then
        ; Get by PID
            $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process)
        Else
        ; Get by Name
            $colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'")
        EndIf

        If IsObj($colProcs) Then
        ; Return for no matches
            If $colProcs.count = 0 Then Return $avProcs

        ; Size the array
            ReDim $avProcs[$colProcs.count + 1][10]
            $avProcs[0][0] = UBound($avProcs) - 1

        ; For each process...
            For $oProc In $colProcs
            ; [n][0] = Process name
                $avProcs[$n][0] = $oProc.name
            ; [n][1] = Process PID
                $avProcs[$n][1] = $oProc.ProcessId
            ; [n][2] = Parent PID
                $avProcs[$n][2] = $oProc.ParentProcessId
            ; [n][3] = Owner
                If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName
            ; [n][4] = Priority
                $avProcs[$n][4] = $oProc.Priority
            ; [n][5] = Executable path
                $avProcs[$n][5] = $oProc.ExecutablePath
            ; [n][8] = Creation date/time
                $dtmDate = $oProc.CreationDate
                If $dtmDate <> "" Then
                ; Back referencing RegExp pattern from weaponx
                    Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)"
                    $dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6")
                EndIf
                $avProcs[$n][8] = $dtmDate
            ; [n][9] = Command line string
                $avProcs[$n][9] = $oProc.CommandLine

            ; increment index
                $n += 1
            Next
        Else
            SetError(2); Error getting process collection from WMI
        EndIf
    ; release the collection object
        $colProcs = 0

        $oRefresher.Refresh

    ; Get PerfProc data
        For $oProc In $colRefProcs
        ; Find it in the array
            For $n = 1 To $avProcs[0][0]
                If $avProcs[$n][1] = $oProc.IDProcess Then
                ; [n][6] = CPU usage
                    $avProcs[$n][6] = $oProc.PercentProcessorTime
                ; [n][7] = memory usage
                    $avProcs[$n][7] = $oProc.WorkingSet
                    ExitLoop
                EndIf
            Next
        Next
    Else
        SetError(1); Error connecting to WMI
    EndIf

; Return array
    Return $avProcs
EndFunc  ;==>_ProcessListProperties
Link to comment
Share on other sites

  • 1 year later...

for some monitoring tasks i'm using WMI with a SWbemRefresher.

on most of my system it's working fine. however, i have a few where it fails on the following line:

$colItems = $oRefresher.AddEnum($objWMIService, "Win32_PerfFormattedData_PerfProc_Process").ObjectSet

any idea how to find out why exactly it's failing?

could be system local specific or whatever who knows.

any suggestions how to troubleshoot?

  thanks in advance, francoiste


working code below ...

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_UseUpx=Y
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_Run_Tidy=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#pragma compile(ExecLevel, highestAvailable)


;# see http://msdn.microsoft.com/en-us/library/windows/desktop/aa394597%28v=VS.85%29.aspx  ("WMI Tasks: Performance Monitoring")
Local $strComputer = "."
Local $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\cimv2")
If @error Or (Not IsObj($objWMIService)) Then
  MsgBox(4096 + 48, "Error 1", "Error creating wmi object for localhost")
  Exit 1
EndIf

Local $colItems = 0
Local $oRefresher = 0

;# get collection of all processes from Win32_PerfFormattedData_PerfProc_Process
;# we must use an SWbemRefresher to pull the collection, or all Perf data will be zeros
;# refresher info: http://msdn.microsoft.com/en-us/library/windows/desktop/aa393026%28v=vs.85%29.aspx
$oRefresher = ObjCreate("WbemScripting.SWbemRefresher")
If @error Or (Not IsObj($oRefresher)) Then
  MsgBox(4096 + 48, "Error 3a", "error creating wmi refresher object" & @CRLF & @error)
  Exit 1
EndIf

$colItems = $oRefresher.AddEnum($objWMIService, "Win32_PerfFormattedData_PerfProc_Process").ObjectSet
If @error Or (Not IsObj($colItems)) Then
  MsgBox(4096 + 48, "Error 3b", "error adding wmi enum to refresher object" & @CRLF & @error) ;# <--- this is where it fails
  Exit 1
EndIf

$oRefresher.Refresh
If (@error == 1) Or (Not IsObj($colItems)) Then
  MsgBox(4096 + 48, "Error 4a", "error refreshing wmi perfdata object" & @CRLF & @error)
  Exit 1
Else
  If ($colItems.count <= 0) Then
    MsgBox(4096 + 48, "Error 4b", "WMI refresher query did not find the process.")
    Exit 1
  EndIf
EndIf

;# time delay before calling the refresher
Local $iTime = TimerInit()
Do
  Sleep(50)
Until TimerDiff($iTime) > 200

$oRefresher.Refresh

MsgBox(4096 + 48, "Done", "Completed successfully.")


;# additional code below ...

side note:

when i run the original author's code (with custom error handler) it is showing the following error message regarding COM error 80020009:

 

wmi.png

Edited by francoiste
Link to comment
Share on other sites

  • 2 weeks later...

please ignore my previous question on COM error 80020009.

i have answered my own question (as to what might be wrong and how to troubleshoot):
it turned out that on this particular system my performance counter registry was corrupt!
i was also getting errors when running "perfmon.msc".

eventually i solved it by following the steps in https://support.microsoft.com/en-us/kb/2554336 :

  • open an elevated command prompt
  • CD /D C:\windows\system32
  • lodctr.exe /R
  • CD /D C:\windows\sysWOW64
  • lodctr.exe /R
  • WINMGMT.EXE /RESYNCPERF
  • <reboot>

 

Edited by francoiste
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...