Jump to content

[SOLVED] Performance Data Helper Bug


Recommended Posts

Hi, for the life of me I can't seem to get the below code to work, aside from giving me a list of PDH Query Path Objects. The PDHQueryHandle returned by the 'PdhOpenQueryW' function returns fine, but as soon as I try to *use* the handle, it gives me the error code that the handle is invalid! WTH?

Can someone verify the same behavior for me? Or point out a stupid mistake I may have made?

Thanks!

Ascend4nt

P.S. MSDN Link: Using the PDH Functions to Consume Counter Data

*EDIT: Oops, in my rush to copy and paste, I forgot one crucial line ($sCounterPath)

*EDIT2: Fix found (thx Manko) - though source is not updated. A UDF will be released hopefully soon incorporating the fixes (see DLLOpen/Close recommendation), as well as including actual functionality!

#include <Array.au3>
Local $sCounterPath="\Process(*)\% Processor Time"
Local $hPDHQueryHandle
; PdhOpenQuery: Create a PDH Query Handle
Local $aRet=DllCall("pdh.dll","long","PdhOpenQueryW","ptr",0,"dword*",0,"ptr*",$hPDHQueryHandle)
; Error?
If @error Or Not IsArray($aRet) Or $aRet[0] Then Exit

; DEBUG: Return info
ConsoleWrite("1st PDH Call succeeded, return:" &$aRet[0]&",param1:"&$aRet[1]&",param2:"&$aRet[2]&",handle:" & $aRet[3] & @CRLF)
; Copy handle
$hPDHQueryHandle=$aRet[3]

Local $iBufSize
; 1st call - get buffer size
$aRet=DllCall("pdh.dll","long","PdhExpandWildCardPathW","ptr",ChrW(0),"wstr",$sCounterPath,"ptr",ChrW(0),"dword*",$iBufSize,"dword",0)

; Return should be PDH_MORE_DATA (0x800007D2)
If @error Or Not IsArray($aRet) Or $aRet[0]<>0x800007D2 Then
    ; Close PDH Query Handle
    DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
    Exit
EndIf

; Get required buffer size
$iBufSize=$aRet[4]
; DEBUG
ConsoleWrite("BufSize required:" & $iBufSize & @CRLF)
; Setup a buffer (ubytes because pulling a multi-NULL-terminated Unicode string out is impossible with wchars)
Local $stExpandedPathList=DllStructCreate("ubyte["&($iBufSize*2)&']')
; 2nd call - fill buffer with expanded PDH Paths
$aRet=DllCall("pdh.dll","long","PdhExpandWildCardPathW","ptr",ChrW(0),"wstr",$sCounterPath, _
    "ptr",DllStructGetPtr($stExpandedPathList),"dword*",$iBufSize,"dword",0)
; Error?
If @error Or Not IsArray($aRet) Or $aRet[0] Then
    ; Close PDH Query Handle
    DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
    Exit
EndIf
; DEBUG INFO
ConsoleWrite("Call successful, Bufsize=" & $aRet[4]&", Expanded Path List w\ len:" & _
    StringLen(BinaryToString(DllStructGetData($stExpandedPathList,1),2))&@CRLF&"Contents:" & @CRLF)

; GET UNICODE STRING, SPLIT BY NULL-TERMS INTO ARRAY
Local $ahPDHCounterHandle,$aPDHProcessList=StringSplit(BinaryToString(DllStructGetData($stExpandedPathList,1),2),ChrW(0),1)
; Now to go through and add them one by one to the PDH Query Handle
If IsArray($aPDHProcessList) Then
    ; Last split is probably at the double-NULL term, so remove the last element and decrease count
    If $aPDHProcessList[$aPDHProcessList[0]]=="" Then
        ReDim $aPDHProcessList[$aPDHProcessList[0]]
        $aPDHProcessList[0]-=1
    EndIf
    ; DEBUG: Show PDH Process List (as split)
    _ArrayDisplay($aPDHProcessList,"PDH Process List")
    ; Set size of Counter Handles to the same size as the PDH Process List
    Dim $ahPDHCounterHandle[$aPDHProcessList[0]+1]
    ; Equalize Bottom element (count)
    $ahPDHCounterHandle[0]=$aPDHProcessList[0]
    ; Iterate through array
    For $i=1 to $aPDHProcessList[0]
        ; DEBUG
        ConsoleWrite("Handle (" &$hPDHQueryHandle&") Adding:" &$aPDHProcessList[$i] & @CRLF)
        
        ; DEBUG CALL - Validate Path. Works! Argh
        ;$aRet=DllCall("pdh.dll","long","PdhValidatePathW","wstr",$aPDHProcessList[$i])
        ;If IsArray($aRet) And Not $aRet[0] Then ConsoleWrite("Path validated!" & @CRLF)
        
        ; ADD COUNTER CALL - CONSISTENT ERRORS! ARGH.
        ;   (err code is INVALID HANDLE)
        $aRet=DllCall("pdh.dll","long","PdhAddCounterW","ptr",$hPDHQueryHandle,"wstr",$aPDHProcessList[$i],"dword*",$i,"ptr*",$ahPDHCounterHandle[$i])
        If @error Or Not IsArray($aRet) Or $aRet[0] Then
            ; Return code C0000BBC = INVALID HANDLE. WHY?!?!
            
            ; Technically this could throw an error since $aRet might not be an array.. but here for DEBUG info
            ConsoleWrite("Ret:" & Hex($aRet[0]) & @CRLF)
            ; Close PDH Query Handle
            $aRet=DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
            ; Technically not a good idea since $aRet might not be an array.. but here for DEBUG info
            ConsoleWrite("Ret:" & Hex($aRet[0]) & @CRLF)
            Exit
        EndIf
    Next
