Hi all,
i'm trying to code using pdh.dll, and i have a problem with this structure:
typedef struct _PDH_COUNTER_PATH_ELEMENTS {
LPTSTR szMachineName;
LPTSTR szObjectName;
LPTSTR szInstanceName;
LPTSTR szParentInstance;
DWORD dwInstanceIndex;
LPTSTR szCounterName;
} PDH_COUNTER_PATH_ELEMENTS,
*PPDH_COUNTER_PATH_ELEMENTS;
This is my asm version:
PDH_COUNTER_PATH_ELEMENTS STRUCT
szMachineName DWORD ?
szObjectName DWORD ?
szInstanceName DWORD ?
szParentInstance DWORD ?
dwInstanceIndex DWORD ?
szCounterName DWORD ?
PDH_COUNTER_PATH_ELEMENTS ENDS
When i use it, i get "error reading from memory". What is *PPDH_COUNTER_PATH_ELEMENTS standing for? I guess this is the reason for my problem..
BTW, i need this to retrieve CPU-Load in my app; everything works fine with my localized counter path, but i want to get them by index (PdhLookupPerfNameByIndex) and build correct localized strings in any language with PdhMakeCounterPath.
Thank you in advance! phoenix
Quote from: Phoenix on March 19, 2005, 11:55:03 PM
What is *PPDH_COUNTER_PATH_ELEMENTS standing for?
Hi Phoenix,
maybe I'm telling you no news, but anyway...
"*PPDH_COUNTER_PATH_ELEMENTS" is the type of a pointer pointing to a structure of type "PDH_COUNTER_PATH_ELEMENTS".
PPDH_COUNTER_PATH_ELEMENTS ptr;
is the same as
PDH_COUNTER_PATH_ELEMENTS *ptr;
I don't know where your problem is so please post some code and we can have a look.
Thank you, mnemonic. Here is the code:
ComputerNameDnsFullyQualified EQU 0003h
.DATA?
szComName DB MAX_COMPUTERNAME_LENGTH+1 DUP (?)
szObjName DB MAX_PATH DUP (?)
szCntName DB MAX_PATH DUP (?)
szCntPath DB PDH_MAX_COUNTER_PATH DUP (?)
.DATA
cbBData DWORD PDH_MAX_COUNTER_PATH
dwNumB DWORD MAX_COMPUTERNAME_LENGTH+1
dwNameBufS DWORD MAX_PATH
hQuery DWORD 0
hCounter DWORD 0
hEvent DWORD 0
lpThreadId DWORD 0
szFCPath DB "\Prozessor(0)\Prozessorzeit (%)",0
szFCPathE DB "\Processor(0)\% Processor Time",0
.CODE
_InitPdhCounter PROC
Local hKey:DWORD
Local pcpe:PDH_COUNTER_PATH_ELEMENTS
;Local pos
;-- Determine if at least Win NT 4.0 is installed
mov osEX.dwOSVersionInfoSize,sizeof(OSVERSIONINFO)
invoke GetVersionEx,ADDR osEX
.if (osEX.dwPlatformId < 2) || (osEX.dwMajorVersion < 3)
xor eax,eax
not eax
jmp _exit
.endif
;-- RETRIEVE THE LOCALIZED LANGUAGE STRING
;-- Create a PDH Query
Invoke PdhOpenQuery,0,0,ADDR hQuery
;*******************************************************************************
;-- Retrieve computer name - ok.
Invoke GetComputerNameEx,ComputerNameDnsFullyQualified,ADDR szComName,ADDR dwNumB
;-- Retrieve localized string by index: "Processor" - ok.
Invoke PdhLookupPerfNameByIndex, ADDR szComName,238,ADDR szObjName, ADDR dwNameBufS
;-- Retrieve localized string by index: "% Processor Time" - ok.
Invoke PdhLookupPerfNameByIndex, ADDR szComName,6,ADDR szCntName, ADDR dwNameBufS
;-- store the pointers in PDH_COUNTER_PATH_ELEMENTS struct
lea edx,szComName
mov pcpe.szMachineName,edx
lea edx,szObjName
mov pcpe.szObjectName,edx
mov pcpe.szInstanceName,NULL
mov pcpe.szParentInstance,NULL
mov pcpe.dwInstanceIndex,0
lea edx,szCntName
mov pcpe.szCounterName,edx
;-- This does not work, returns:
; PDH_INVALID_ARGUMENT - A required argument is missing or incorrect.
Invoke PdhMakeCounterPath,ADDR pcpe,ADDR szCntPath,ADDR cbBData,0
;-- If i try this, i get "error reading from memory": - but i use a valid path !
invoke PdhParseCounterPath,ADDR szFCPath,ADDR pcpe,ADDR cbBData,0
;*******************************************************************************
;-- Add a counter to the query for the counterPath specified (using valid (german) path - ok.
Invoke PdhAddCounter,hQuery,ADDR szFCPath,0,ADDR hCounter
invoke PdhParseCounterPath,ADDR szFCPath,ADDR pcpe,ADDR cbBData,0
Invoke CreateEvent,NULL,FALSE,FALSE,NULL
mov hEvent,eax
;-- Create threadproc
mov ecx,OFFSET ThreadProc
invoke CreateThread,NULL,NULL,ecx,NULL,0,ADDR lpThreadId
;-- Start collecting data with 1 sec interval
Invoke PdhCollectQueryDataEx,hQuery,1,hEvent
xor eax,eax
_exit:
RET
_InitPdhCounter EndP
There must be a problem with the PDH_COUNTER_PATH_ELEMENTS-structure, when i add some more bytes to the structure, the "error reading from memory" disappeares when i call PdhParseCounterPath-function, but, however, the PDH_INVALID_ARGUMENT remains for PdhMakeCounterPath. I have searched MSDN and googled a lot, but i did find no solution, so thank you for your help!
Strange, I can't figure out what's wrong with your code...
I googled a bit too and found some examples (http://www.codeproject.com/threads/getprocesstimes.asp?select=799612&df=100&forumid=15846&exp=0). I can't do much since you posted only a snippet of your code which I can't build to a running program.
I would suggest you play around a bit with the values passed to the function. There is a suggestion to set dwInstanceIndex to -1. I think it's some kind of voodoo :bg
The structure realy seems to be correct.
Maybe one of the more experienced coders here has a look at your prob and will help you out with the magic solution.
Sometimes it's just a matter of experience.
I found the source of one of the errors, and another related problem, but the call to PdhParseCounterPath is still not working. I am out of time to work on it so I am posting what I have.
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\pdh.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\pdh.lib
includelib \masm32\lib\msvcrt.lib
include \masm32\macros\macros.asm
PDH_COUNTER_PATH_ELEMENTS STRUCT
szMachineName DWORD ?
szObjectName DWORD ?
szInstanceName DWORD ?
szParentInstance DWORD ?
dwInstanceIndex DWORD ?
szCounterName DWORD ?
PDH_COUNTER_PATH_ELEMENTS ENDS
ComputerNameDnsFullyQualified EQU 0003h
PDH_MAX_COUNTER_PATH EQU 2048
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
cbBData DD PDH_MAX_COUNTER_PATH
dwNumB DD MAX_COMPUTERNAME_LENGTH+1
dwNameBufS DD MAX_PATH
hQuery DD 0
hCounter DD 0
hEvent DD 0
lpThreadId DD 0
szFCPath DB "\Prozessor(0)\Prozessorzeit (%)",0
szFCPathE DB "\Processor(0)\% Processor Time",0
.data?
szComName DB MAX_COMPUTERNAME_LENGTH+1 DUP (?)
szObjName DB MAX_PATH DUP (?)
szCntName DB MAX_PATH DUP (?)
szCntPath DB PDH_MAX_COUNTER_PATH DUP (?)
.code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
call _InitPdhCounter
invoke printf,chr$(13,10,"Press any key to exit...")
@@:
call _kbhit
test eax, eax
jz @B
exit
_InitPdhCounter PROC
Local hKey:DWORD
Local pcpe:PDH_COUNTER_PATH_ELEMENTS
;*** ALLOW EXTRA SPACE
LOCAL pad[1000]:DWORD
;Local pos
;-- Determine if at least Win NT 4.0 is installed
;mov osEX.dwOSVersionInfoSize,sizeof(OSVERSIONINFO)
;invoke GetVersionEx,ADDR osEX
;.if (osEX.dwPlatformId < 2) || (osEX.dwMajorVersion < 3)
; xor eax,eax
; not eax
; jmp _exit
;.endif
;-- RETRIEVE THE LOCALIZED LANGUAGE STRING
;-- Create a PDH Query
Invoke PdhOpenQuery,0,0,ADDR hQuery
print chr$(13,10,"hQuery:")
print uhex$(hQuery)
;*******************************************************************************
;-- Retrieve computer name - ok.
Invoke GetComputerNameEx,ComputerNameDnsFullyQualified,ADDR szComName,ADDR dwNumB
print chr$(13,10,"szComName:")
print ADDR szComName
;-- Retrieve localized string by index: "Processor" - ok.
Invoke PdhLookupPerfNameByIndex, ADDR szComName,238,ADDR szObjName, ADDR dwNameBufS
print chr$(13,10,"szObjName:")
print ADDR szObjName
; *** PROBLEM HERE WITH CHANGE IN BUFFER SIZE VARIABLE ***
print chr$(13,10,"dwNameBufS:")
print ustr$(dwNameBufS)
mov dwNameBufS,MAX_PATH
;-- Retrieve localized string by index: "% Processor Time" - ok.
Invoke PdhLookupPerfNameByIndex, ADDR szComName,6,ADDR szCntName, ADDR dwNameBufS
print chr$(13,10,"szCntName:")
print ADDR szCntName
;-- store the pointers in PDH_COUNTER_PATH_ELEMENTS struct
lea edx,szComName
;mov pcpe.szMachineName,edx
mov pcpe.szMachineName,NULL
lea edx,szObjName
mov pcpe.szObjectName,edx
;mov pcpe.szInstanceName,NULL
mov pcpe.szInstanceName,chr$("_Total")
mov pcpe.szParentInstance,NULL
mov pcpe.dwInstanceIndex,0
lea edx,szCntName
mov pcpe.szCounterName,edx
print chr$(13,10,"cbBData:")
print ustr$(cbBData)
;-- This does not work, returns:
; PDH_INVALID_ARGUMENT - A required argument is missing or incorrect.
Invoke PdhMakeCounterPath,ADDR pcpe,ADDR szCntPath,ADDR cbBData,0
print chr$(13,10,"szCntPath:")
print ADDR szCntPath
; *** PROBLEM HERE WITH CHANGE IN BUFFER SIZE VARIABLE ***
print chr$(13,10,"cbBData:")
print ustr$(cbBData)
;mov cbBData,PDH_MAX_COUNTER_PATH
; *** SET SO FUNCTION WILL RETURN BUFFER SIZE REQUIRED ***
mov cbBData,0
;-- If i try this, i get "error reading from memory": - but i use a valid path !
invoke PdhParseCounterPath,ADDR szFCPath,ADDR pcpe,ADDR cbBData,0
;invoke PdhParseCounterPath,ADDR szCntPath,ADDR pcpe,ADDR cbBData,0
print chr$(13,10,"buffer required:")
print ustr$(cbBData)
;*******************************************************************************
RET ; *** THIS STILL NOT WORKING ***
; *** PROBLEM MAY BE IN PDH_COUNTER_PATH_ELEMENTS STRUCTURE ***
invoke PdhParseCounterPath,ADDR szFCPath,ADDR pcpe,ADDR cbBData,0
print ustr$(eax)
RET
;-- Add a counter to the query for the counterPath specified (using valid (german) path - ok.
Invoke PdhAddCounter,hQuery,ADDR szFCPath,0,ADDR hCounter
invoke PdhParseCounterPath,ADDR szFCPath,ADDR pcpe,ADDR cbBData,0
Invoke CreateEvent,NULL,FALSE,FALSE,NULL
mov hEvent,eax
;-- Create threadproc
;mov ecx,OFFSET ThreadProc
;invoke CreateThread,NULL,NULL,ecx,NULL,0,ADDR lpThreadId
;-- Start collecting data with 1 sec interval
Invoke PdhCollectQueryDataEx,hQuery,1,hEvent
xor eax,eax
;_exit:
RET
_InitPdhCounter EndP
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
MichaelW, you solved my problem!! Thank you!
; *** PROBLEM HERE WITH CHANGE IN BUFFER SIZE VARIABLE ***
print chr$(13,10,"dwNameBufS:")
print ustr$(dwNameBufS)
mov dwNameBufS,MAX_PATH
I really should have noticed that..... ::)
But the major problem was
mov pcpe.szInstanceName,chr$("_Total")
for pdhMakeCounterPath. I have spent hours to find the problem...
The pdhParseCounterPath is still only working on my machine when i change the structure as follows:
PDH_COUNTER_PATH_ELEMENTS STRUCT
szMachineName DWORD ?
szObjectName DWORD ?
szInstanceName DWORD ?
szParentInstance DWORD ?
dwInstanceIndex DWORD ?
szCounterName DWORD ?
szFillBytes BYTE PDH_MAX_COUNTER_PATH DUP (?)
PDH_COUNTER_PATH_ELEMENTS ENDS
so there may be a bug within the PdhParseCounterPath function, i can't see any other reason..
Again, thak you very much!!
Is the structure a "header" structure? A header structure omits the variable data section, to avoid HLL complications. The header is immediately followed by a data area that will be used for data you supply, or for data supplied by some API.
tenkey,
this is the solution. The
PdhParseCounterPath function needs additional space to store the strings.
from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/pdhparsecounterpath.asp:
QuoteThe buffer space allocated for this should be large enough for the structure and the strings that will be referenced by the members in this structure.
We have to determine the size of the additional buffer first:
mov dwBufferSize,0
Invoke PdhParseCounterPath,ADDR szCntPath,ADDR pcpe,ADDR dwBufferSize,0
The required additional size is returned in dwBufferSize. After allocating memory of required size (dwBufferSize + SIFEOF(PDH_COUNTER_PATH_ELEMENTS) we can call this function again, with no problems....
Sometimes reading MSDN more attentive can prevent from running into difficulties... i'm afraid, this will not be the last one for me.
Thank you all for your help!!