Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pdh.go alway get incorrect data #12

Open
oliveagle opened this issue Feb 11, 2015 · 3 comments · May be fixed by #14
Open

pdh.go alway get incorrect data #12

oliveagle opened this issue Feb 11, 2015 · 3 comments · May be fixed by #14

Comments

@oliveagle
Copy link

#python pseudocode
hQuery = win32pdh.OpenQuery()
hCounter = win32pdh.AddCounter(hQuery, "\System\Processes")
win32pdh.CollectQueryData(hQuery)
win32pdh.CollectQueryData(hQuery)
_, val = win32pdh.GetFormattedCounterValue(hCounter, win32pdh.PDH_FMT_DOUBLE)
print val

Code above will get processes count of windows. which usually in my system is around 60

but with pdh.go version I always get meaningless data. here is my code:

// +build windows
package main

import (
    "fmt"
    "github.com/kr/pretty"
    "github.com/lxn/win"
)

func main() {
    var handle win.PDH_HQUERY
    var counterHandle win.PDH_HCOUNTER
    ret := win.PdhOpenQuery(0, 0, &handle)
    ret = win.PdhAddEnglishCounter(handle, "\\System\\Processes", 0, &counterHandle)

    var derp win.PDH_FMT_COUNTERVALUE_DOUBLE

    ret = win.PdhCollectQueryData(handle)

    var lpdwType *uint32

    fmt.Printf("Collect return code is %x\n", ret) // return code will be PDH_CSTATUS_INVALID_DATA
    ret = win.PdhGetFormattedCounterValueDouble(counterHandle, lpdwType, &derp)
    pretty.Println(derp)

    ret = win.PdhCollectQueryData(handle)
    fmt.Printf("Collect return code is %x\n", ret) // return code will be ERROR_SUCCESS
    ret = win.PdhGetFormattedCounterValueDouble(counterHandle, lpdwType, &derp)
    pretty.Println(derp)
}

here is the output
qq20150211-1

after some dig on this. I found out a solution: pass in a c struct instead of go struct

here is the code:

/*
typedef struct _PDH_FMT_COUNTERVALUE_DOUBLE
{
    int CStatus;
    double DoubleValue;
}PDH_FMT_COUNTERVALUE_DOUBLE;
*/
import "C"

func main(){
    // ...

    var pValue C.PDH_FMT_COUNTERVALUE_DOUBLE

    r1, r2, err = syscall.Syscall6(uintptr(PdhGetFormattedCounterValue), 4,
        uintptr(phCounter),
        uintptr(PDH_FMT_DOUBLE),
        uintptr(lpdwType),
        uintptr(unsafe.Pointer(&pValue)),
        0, 0)
    fmt.Println(r1, r2, err)
    fmt.Println(lpdwType, pValue, pValue.DoubleValue)
    pretty.Println(pValue)
}

qq20150211-3

I checked these counters they all give me correct data

    // path := syscall.StringToUTF16Ptr("\\System\\Processes")
    // path := syscall.StringToUTF16Ptr("\\LogicalDisk(C:)\\% Free Space")
    // path := syscall.StringToUTF16Ptr("\\Memory\\% Committed Bytes In Use")
    path := syscall.StringToUTF16Ptr("\\Memory\\Available MBytes")
@oliveagle
Copy link
Author

/*
typedef long LONG;
typedef unsigned long DWORD;
typedef struct _PDH_FMT_COUNTERVALUE_DOUBLE
{
    DWORD CStatus;
    double DoubleValue;
}PDH_FMT_COUNTERVALUE_DOUBLE;
*/
import "C"

this struct will be better

@krpors
Copy link
Contributor

krpors commented Feb 11, 2015

That's weird. When I created the code (+ the example in the comments) it worked fine. When I try it right now myself, I also get garbled data.

@douglaswth
Copy link

I'm also running into this using \System\System Up Time on all of the types. Using the CGo double struct that @oliveagle proposed seems to be working fine. Perhaps Go structs no longer line up correctly with Windows C structs or it is also possible that this only worked/works correctly with 32bit as I'm running into the problem on 64bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants