News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Problems translating structure...

Started by Phoenix, March 19, 2005, 11:55:03 PM

Previous topic - Next topic

Phoenix

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

mnemonic

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.
Be kind. Everyone you meet is fighting a hard battle.--Plato
-------
How To Ask Questions The Smart Way

Phoenix

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!


mnemonic

Strange, I can't figure out what's wrong with your code...
I googled a bit too and found some examples. 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.
Be kind. Everyone you meet is fighting a hard battle.--Plato
-------
How To Ask Questions The Smart Way

MichaelW

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

eschew obfuscation

Phoenix

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!!

tenkey

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.
A programming language is low level when its programs require attention to the irrelevant.
Alan Perlis, Epigram #8

Phoenix

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!!