Jump to content
Ascend4nt

Performance Counters in Windows - Measure Process, CPU, Network, Disk Usage

Recommended Posts

Okay.. before I go crazy and clear out space and install the O/S, do me a favor and look in your registry at these keys:

"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfOS\Performance"

"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfProc\Performance"

See if they exist and this value exists (and what it is set to):

"Disable Performance Counters"

Keys exist but values don't...

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\PerfOS]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\PerfOS\Performance]
"Close"="CloseOSObject"
"Collect"="CollectOSObjectData"
"Collect Timeout"=dword:00001f40
"Library"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\
  74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,70,\
  00,65,00,72,00,66,00,6f,00,73,00,2e,00,64,00,6c,00,6c,00,00,00
"Object List"="2 4 86 238 260 700"
"Open"="OpenOSObject"
"Open Timeout"=dword:00001388

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\PerfProc]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\PerfProc\Performance]
"Close"="CloseSysProcessObject"
"Collect"="CollectSysProcessObjectData"
"Collect Timeout"=dword:00001f40
"Library"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\
  74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,70,\
  00,65,00,72,00,66,00,70,00,72,00,6f,00,63,00,2e,00,64,00,6c,00,6c,00,00,00
"Object List"="230 232 786 740 816 1408 1500 1548 1760"
"Open"="OpenSysProcessObject"
"Open Timeout"=dword:00002710

but it would probably give UAC prompts.

UAC disabled :idea:

If you'd be so kind, and if it is a non-English version of Windows you are using, could you try replacing 'PdhAddCounterW' in the DLLCall in the '_PDH_PerformanceCounters' module with 'PdhAddEnglishCounterW'? All the other parameters should remain the same. This function is a Vista+ function, so I might have to add a @OSVersion check before this call.

You're right, i've got the German localized version of Win7-64 installed. I replaced the functions in the dllcalls, this is the result:

CPU count result:4
_PDH_GetNewQueryHandle Call succeeded, return:0,param1:0x0000000000000000,param2:0,handle:0x00000000041112F0
PdhAddEnglishCounterW success for path '\Process(*)\ID Process', handle:0x0000000004112570
PdhAddEnglishCounterW success for path '\Process(*)\Creating Process ID', handle:0x00000000041508D0
New processes detected since last call (or this is initial call)

_PDH_RemoveCounter called w/ Counter Handle (0x0000000004112570)
_PDH_RemoveCounter called w/ Counter Handle (0x00000000041508D0)
PdhCloseQuery DLL call successful
Time for _PDH_ProcessGetChildren():461.675104292745 ms
No Child Processes found for PID#2996

So, no more errors, but I would have expected a pid to the "sound" window.

Sorry to put you to work, but hey - I'll be very grateful! Thanks in advance!

I thank you for taking a look into it :)...

*edit: also, do me a favor and see what keys are under this key in your registry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib]
"Last Counter"=dword:000019f0
"Last Help"=dword:000019f1
"Base Index"=dword:00000737
"Version"=dword:00010001
"ExtCounterTestLevel"=dword:00000004
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\007]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{0fbd1ae9-8e6f-4e53-8434-676cbb70d31f}]
"InstallType"=dword:00000001
"ProviderType"=dword:00000000
"ProviderName"="TBS"
"ApplicationIdentity"=hex(2):74,00,62,00,73,00,73,00,76,00,63,00,2e,00,64,00,\
  6c,00,6c,00,00,00
.....

Share this post


Link to post
Share on other sites

Thanks KaFu for all that work. I've been doing research on alternatives myself, since I don't want to break Win2000/XP compatibility, and I believe I've come up with a solution. Unfortunately, the solution doesn't allow 'hardcoded' paths (embedded strings).

I've already added two functions to the PDH core module that allows lookup of individual values based on index or name using these two API calls:

PdhLookupPerfNameByIndex

PdhLookupPerfIndexByName

Only issue with this is Counters like '% Processor Time' will give only one value, yet its located in both the 'Process' and 'Processor' Objects. I *believe* that the Objects give unique values too, so what is needed is to pull both index #'s and then look both up and combine them into a localized Counter string. Then I can recode those extended _PDH modules to use index #'s instead of hardcoded paths.

The only foreseeable problem with this is anyone who wants to add PDH Performance Counters to their code will probably be confused at how to make it localized... I'll have to brainstorm on a good way to wrap this stuff into something 'programmer-friendly'..

Oh, and unfortunately the PdhAddEnglishCounter is only a temporary workaround - and only good for English counters, so someone programming in another language and adding counters will obviously have no use for that function.

Ahh.. and I was thinking of using that '009' key (English locale) in Perflib to pull and search strings, but the two functions above basically kill the need for that. Thanks for checking it out though :idea:

Oh, and finally - the issue of why you aren't seeing a child process for the sound window? Hmm.. I think in Win 7 the sound properties are loaded via rundll32.exe, correct? I can give you another UDF which is better suited for finding child/parent processes - OR you can simply run TestPDH_TaskManager (while both your program and the Audio window are open and stalled - maybe via a MsgBox) and check the child/parent process relationships yourself. Maybe 'control.exe' runs, shuts down, and spawns rundll32.exe? (in which case it wouldn't show up as a child)

Okay.. I think that covers all bases for now. Thanks again for your help KaFu.


Share this post


Link to post
Share on other sites

Oh, and finally - the issue of why you aren't seeing a child process for the sound window? Hmm.. I think in Win 7 the sound properties are loaded via rundll32.exe...

Oh, you're right about that, missed the logic somehow :idea:... thanks for taking a look into this m8!

#include <Winapi.au3>
#include <WindowsConstants.au3>

Global $hWnd_Sound

$iPID_Sound = Run("rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,0")

$timer_timeout = TimerInit()
While not IsHWnd($hWnd_Sound)
    Sleep(100)
    $hWnd_Sound = _Detect_Sound_dialog_hWnd($iPID_Sound)
    If TimerDiff($timer_timeout) > 5000 Then
        ExitLoop
    EndIf
WEnd

MsgBox(0, "", $iPID_Sound & @CRLF & WinGetProcess("Sound") & @CRLF & @CRLF & WinGetHandle("Sound") & @CRLF & $hWnd_Sound)
ProcessClose($iPID_Sound)

Func _Detect_Sound_dialog_hWnd($iPID)
    $hWnds = WinList("[CLASS:#32770;]", "")
    For $i = 1 To $hWnds[0][0]
        If BitAND(WinGetState($hWnds[$i][1], ''), 2) Then
            If WinGetProcess(_WinAPI_GetAncestor($hWnds[$i][1], $GA_ROOTOWNER)) = ProcessExists($iPID) Then Return $hWnds[$i][1]
        EndIf
    Next
    Return 0
EndFunc   ;==>_Detect_FF_dialog_hWnd

Share this post


Link to post
Share on other sites

UPDATES:

  • 5/18/2010: Localization issues should be fixed. New function _PDH_CounterNameToNonLocalStr() creates a special string that can be used to create counters for other languages.

    - Two support functions were added in addition to the above

    - _PDH_GetCounterInfo() now returns an array.

    - TestPDH_PerformanceCounters now provides better output on the bottom.

    * Also fixed PCRE issue with multiple parentheses.

Thanks KaFu for putting me back to work on this :idea: Hopefully this should be the last tweaks for a while, until I get my lazy arse to fixing the TaskManager 'no-refresh' GUI.

Of course, if there are any more issues, please report them.

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Hi Ascend4nt,

this is really a nice thing i could use to administrate our server\clients. I looked at the example scripts and the other au3 files and also got some infos from MSDN. The one thing i can't figure out is:

I want to get a process list from a specific remote pc. How do i get this to work? In your example 'TestPDH_TaskManager.au3' after the line 173 there you add the performance counters needed. But this is only for the local pc. I don't know how to change the string (":230\...") to call the counter on the remote pc. I don't wan't to use \\PCNAME\Process(*)\ID Process for example cause this would only run on an english OS.

I really feel kind of stupid that i can't get it. I think i don't have fully understand the localized and non-localized thingy.... :mellow:

Would be really great if i can take a look at an example counter so i can take the next steps on my own :P

Thx in advance

Sundance

PS: so i looked at the new function _PDH_CounterNameToNonLocalStr . When i add \PCNAME at the end of :230\... then this should be the right path!?

Edited by Sundance

Share this post


Link to post
Share on other sites

My apologies, the function header 'documentation' isn't very good, and I know this project needs documentation overall.

Anyway, you are correct, the localized counter would be done in this manner:

For \\PCNAME\Process(*)\ID Process, you would pass it to _PDH_CounterNameToNonLocalStr() with the first parameter as the string, and the second parameter as True (to keep the PC name as a part of the non-localized output string).

What you'd wind up with is this (for the given example):

:230\784\(*)\PCNAME

So where the format is typically \\PCNAME\Object(Instance)\CounterName, it will be changed to the numerical form representing:

:Object\Counter\(Instance)\PCNAME

Instance and PCNAME are optional, depending on the Object and whether or not its a local PC. In the case both of those are missing, it would be:

:Object\Counter\

If there's no instance but a PCNAME it would be:

:Object\Counter\\PCNAME

That 2nd backslash must be there no matter what, in order for it to be recognized correctly (anything between the 2nd and 3rd slashes is Instance - but in the above case there is none, though you must format it as if there was one). The third slash+PCNAME is needed only when its not a Counter on the local PC.

Hope that helps? You can experiment with the 'TestPDH_PerformanceCounters' program and use 'Manual Entry' to try various strings - if its formatted incorrectly, you'll get a MsgBox telling you its a bad string. I'll try to add another non-localized path string in the output in the next release so that you can just copy and paste the Non-localized counter path (including PCNAME).