EndIf
; Close PDH Query Handle
DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
Edited by ascendant
Link to comment
Share on other sites

Hi, for the life of me I can't seem to get the below code to work, aside from giving me a list of PDH Query Path Objects. The PDHQueryHandle returned by the 'PdhOpenQueryW' function returns fine, but as soon as I try to *use* the handle, it gives me the error code that the handle is invalid! WTH?

Can someone verify the same behavior for me? Or point out a stupid mistake I may have made?

Thanks!

Ascend4nt

P.S. MSDN Link: Using the PDH Functions to Consume Counter Data

#include <Array.au3>

Local $hPDHQueryHandle
; PdhOpenQuery: Create a PDH Query Handle
Local $aRet=DllCall("pdh.dll","long","PdhOpenQueryW","ptr",0,"dword*",0,"ptr*",$hPDHQueryHandle)
; Error?
If @error Or Not IsArray($aRet) Or $aRet[0] Then Exit

; DEBUG: Return info
ConsoleWrite("1st PDH Call succeeded, return:" &$aRet[0]&",param1:"&$aRet[1]&",param2:"&$aRet[2]&",handle:" & $aRet[3] & @CRLF)
; Copy handle
$hPDHQueryHandle=$aRet[3]

Local $iBufSize
; 1st call - get buffer size
$aRet=DllCall("pdh.dll","long","PdhExpandWildCardPathW","ptr",ChrW(0),"wstr",$sCounterPath,"ptr",ChrW(0),"dword*",$iBufSize,"dword",0)

; Return should be PDH_MORE_DATA (0x800007D2)
If @error Or Not IsArray($aRet) Or $aRet[0]<>0x800007D2 Then
    ; Close PDH Query Handle
    DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
    Exit
EndIf

; Get required buffer size
$iBufSize=$aRet[4]
; DEBUG
ConsoleWrite("BufSize required:" & $iBufSize & @CRLF)
; Setup a buffer (ubytes because pulling a multi-NULL-terminated Unicode string out is impossible with wchars)
Local $stExpandedPathList=DllStructCreate("ubyte["&($iBufSize*2)&']')
; 2nd call - fill buffer with expanded PDH Paths
$aRet=DllCall("pdh.dll","long","PdhExpandWildCardPathW","ptr",ChrW(0),"wstr",$sCounterPath, _
    "ptr",DllStructGetPtr($stExpandedPathList),"dword*",$iBufSize,"dword",0)
; Error?
If @error Or Not IsArray($aRet) Or $aRet[0] Then
    ; Close PDH Query Handle
    DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
    Exit
EndIf
; DEBUG INFO
ConsoleWrite("Call successful, Bufsize=" & $aRet[4]&", Expanded Path List w\ len:" & _
    StringLen(BinaryToString(DllStructGetData($stExpandedPathList,1),2))&@CRLF&"Contents:" & @CRLF)

; GET UNICODE STRING, SPLIT BY NULL-TERMS INTO ARRAY
Local $ahPDHCounterHandle,$aPDHProcessList=StringSplit(BinaryToString(DllStructGetData($stExpandedPathList,1),2),ChrW(0),1)
; Now to go through and add them one by one to the PDH Query Handle
If IsArray($aPDHProcessList) Then
    ; Last split is probably at the double-NULL term, so remove the last element and decrease count
    If $aPDHProcessList[$aPDHProcessList[0]]=="" Then
        ReDim $aPDHProcessList[$aPDHProcessList[0]]
        $aPDHProcessList[0]-=1
    EndIf
    ; DEBUG: Show PDH Process List (as split)
    _ArrayDisplay($aPDHProcessList,"PDH Process List")
    ; Set size of Counter Handles to the same size as the PDH Process List
    Dim $ahPDHCounterHandle[$aPDHProcessList[0]+1]
    ; Equalize Bottom element (count)
    $ahPDHCounterHandle[0]=$aPDHProcessList[0]
    ; Iterate through array
    For $i=1 to $aPDHProcessList[0]
        ; DEBUG
        ConsoleWrite("Handle (" &$hPDHQueryHandle&") Adding:" &$aPDHProcessList[$i] & @CRLF)
        
        ; DEBUG CALL - Validate Path. Works! Argh
        ;$aRet=DllCall("pdh.dll","long","PdhValidatePathW","wstr",$aPDHProcessList[$i])
        ;If IsArray($aRet) And Not $aRet[0] Then ConsoleWrite("Path validated!" & @CRLF)
        
        ; ADD COUNTER CALL - CONSISTENT ERRORS! ARGH.
        ;   (err code is INVALID HANDLE)
        $aRet=DllCall("pdh.dll","long","PdhAddCounterW","ptr",$hPDHQueryHandle,"wstr",$aPDHProcessList[$i],"dword*",$i,"ptr*",$ahPDHCounterHandle[$i])
        If @error Or Not IsArray($aRet) Or $aRet[0] Then
            ; Return code C0000BBC = INVALID HANDLE. WHY?!?!
            
            ; Technically this could throw an error since $aRet might not be an array.. but here for DEBUG info
            ConsoleWrite("Ret:" & Hex($aRet[0]) & @CRLF)
            ; Close PDH Query Handle
            $aRet=DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
            ; Technically not a good idea since $aRet might not be an array.. but here for DEBUG info
            ConsoleWrite("Ret:" & Hex($aRet[0]) & @CRLF)
            Exit
        EndIf
    Next
EndIf
; Close PDH Query Handle
DllCall("pdh.dll","long","PdhCloseQuery","ptr",$hPDHQueryHandle)
Should PdhExpandWildCardPathW be PdhExpandWildCardPathH? Edited by martin
Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

Should PdhExpandWildCardPathW be PdhExpandWildCardPathH?

No, that would be used for log files. Anyway, the handle isn't used for that function, and works fine as it is (see the results in _ArrayDisplay()).

Thanks for trying though :P

Link to comment
Share on other sites

No, that would be used for log files. Anyway, the handle isn't used for that function, and works fine as it is (see the results in _ArrayDisplay()).

Thanks for trying though :P

Ok.

I didn't see the output of _ArrayDisplay because the code you posted doesn't run, so I was just guessing.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

martin, sorry about that! - I screwed up and forgot one line (Local $sCounterPath="\Process(*)\% Processor Time"). I added it to the 1st post. It should run now - but you'll see by the console messages/comments what's the matter

thx

Link to comment
Share on other sites

Hi!

Dll get's loaded and unloaded at every call, maybe it's as sugested in below URL, handle becomes invalid if you don't keep dll loaded?

http://www.autohotkey.com/forum/topic17831.html - It just had to be autohotkey?! :unsure:

Now I get "C0000BB9" on the add counter thingy... 0xC0000BB9 (PDH_CSTATUS_NO_COUNTER) The specified counter could not be found.

and "00000000" on the closequerything. Progress! Status ok, I guess. :P

/Manko [EDIT: Tried myself...]

Edited by Manko
Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...
Link to comment
Share on other sites

Manko, I knew you were the man!! Wow, how about that.. I never even thought about the handle becoming invalid by not explicitly loading the DLL.

With the DLLOpen/Close, the function works now - so far :unsure:

Now to see what I can get this puppy to do.. :P

*edit: hmm.. don't know why you're seeing the errors, I haven't now that I use the DLL handle.. but I'll work on the code and release it when I've made it actually do something useful

Edited by ascendant
Link to comment
Share on other sites

Manko, I knew you were the man!! Wow, how about that.. I never even thought about the handle becoming invalid by not explicitly loading the DLL.

With the DLLOpen/Close, the function works now - so far :D

Now to see what I can get this puppy to do.. :P

*edit: hmm.. don't know why you're seeing the errors, I haven't now that I use the DLL handle.. but I'll work on the code and release it when I've made it actually do something useful

GreAT!!

(Dont forget to rename this thread as solved.) :unsure:

/Manko

Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...
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...