win
win copied to clipboard
pdh.go alway get incorrect data
#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
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)
}
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")
/*
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
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.
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.