*edit: 2nd backslash confusion - tried to make it more clearer

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Hiho,

many thanks for your info!

(Don't think you must apologies.) The less documentation is given the more i must dig into the code and that is not the badest thing to happen. So now i have my way to go...:P

see you

Sundance

PS: after a enough sleep this night i continued to get it done and i've just finished it :mellow:

Just needed to call:

_PDH_GetCounterList

_PDH_GetCounterValuesByPathArrays

Thats all. Its really simple when using your 'wrapper functions'

Edited by Sundance

Share this post


Link to post
Share on other sites

Wow, your skills are really amazing :mellow:

i'm just try a few things, and i was wondering if there is a way to get the cpu usage of a single process.

right now i use this:

#include <_PDH_ProcessStats.au3>

MsgBox(0,"", _GetUsage (0))

Func _GetUsage ($pid)
    _PDH_Init()
    Local $hPDHQueryHandle=_PDH_GetNewQueryHandle()
    ;   Process ID Counter Handle:  ":230\784\(*)"      [English: "\Process(*)\ID Process"]
    Local $hPDHPIDCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\784\(*)")
    ;   CPU Usage Counter Handle:   ":230\6\(*)"        [English: "\Process(*)\% Processor Time"]
    Local $hPDHCPUCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\6\(*)")
    ;   Parent Process ID Counter Handle:   ":230\1410\(*)"     [English: "\Process(*)\Creating Process ID"]
    Local $hPDHPPIDCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\1410\(*)")
    ;   Process Memory (in use) Counter Handle: ":230\180\(*)"  [English: "\Process(*)\Working Set"]
    Local $hPDHMemCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\180\(*)")
    ;   Process Elapsed Time Counter Handle:    ":230\684\(*)"  [English:"\Process(*)\Elapsed Time"]
    Local $hPDHTimeCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\684\(*)")
    Local $aProcessArray
    _PDH_ProcessStats($hPDHQueryHandle,$aProcessArray, $hPDHPIDCounterHandle,-1,$hPDHCPUCounterHandle,-1,-1,1)
    For $a = 1 To UBound($aProcessArray)-1
        If $aProcessArray[$a][1] = $pid Then
            Return $aProcessArray[$a][2]
        EndIf
    Next
    _PDH_UnInit($hPDHQueryHandle)
EndFunc

Share this post


Link to post
Share on other sites

yetrael, that's one way to do it - you'd need to search for the specific process ID/name in the array, and then report on that info.

However, I've whipped up this extra UDF today which allows a single Process Counter to be added. I'll be uploading it shortly.

*edit: Now it's uploaded, yetrael. Take a look at 'TestPDH_ProcessCounter.au3'. Change the $sProcess and $iProcessID values to be what you need, and if you like, you can change the requested counter (6, or "% Processor Time") to another Counter name/number (just remember that -2 should be removed for other Process Counters)

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

UPDATES:

6/20/2010:

- Added new module: _PDH_AddProcessCounter.au3, to make adding single Process Counters easier

- Added a test of the new module 'TestPDH_ProcessCounter.au3'. This will have to be manually edited to test other Processes other than 'autoit3.exe'

- Updated TestPDH_PerformanceCounters to now display "Non-Localized Counter Path *with* PC Name"


Share this post


Link to post
Share on other sites

Hi,

First of all, thank you very Ascendant much for providing us with this source code!

I am a very primitive programmer and I am just writing a small AutoIT script that logs memory usage to a file.

What you've written looks like it will do exactly what I intend, however it is so far beyond me that I don't even know where to begin :S

Assuming I've included the appropriate dendancies and have a file output structure set up, what would be the simpilest way to get a string return of the PID, Mem Usage and CPU Usage of a single process (identified by Process Name).

Thank you for any assistance you can provide.

Scott.

Share this post


Link to post
Share on other sites

Also - If I wanted to modify this to check the same stats on a remote PC (connected on the same LAN) what would be I need to do?

Thanks again.

Scott.

Edited by scottymiles

Share this post


Link to post
Share on other sites

scotty, Just to let you know - I haven't ignored your posts. In fact, I coded up something a day after your post that I was sure would help, but then ran into a very strange situation.

It turns out that Counters can literally 'switch' and refer to another Counter of a given Instance index #. At first I thought a problem would be reported (as an error return), but that isn't the case at all. In fact, I was lucky with my one example that CPU Usage was returning an error - but *no* other Counters reported errors, they just 'jumped' to the next Instance.

It can basically be explained like such:

With 3 instances of "autoit3.exe", the Counter will refer to them as these Instance names/indexes (.exe is stripped off internally):

autoit3 (This can also be written "autoit3#0", but it is always returned as "autoit3")

autoit3#1

autoit3#2

Note that the numbering is in sync with the order of creation, and that if another extension (not .exe) is encountered, that would be left intact (say, "executable.tmp")

Okay. So the problem here lies in the fact that if an instance closes, there will be a shift in numbering.

To clarify, let's give them some PID #'s

autoit3 = 470

autoit3#1 = 510

autoit3#2 = 640

Say we are watching PID #510 (autoit3#1), and PID # 470 (autoit3) closes. This results in the following reordering

autoit3 = 510

autoit3#1 = 640

The problem is, we were watching "autoit3#1" with PID #510, but the instance # has changed. Now "autoit3#1" refers to PID # 640, which we don't want at all! But Window's Performance Counters were designed without any thought into connecting instance #'s to 'physical' objects of any type. The instance names are just indexes into a list of *current* instances - more like 'pseudo-references'.

The same would happen if we were watching "autoit3" (PID 470), it closed, but PID #510 remained alive (same example above). We'd now have a dead process, but a still-valid counter handle (it indexes the 1st instance - 510).

So given all of this, I've been reworking my Process UDF's code to give different interface for watching Process Counters.

While using wildcard counters is the sure-fire bet for keeping things in order, using single Process Counters is something that needs a new interface - one that keeps a watch on the PID and makes certain a Counter doesn't 'stray' over to another Process 'instance'. So that's been what I've been working on - a new Process Counters interface built around a 'Process Stats' array that will keep things *fixed* onto the right instance (readjusting Counters as necessary).

Anyway, I just thought I'd explain the delay in help and let you know that things are being worked on. Using Process Counters should be *much* easier/friendlier in my next release.

HOWEVER, watching a process on another PC is a problem. Currently I use ProcessList() to sync up processes and instance #'s, which only works for the current PC. The only way to get a list of processes for another PC that I know of is through either using Wildcard counters, or through WMI (slow).

Wildcard Counters are your best bet right now - you can search through a list of processes on another PC by keeping an "ID Process" counter (PID) and search using that along with the process name (with any ".exe" stripped off the end). So you'd build that list with "\\PCNAME\Process(*)\CounterName" (where CounterName is "ID Process" or any other Counters you need). Actually, to keep it non-localized, it would look like ":230\##\(*)\PCNAME" (where ## is the index # of the Counter (for example, 784 = "ID Process")

By the way, _PDH_UpdateCounterArray() is the function that updates wildcard Counters (and returns an array). Hmm.. I guess it makes more sense to rename that function to _PDH_UpdateWildcardCounter().. going on my to-do list..

Hopefully I didn't confuse the heck out of you. As I've written in my 1st post, the project needs good documentation, and I've yet to produce that. Right now I just suggest reading through function headers and examples to try and figure it out. Basically, at its simplest, the call order is:

_PDH_Init()

_PDH_GetNewQueryHandle()

_PDH_AddCounter() ; (however many Counters/Wildcard counters needed)

_PDH_UpdateCounter() or _PDH_UpdateCounterArray() ; (however many times you need to poll them)

_PDH_FreeQueryHandle()

_PDH_UnInit()

Okay.. now let me get back to work on this beast..


Share this post


Link to post
Share on other sites

Ascendant,

Thank you very much for putting your time into this :mellow:

I have only had a brief look at the code, but knowing where to start has made this a lot clearer to me! (I don't know why I didn't do a search for "init")

As I said, I've only had a quick look and haven't tried to compile anything, but would something like this work:

Func GetProcessList($pc)
    $hPDHQueryHandle=_PDH_GetNewQueryHandle()
    $hPDHPIDCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\784\(*)\" & $pc)
    $hPDHCPUCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\6\(*)\" & $pc)
    $hPDHPPIDCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\1410\(*)\" & $pc)
    $hPDHMemCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\180\(*)\" & $pc)
    $hPDHTimeCounterHandle=_PDH_AddCounter($hPDHQueryHandle,":230\684\(*)\" & $pc)
    $aProcessArray

    _PDH_ProcessStats($hPDHQueryHandle,$aProcessArray, _
            $hPDHPIDCounterHandle,$hPDHPPIDCounterHandle,$hPDHCPUCounterHandle,$hPDHMemCounterHandle,$hPDHTimeCounterHandle,1)

    If @error Then
        Terminate("Get Process List Fail")
    EndIf

    $aProcessArray[0][0]="Process Name"
    $aProcessArray[0][1]="Process ID"
    $aProcessArray[0][2]="Parent PID"
    $aProcessArray[0][3]="CPU Usage"
    $aProcessArray[0][4]="Memory Usage"
    $aProcessArray[0][5]="Process Creation FileTime +\- 1 sec"
    $aProcessArray[0][6]="Process Creation Time +\- 1 sec"
EndFunc


Func UpdateProcessList($pc)
    _PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHPIDCounterHandle,":230\784\(*)\" & $pc)
    _PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHCPUCounterHandle,":230\6\(*)\" & $pc)
    _PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHPPIDCounterHandle,":230\1410\(*)\" & $pc)
    _PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHMemCounterHandle,":230\180\(*)\" & $pc)
    _PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHTimeCounterHandle,":230\684\(*)\" & $pc)
EndFunc


Func WriteProcessInfo()
    ;Search array for required process
    ;Write desired info to file
EndFunc

Is this the best approach? (assuming that this is even remotely correct :P)

Thank you again for all your help!

Scott.

Share this post


Link to post
Share on other sites

scotty,

Unfortunately _PDH_ProcessStats() in its current implementation is a mess and additionally only works for the local PC. I've rewritten the module (and renamed it) since, making it much easier to use (for local Processes anyway).

For networked PC's, your option right now is to do a _PDH_UpdateCounterArray() call for each Wildcard counter you collected. I've pondered on expanding that function but its difficult to create a version of this function that works unless the Object type is known beforehand and is the same for *all* Counters added (impossible things to know inside the function).

However, in your case - if you call _PDH_UpdateCounterArray() for the "ID Process" (# 784) Counter first, and locate the Process ID you are looking for, *keep* track of that row index # and for each subsequent Counter, get a new array with _PDH_UpdateCounterArray() - but with these subsequent calls, make *certain* that the 4th parameter is set to 'True'. This will keep the list in exactly the same order and size, and the only thing different would be the 2nd column will have values based on the Process Counter you are calling with (which you only need look up by the row index # you saved earlier).

I'm pondering creating a networked PC version of the new '_PDH_ProcessAll' set of UDF functions I've been working on, which would bypass ProcessList(). The only drawback to this method would be the process names would be incomplete for processes ending in '.exe'. I'll toss the idea around in my head some more though as I finish up what I'm doing.

Anyway, hopefully in the meantime you can utilize the _PDH_UpdateCounterArray() for now as I described.


Share this post


Link to post
Share on other sites

Ohhhhh... I was under the impression I was meant to use _PDH_ProcessStats() in conjunction with _PDH_UpdateCounterArray(), but this makes more sense.

A few things I've run into:

$aProcessArray=_PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHPIDCounterHandle,":230\784\(*)\" & $pc, 1)

If I pass in the true value like you say, i get a NULL reference runtime error: The instruction at "0x64002baa" referenced memory at "0x00000004". The memory could not be "read".

The debugging the exe gives me the line: 74002BAA mov ecx,dword ptr [eax+4]

However, if I run the code as:

$aProcessArray=_PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHPIDCounterHandle,":230\784\(*)", 1)

It will compile and run fine, returning the stats of the local PC processes.

Is ":230\784\(*)\" & $pc in the wrong syntax or am I doing something else wrong?

Also for note:

$aProcessArray=_PDH_UpdateCounterArray($hPDHQueryHandle,$hPDHPIDCounterHandle,":230\784\(*)\" & $pc)

This (without the true value) compiles and runs fine, however still returns the local stats. By the way, I have tried suplimenting $pc with both PC name and IP and always get the same results.

Thanks for your help.

Scott.

Share this post


Link to post
Share on other sites

That runtime error is VERY odd. I don't see anything that would cause a crash like that (though you may want to make sure you are compiling using v3.3.6+ of AutoIT). As to the script code..

When you concatenate a non-localized string with a PC-name suffix using "& $pc" , the PC-name should not have the '\\' prefix. So for '\\SOMEPC" it should be appended as just "SOMEPC" to that non-localized string, giving ":230\784\(*)\SOMEPC". Also very important is that if you are looking at the local PC, you should use the format ":230\784\(*)" with no ending backslash.

The third parameter to _PDH_UpdateCounterArray() is optional and shouldn't give any problems whatever it's set to. (However I do recommend setting it to -2 when collecting CPU stats).

*edit: The most *important* part of the code you should be checking is _PDH_AddCounter() - the path there should have the correct path as stated above. It doesn't matter what path you give to _PDH_UpdateCounterArray().

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Finally got it all working perfect! My problem was that I didn't need to pass the path into _PDH_UpdateCounterArray(). Once I took that out it started working great!

Thank you so much for your help Ascendant! You're the best!

Your code has been extremely useful and is working very efficiently!

Thank you again!!!!

Scott.

Share this post


Link to post
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

  • Similar Content

    • By jresine
      Hello, is it possible to know via a script or command, to have the percentage of disk usage of a process? thank you in advance.
      ps: see image

    • By Raywando
      Hello,
      This is my first post. So I’ve worked on a script for a while and I’m planning to publish it but the problem is that it connects to an FTP server at some point, and as you probably know FTP credentials are easily captured by a MITM attack or Wireshark (not sure if Wireshark does). So I thought if i can detect data capturing in the user’s network the script would stop. Any idea?.
      If there’s another workaround I’m happy to hear it. 
    • By Miliardsto
      I want to detect if exact process or window uses directx or opengl or maybe something else library used in applications.
      Thats becouse there could be many windows with same names and different names and the same with process. I got so much process names I want to my script works with all, so i want standardize.
      All of this processes uses DirectX or OpenGL so then If I check this window/process uses these libraries I will be sure thats the right process
    • By TryWare90Days
      I'm trying to kill a malware process, that I can't remove with my www.sophus.com/hom antivirus.

      The malware is known as coinminer,config and my Sophus only creates popups of blocking the malware.

      I know that the malware is constantly launching a svchost *32.exe processes, where the svchost.exe processes are from my Windows 7 operating system.
      I have with no luck tried to do this:
      Global $_bStatus = False
      While $_bStatus = False
                 Global $_iPid
                 Global $_sActiveTitleNew = "svchost *32.exe"
                 $_iPid = WinGetProcess($_sActiveTitleNew)
                 If $_iPid <> -1 Then $_bStatus = ProcessClose($_iPid)   
      Wend
      EXIT
       
      But the $_iPid doesn't ever show anything else than  -1, even if I can see the svchost *32.exe process in my TaskManager
       
      YES - I know I shouldn't EXIT after killing the first malware detection, but it is easier to explain the above for you, so I can get a solution.
    • By JoeWagner
      I'm building a tool to remotely monitor CPU usage on my server.
      I have a working tool but I have a few issues I'd like some help with.
      1. The app uses more system memory on a continual growth rate...  It eventually starts displaying strange artifacts and the background flashes between black and and white behind the GDI+ elements.  I determined this couldn't be left to run for any amount of time (greater than 15-20 minutes) - Very frustrating.
      I suspect it's because it keeps drawing new GDI+ elements to replace the previous cycle ... the $bar1 = "" is enough to remove the image and allow the new image to be drawn there, but I don't have a handle for the original GDI+ element to throw it away... Not sure where they go...
      I also suspect there could be a better way to do what I'm doing here, but from a problem solving perspective - this is what I came up with - I will accept suggestions for how better to accomplish the same / better or acceptable results  
      I will not however accept corrections on grammar, punctuation or commenting - I didn't comment this as I was going, I use the variables that make sense to me (or as they were when I lifted them from the scraps I found on the internet) and you can never be too careful with punctuation.
      2. I have a WMI query that is used to remotely pull the CPU data from the server - if I supply the wrong credentials the app crashes... I tried to make it show an error and go back to allow me to try again ... doesn't work. Any help with catching that error and preventing the crash would be super helpful. (works great if the credentials are correct; domain or local)
       
      The whole thing below... 
      #include <Date.au3> #include <WindowsConstants.au3> #include <GuiConstantsEX.au3> #include <EditConstants.au3> #include <ButtonConstants.au3> #include <GDIPlus.au3> Global $__g_hGDIPDll Global $graph[21] Global $timer, $timeout = 500 Global $hFlag = 0 $timer = TimerInit() $main = GUICreate("CPU Graph", 125, 220, Default, Default, Default, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) $bar1 = GUICtrlCreatePic("", 10, 10, 5, 100) $bar2 = GUICtrlCreatePic("", 15, 10, 5, 100) $bar3 = GUICtrlCreatePic("", 20, 10, 5, 100) $bar4 = GUICtrlCreatePic("", 25, 10, 5, 100) $bar5 = GUICtrlCreatePic("", 30, 10, 5, 100) $bar6 = GUICtrlCreatePic("", 35, 10, 5, 100) $bar7 = GUICtrlCreatePic("", 40, 10, 5, 100) $bar8 = GUICtrlCreatePic("", 45, 10, 5, 100) $bar9 = GUICtrlCreatePic("", 50, 10, 5, 100) $bar10 = GUICtrlCreatePic("", 55, 10, 5, 100) $bar11 = GUICtrlCreatePic("", 60, 10, 5, 100) $bar12 = GUICtrlCreatePic("", 65, 10, 5, 100) $bar13 = GUICtrlCreatePic("", 70, 10, 5, 100) $bar14 = GUICtrlCreatePic("", 75, 10, 5, 100) $bar15 = GUICtrlCreatePic("", 80, 10, 5, 100) $bar16 = GUICtrlCreatePic("", 85, 10, 5, 100) $bar17 = GUICtrlCreatePic("", 90, 10, 5, 100) $bar18 = GUICtrlCreatePic("", 95, 10, 5, 100) $bar19 = GUICtrlCreatePic("", 100, 10, 5, 100) $bar20 = GUICtrlCreatePic("", 105, 10, 5, 100) $host = GUICtrlCreateInput("Host", 10, 115, 100, 20, $ES_AUTOHSCROLL) $user = GUICtrlCreateInput("User", 10, 140, 100, 20, $ES_AUTOHSCROLL) GUICtrlSetFont(-1, 8, 400) $pass = GUICtrlCreateInput("Pass", 10, 165, 100, 20, BitOR($ES_PASSWORD,$ES_AUTOHSCROLL)) GUICtrlSetFont(-1, 8, 400) $start = GUICtrlCreateButton("Start", 10, 190, 100, 20, $BS_DEFPUSHBUTTON) GUISetState() While 1 $msg = GUIGetMsg() If $msg = $GUI_EVENT_CLOSE Then ExitLoop If $msg = $start Then ConnectWMI() If $hFlag = 1 Then If TimerDiff($timer) > $timeout Then UpdateGraph() EndIf WEnd Func ConnectWMI() Global $hostname = GUICtrlRead($host) If Ping($hostname, 2000) = 0 Then Msgbox(0, "Error", "Unable to reach specified host") Return 0 EndIf Local $usr = GUICtrlRead($user) Local $pwd = GUICtrlRead($pass) Global $objSWbemLocator = ObjCreate("WbemScripting.SWbemLocator") Global $objWMIService = $objSWbemLocator.ConnectServer($hostname, "root\cimv2", $usr, $pwd) If @error Then Msgbox(0, "Error", "Unable to connect to the Host with the supplied credentials") Return 0 EndIf $hFlag = 1 UpdateGraph() EndFunc Func UpdateGraph() $usage = _Processor_Usage() For $i = 1 to 19 $graph[$i] = $graph[$i+1] Next $graph[20] = $usage GUICtrlSetImage($bar1, "") CreateBar($bar1, $graph[1]) GUICtrlSetImage($bar2, "") CreateBar($bar2, $graph[2]) GUICtrlSetImage($bar3, "") CreateBar($bar3, $graph[3]) GUICtrlSetImage($bar4, "") CreateBar($bar4, $graph[4]) GUICtrlSetImage($bar5, "") CreateBar($bar5, $graph[5]) GUICtrlSetImage($bar6, "") CreateBar($bar6, $graph[6]) GUICtrlSetImage($bar7, "") CreateBar($bar7, $graph[7]) GUICtrlSetImage($bar8, "") CreateBar($bar8, $graph[8]) GUICtrlSetImage($bar9, "") CreateBar($bar9, $graph[9]) GUICtrlSetImage($bar10, "") CreateBar($bar10, $graph[10]) GUICtrlSetImage($bar11, "") CreateBar($bar11, $graph[11]) GUICtrlSetImage($bar12, "") CreateBar($bar12, $graph[12]) GUICtrlSetImage($bar13, "") CreateBar($bar13, $graph[13]) GUICtrlSetImage($bar14, "") CreateBar($bar14, $graph[14]) GUICtrlSetImage($bar15, "") CreateBar($bar15, $graph[15]) GUICtrlSetImage($bar16, "") CreateBar($bar16, $graph[16]) GUICtrlSetImage($bar17, "") CreateBar($bar17, $graph[17]) GUICtrlSetImage($bar18, "") CreateBar($bar18, $graph[18]) GUICtrlSetImage($bar19, "") CreateBar($bar19, $graph[19]) GUICtrlSetImage($bar20, "") CreateBar($bar20, $graph[20]) $timer = TimerInit() EndFunc Func _Processor_Usage() Dim $Col_Items = $objWMIService.ExecQuery('SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor', 'WQL') Local $Obj_Item For $Obj_Item In $Col_Items Return $Obj_Item.PercentProcessorTime Next EndFunc Func CreateBar($target, $value) Local $width=5, $height=2 _GDIPlus_Startup() $hImage = DLL_BitmapCreate($width, $height*50) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage) _GDIPlus_GraphicsSetSmoothingMode($hGraphic, 2) ;100 If $value > 98 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF00F2F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 0, $width, $height, $hBrush) EndIf ;98 If $value > 96 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF0182C") _GDIPlus_GraphicsFillRect($hGraphic, 0, 2, $width, $height, $hBrush) EndIf ;96 If $value > 94 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF0212A") _GDIPlus_GraphicsFillRect($hGraphic, 0, 4, $width, $height, $hBrush) EndIf ;94 If $value > 92 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF02B28") _GDIPlus_GraphicsFillRect($hGraphic, 0, 6, $width, $height, $hBrush) EndIf ;92 If $value > 90 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF03426") _GDIPlus_GraphicsFillRect($hGraphic, 0, 8, $width, $height, $hBrush) EndIf ;90 If $value > 88 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF03E24") _GDIPlus_GraphicsFillRect($hGraphic, 0, 10, $width, $height, $hBrush) EndIf ;88 If $value > 86 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF04722") _GDIPlus_GraphicsFillRect($hGraphic, 0, 12, $width, $height, $hBrush) EndIf ;86 If $value > 84 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF05120") _GDIPlus_GraphicsFillRect($hGraphic, 0, 14, $width, $height, $hBrush) EndIf ;84 If $value > 82 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF05A1D") _GDIPlus_GraphicsFillRect($hGraphic, 0, 16, $width, $height, $hBrush) EndIf ;82 If $value > 80 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF0641B") _GDIPlus_GraphicsFillRect($hGraphic, 0, 18, $width, $height, $hBrush) EndIf ;80 If $value > 78 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF06D19") _GDIPlus_GraphicsFillRect($hGraphic, 0, 20, $width, $height, $hBrush) EndIf ;78 If $value > 76 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF07717") _GDIPlus_GraphicsFillRect($hGraphic, 0, 22, $width, $height, $hBrush) EndIf ;76 If $value > 74 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF08015") _GDIPlus_GraphicsFillRect($hGraphic, 0, 24, $width, $height, $hBrush) EndIf ;74 If $value > 72 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF08A13") _GDIPlus_GraphicsFillRect($hGraphic, 0, 26, $width, $height, $hBrush) EndIf ;72 If $value > 70 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF09311") _GDIPlus_GraphicsFillRect($hGraphic, 0, 28, $width, $height, $hBrush) EndIf ;70 If $value > 68 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF09311") _GDIPlus_GraphicsFillRect($hGraphic, 0, 30, $width, $height, $hBrush) EndIf ;68 If $value > 66 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFF09D0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 32, $width, $height, $hBrush) EndIf ;66 If $value > 64 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFECA20F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 34, $width, $height, $hBrush) EndIf ;64 If $value > 62 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFE8A80F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 36, $width, $height, $hBrush) EndIf ;62 If $value > 60 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFE5AD0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 38, $width, $height, $hBrush) EndIf ;60 If $value > 58 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFE1B30F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 40, $width, $height, $hBrush) EndIf ;58 If $value > 56 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFDEB80F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 42, $width, $height, $hBrush) EndIf ;56 If $value > 54 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFDABE0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 44, $width, $height, $hBrush) EndIf ;54 If $value > 52 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFD6C30F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 46, $width, $height, $hBrush) EndIf ;52 If $value > 50 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFCFCE0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 48, $width, $height, $hBrush) EndIf ;50 If $value > 48 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFCCD40F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 50, $width, $height, $hBrush) EndIf ;48 If $value > 46 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFC8D90F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 52, $width, $height, $hBrush) EndIf ;46 If $value > 44 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFC4DF0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 54, $width, $height, $hBrush) EndIf ;44 If $value > 42 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFC1E40F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 56, $width, $height, $hBrush) EndIf ;42 If $value > 40 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFBDEA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 58, $width, $height, $hBrush) EndIf ;40 If $value > 38 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFBAF00F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 60, $width, $height, $hBrush) EndIf ;38 If $value > 36 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFBAF00F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 62, $width, $height, $hBrush) EndIf ;36 If $value > 34 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFADEF0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 64, $width, $height, $hBrush) EndIf ;34 If $value > 32 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFFA1EE0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 66, $width, $height, $hBrush) EndIf ;32 If $value > 30 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF94ED0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 68, $width, $height, $hBrush) EndIf ;30 If $value > 28 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF88ED0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 70, $width, $height, $hBrush) EndIf ;28 If $value > 26 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF7CEC0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 72, $width, $height, $hBrush) EndIf ;26 If $value > 24 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF6FEB0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 74, $width, $height, $hBrush) EndIf ;24 If $value > 22 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF63EA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 76, $width, $height, $hBrush) EndIf ;22 If $value > 20 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF56EA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 78, $width, $height, $hBrush) EndIf ;20 If $value > 18 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF56EA0F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 80, $width, $height, $hBrush) EndIf ;18 If $value > 16 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF4AE90F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 82, $width, $height, $hBrush) EndIf ;16 If $value > 14 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF3EE80F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 84, $width, $height, $hBrush) EndIf ;14 If $value > 12 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF31E70F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 86, $width, $height, $hBrush) EndIf ;12 If $value > 10 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF25E70F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 88, $width, $height, $hBrush) EndIf ;10 If $value > 8 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF18E60F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 90, $width, $height, $hBrush) EndIf ;8 If $value > 6 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF0CE50F") _GDIPlus_GraphicsFillRect($hGraphic, 0, 92, $width, $height, $hBrush) EndIf ;6 If $value > 4 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF00E510") _GDIPlus_GraphicsFillRect($hGraphic, 0, 94, $width, $height, $hBrush) EndIf ;4 If $value > 2 Then $hBrush = _GDIPlus_BrushCreateSolid("0xFF00E509") _GDIPlus_GraphicsFillRect($hGraphic, 0, 96, $width, $height, $hBrush) EndIf ;2 $hBrush = _GDIPlus_BrushCreateSolid("0xFF00E509") _GDIPlus_GraphicsFillRect($hGraphic, 0, 98, $width, $height, $hBrush) $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage) GUICtrlSendMsg($target, 0x172, 0, $hBitmap) _WinAPI_DeleteObject($hBitmap) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() EndFunc ;==>_CreateBar Func DLL_BitmapCreate($width, $height) Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $width, "int", $height, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0) Return $aResult[6] EndFunc ;==>DLL_BitmapCreate  
       
×
×
  • Create New...