pdh.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. // Copyright 2013 The win_pdh Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build windows
  5. package win_pdh
  6. import (
  7. "syscall"
  8. "unsafe"
  9. )
  10. // Error codes
  11. const (
  12. ERROR_SUCCESS = 0
  13. ERROR_INVALID_FUNCTION = 1
  14. )
  15. type (
  16. HANDLE uintptr
  17. )
  18. // PDH error codes, which can be returned by all Pdh* functions. Taken from mingw-w64 pdhmsg.h
  19. const (
  20. PDH_CSTATUS_VALID_DATA = 0x00000000 // The returned data is valid.
  21. PDH_CSTATUS_NEW_DATA = 0x00000001 // The return data value is valid and different from the last sample.
  22. PDH_CSTATUS_NO_MACHINE = 0x800007D0 // Unable to connect to the specified computer, or the computer is offline.
  23. PDH_CSTATUS_NO_INSTANCE = 0x800007D1
  24. PDH_MORE_DATA = 0x800007D2 // The PdhGetFormattedCounterArray* function can return this if there's 'more data to be displayed'.
  25. PDH_CSTATUS_ITEM_NOT_VALIDATED = 0x800007D3
  26. PDH_RETRY = 0x800007D4
  27. PDH_NO_DATA = 0x800007D5 // The query does not currently contain any counters (for example, limited access)
  28. PDH_CALC_NEGATIVE_DENOMINATOR = 0x800007D6
  29. PDH_CALC_NEGATIVE_TIMEBASE = 0x800007D7
  30. PDH_CALC_NEGATIVE_VALUE = 0x800007D8
  31. PDH_DIALOG_CANCELLED = 0x800007D9
  32. PDH_END_OF_LOG_FILE = 0x800007DA
  33. PDH_ASYNC_QUERY_TIMEOUT = 0x800007DB
  34. PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE = 0x800007DC
  35. PDH_CSTATUS_NO_OBJECT = 0xC0000BB8
  36. PDH_CSTATUS_NO_COUNTER = 0xC0000BB9 // The specified counter could not be found.
  37. PDH_CSTATUS_INVALID_DATA = 0xC0000BBA // The counter was successfully found, but the data returned is not valid.
  38. PDH_MEMORY_ALLOCATION_FAILURE = 0xC0000BBB
  39. PDH_INVALID_HANDLE = 0xC0000BBC
  40. PDH_INVALID_ARGUMENT = 0xC0000BBD // Required argument is missing or incorrect.
  41. PDH_FUNCTION_NOT_FOUND = 0xC0000BBE
  42. PDH_CSTATUS_NO_COUNTERNAME = 0xC0000BBF
  43. PDH_CSTATUS_BAD_COUNTERNAME = 0xC0000BC0 // Unable to parse the counter path. Check the format and syntax of the specified path.
  44. PDH_INVALID_BUFFER = 0xC0000BC1
  45. PDH_INSUFFICIENT_BUFFER = 0xC0000BC2
  46. PDH_CANNOT_CONNECT_MACHINE = 0xC0000BC3
  47. PDH_INVALID_PATH = 0xC0000BC4
  48. PDH_INVALID_INSTANCE = 0xC0000BC5
  49. PDH_INVALID_DATA = 0xC0000BC6 // specified counter does not contain valid data or a successful status code.
  50. PDH_NO_DIALOG_DATA = 0xC0000BC7
  51. PDH_CANNOT_READ_NAME_STRINGS = 0xC0000BC8
  52. PDH_LOG_FILE_CREATE_ERROR = 0xC0000BC9
  53. PDH_LOG_FILE_OPEN_ERROR = 0xC0000BCA
  54. PDH_LOG_TYPE_NOT_FOUND = 0xC0000BCB
  55. PDH_NO_MORE_DATA = 0xC0000BCC
  56. PDH_ENTRY_NOT_IN_LOG_FILE = 0xC0000BCD
  57. PDH_DATA_SOURCE_IS_LOG_FILE = 0xC0000BCE
  58. PDH_DATA_SOURCE_IS_REAL_TIME = 0xC0000BCF
  59. PDH_UNABLE_READ_LOG_HEADER = 0xC0000BD0
  60. PDH_FILE_NOT_FOUND = 0xC0000BD1
  61. PDH_FILE_ALREADY_EXISTS = 0xC0000BD2
  62. PDH_NOT_IMPLEMENTED = 0xC0000BD3
  63. PDH_STRING_NOT_FOUND = 0xC0000BD4
  64. PDH_UNABLE_MAP_NAME_FILES = 0x80000BD5
  65. PDH_UNKNOWN_LOG_FORMAT = 0xC0000BD6
  66. PDH_UNKNOWN_LOGSVC_COMMAND = 0xC0000BD7
  67. PDH_LOGSVC_QUERY_NOT_FOUND = 0xC0000BD8
  68. PDH_LOGSVC_NOT_OPENED = 0xC0000BD9
  69. PDH_WBEM_ERROR = 0xC0000BDA
  70. PDH_ACCESS_DENIED = 0xC0000BDB
  71. PDH_LOG_FILE_TOO_SMALL = 0xC0000BDC
  72. PDH_INVALID_DATASOURCE = 0xC0000BDD
  73. PDH_INVALID_SQLDB = 0xC0000BDE
  74. PDH_NO_COUNTERS = 0xC0000BDF
  75. PDH_SQL_ALLOC_FAILED = 0xC0000BE0
  76. PDH_SQL_ALLOCCON_FAILED = 0xC0000BE1
  77. PDH_SQL_EXEC_DIRECT_FAILED = 0xC0000BE2
  78. PDH_SQL_FETCH_FAILED = 0xC0000BE3
  79. PDH_SQL_ROWCOUNT_FAILED = 0xC0000BE4
  80. PDH_SQL_MORE_RESULTS_FAILED = 0xC0000BE5
  81. PDH_SQL_CONNECT_FAILED = 0xC0000BE6
  82. PDH_SQL_BIND_FAILED = 0xC0000BE7
  83. PDH_CANNOT_CONNECT_WMI_SERVER = 0xC0000BE8
  84. PDH_PLA_COLLECTION_ALREADY_RUNNING = 0xC0000BE9
  85. PDH_PLA_ERROR_SCHEDULE_OVERLAP = 0xC0000BEA
  86. PDH_PLA_COLLECTION_NOT_FOUND = 0xC0000BEB
  87. PDH_PLA_ERROR_SCHEDULE_ELAPSED = 0xC0000BEC
  88. PDH_PLA_ERROR_NOSTART = 0xC0000BED
  89. PDH_PLA_ERROR_ALREADY_EXISTS = 0xC0000BEE
  90. PDH_PLA_ERROR_TYPE_MISMATCH = 0xC0000BEF
  91. PDH_PLA_ERROR_FILEPATH = 0xC0000BF0
  92. PDH_PLA_SERVICE_ERROR = 0xC0000BF1
  93. PDH_PLA_VALIDATION_ERROR = 0xC0000BF2
  94. PDH_PLA_VALIDATION_WARNING = 0x80000BF3
  95. PDH_PLA_ERROR_NAME_TOO_LONG = 0xC0000BF4
  96. PDH_INVALID_SQL_LOG_FORMAT = 0xC0000BF5
  97. PDH_COUNTER_ALREADY_IN_QUERY = 0xC0000BF6
  98. PDH_BINARY_LOG_CORRUPT = 0xC0000BF7
  99. PDH_LOG_SAMPLE_TOO_SMALL = 0xC0000BF8
  100. PDH_OS_LATER_VERSION = 0xC0000BF9
  101. PDH_OS_EARLIER_VERSION = 0xC0000BFA
  102. PDH_INCORRECT_APPEND_TIME = 0xC0000BFB
  103. PDH_UNMATCHED_APPEND_COUNTER = 0xC0000BFC
  104. PDH_SQL_ALTER_DETAIL_FAILED = 0xC0000BFD
  105. PDH_QUERY_PERF_DATA_TIMEOUT = 0xC0000BFE
  106. )
  107. // Formatting options for GetFormattedCounterValue().
  108. const (
  109. PDH_FMT_RAW = 0x00000010
  110. PDH_FMT_ANSI = 0x00000020
  111. PDH_FMT_UNICODE = 0x00000040
  112. PDH_FMT_LONG = 0x00000100 // Return data as a long int.
  113. PDH_FMT_DOUBLE = 0x00000200 // Return data as a double precision floating point real.
  114. PDH_FMT_LARGE = 0x00000400 // Return data as a 64 bit integer.
  115. PDH_FMT_NOSCALE = 0x00001000 // can be OR-ed: Do not apply the counter's default scaling factor.
  116. PDH_FMT_1000 = 0x00002000 // can be OR-ed: multiply the actual value by 1,000.
  117. PDH_FMT_NODATA = 0x00004000 // can be OR-ed: unknown what this is for, MSDN says nothing.
  118. PDH_FMT_NOCAP100 = 0x00008000 // can be OR-ed: do not cap values > 100.
  119. PERF_DETAIL_COSTLY = 0x00010000
  120. PERF_DETAIL_STANDARD = 0x0000FFFF
  121. )
  122. type (
  123. PDH_HQUERY HANDLE // query handle
  124. PDH_HCOUNTER HANDLE // counter handle
  125. )
  126. // Union specialization for double values
  127. type PDH_FMT_COUNTERVALUE_DOUBLE struct {
  128. CStatus uint32
  129. DoubleValue float64
  130. }
  131. // Union specialization for 64 bit integer values
  132. type PDH_FMT_COUNTERVALUE_LARGE struct {
  133. CStatus uint32
  134. LargeValue int64
  135. }
  136. // Union specialization for long values
  137. type PDH_FMT_COUNTERVALUE_LONG struct {
  138. CStatus uint32
  139. LongValue int32
  140. padding [4]byte
  141. }
  142. // Union specialization for double values, used by PdhGetFormattedCounterArrayDouble()
  143. type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct {
  144. SzName *uint16 // pointer to a string
  145. FmtValue PDH_FMT_COUNTERVALUE_DOUBLE
  146. }
  147. // Union specialization for 'large' values, used by PdhGetFormattedCounterArrayLarge()
  148. type PDH_FMT_COUNTERVALUE_ITEM_LARGE struct {
  149. SzName *uint16 // pointer to a string
  150. FmtValue PDH_FMT_COUNTERVALUE_LARGE
  151. }
  152. // Union specialization for long values, used by PdhGetFormattedCounterArrayLong()
  153. type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
  154. SzName *uint16 // pointer to a string
  155. FmtValue PDH_FMT_COUNTERVALUE_LONG
  156. }
  157. var (
  158. // Library
  159. libpdhDll *syscall.DLL
  160. // Functions
  161. pdh_AddCounterW *syscall.Proc
  162. pdh_AddEnglishCounterW *syscall.Proc
  163. pdh_CloseQuery *syscall.Proc
  164. pdh_CollectQueryData *syscall.Proc
  165. pdh_GetFormattedCounterValue *syscall.Proc
  166. pdh_GetFormattedCounterArrayW *syscall.Proc
  167. pdh_OpenQuery *syscall.Proc
  168. pdh_ValidatePathW *syscall.Proc
  169. )
  170. func init() {
  171. // Library
  172. libpdhDll = syscall.MustLoadDLL("pdh.dll")
  173. // Functions
  174. pdh_AddCounterW = libpdhDll.MustFindProc("PdhAddCounterW")
  175. pdh_AddEnglishCounterW, _ = libpdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista.
  176. pdh_CloseQuery = libpdhDll.MustFindProc("PdhCloseQuery")
  177. pdh_CollectQueryData = libpdhDll.MustFindProc("PdhCollectQueryData")
  178. pdh_GetFormattedCounterValue = libpdhDll.MustFindProc("PdhGetFormattedCounterValue")
  179. pdh_GetFormattedCounterArrayW = libpdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
  180. pdh_OpenQuery = libpdhDll.MustFindProc("PdhOpenQuery")
  181. pdh_ValidatePathW = libpdhDll.MustFindProc("PdhValidatePathW")
  182. }
  183. // Adds the specified counter to the query. This is the internationalized version. Preferably, use the
  184. // function PdhAddEnglishCounter instead. hQuery is the query handle, which has been fetched by PdhOpenQuery.
  185. // szFullCounterPath is a full, internationalized counter path (this will differ per Windows language version).
  186. // dwUserData is a 'user-defined value', which becomes part of the counter information. To retrieve this value
  187. // later, call PdhGetCounterInfo() and access dwQueryUserData of the PDH_COUNTER_INFO structure.
  188. //
  189. // Examples of szFullCounterPath (in an English version of Windows):
  190. //
  191. // \\Processor(_Total)\\% Idle Time
  192. // \\Processor(_Total)\\% Processor Time
  193. // \\LogicalDisk(C:)\% Free Space
  194. //
  195. // To view all (internationalized...) counters on a system, there are three non-programmatic ways: perfmon utility,
  196. // the typeperf command, and the the registry editor. perfmon.exe is perhaps the easiest way, because it's basically a
  197. // full implemention of the pdh.dll API, except with a GUI and all that. The registry setting also provides an
  198. // interface to the available counters, and can be found at the following key:
  199. //
  200. // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage
  201. //
  202. // This registry key contains several values as follows:
  203. //
  204. // 1
  205. // 1847
  206. // 2
  207. // System
  208. // 4
  209. // Memory
  210. // 6
  211. // % Processor Time
  212. // ... many, many more
  213. //
  214. // Somehow, these numeric values can be used as szFullCounterPath too:
  215. //
  216. // \2\6 will correspond to \\System\% Processor Time
  217. //
  218. // The typeperf command may also be pretty easy. To find all performance counters, simply execute:
  219. //
  220. // typeperf -qx
  221. func PdhAddCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 {
  222. ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath)
  223. ret, _, _ := pdh_AddCounterW.Call(
  224. uintptr(hQuery),
  225. uintptr(unsafe.Pointer(ptxt)),
  226. dwUserData,
  227. uintptr(unsafe.Pointer(phCounter)))
  228. return uint32(ret)
  229. }
  230. // Adds the specified language-neutral counter to the query. See the PdhAddCounter function. This function only exists on
  231. // Windows versions higher than Vista.
  232. func PdhAddEnglishCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 {
  233. if pdh_AddEnglishCounterW == nil {
  234. return ERROR_INVALID_FUNCTION
  235. }
  236. ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath)
  237. ret, _, _ := pdh_AddEnglishCounterW.Call(
  238. uintptr(hQuery),
  239. uintptr(unsafe.Pointer(ptxt)),
  240. dwUserData,
  241. uintptr(unsafe.Pointer(phCounter)))
  242. return uint32(ret)
  243. }
  244. // Closes all counters contained in the specified query, closes all handles related to the query,
  245. // and frees all memory associated with the query.
  246. func PdhCloseQuery(hQuery PDH_HQUERY) uint32 {
  247. ret, _, _ := pdh_CloseQuery.Call(uintptr(hQuery))
  248. return uint32(ret)
  249. }
  250. // Collects the current raw data value for all counters in the specified query and updates the status
  251. // code of each counter. With some counters, this function needs to be repeatedly called before the value
  252. // of the counter can be extracted with PdhGetFormattedCounterValue(). For example, the following code
  253. // requires at least two calls:
  254. //
  255. // var handle win.PDH_HQUERY
  256. // var counterHandle win.PDH_HCOUNTER
  257. // ret := win.PdhOpenQuery(0, 0, &handle)
  258. // ret = win.PdhAddEnglishCounter(handle, "\\Processor(_Total)\\% Idle Time", 0, &counterHandle)
  259. // var derp win.PDH_FMT_COUNTERVALUE_DOUBLE
  260. //
  261. // ret = win.PdhCollectQueryData(handle)
  262. // fmt.Printf("Collect return code is %x\n", ret) // return code will be PDH_CSTATUS_INVALID_DATA
  263. // ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
  264. //
  265. // ret = win.PdhCollectQueryData(handle)
  266. // fmt.Printf("Collect return code is %x\n", ret) // return code will be ERROR_SUCCESS
  267. // ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
  268. //
  269. // The PdhCollectQueryData will return an error in the first call because it needs two values for
  270. // displaying the correct data for the processor idle time. The second call will have a 0 return code.
  271. func PdhCollectQueryData(hQuery PDH_HQUERY) uint32 {
  272. ret, _, _ := pdh_CollectQueryData.Call(uintptr(hQuery))
  273. return uint32(ret)
  274. }
  275. // Formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue.
  276. // This function does not directly translate to a Windows counterpart due to union specialization tricks.
  277. func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_DOUBLE) uint32 {
  278. ret, _, _ := pdh_GetFormattedCounterValue.Call(
  279. uintptr(hCounter),
  280. uintptr(PDH_FMT_DOUBLE),
  281. uintptr(unsafe.Pointer(lpdwType)),
  282. uintptr(unsafe.Pointer(pValue)))
  283. return uint32(ret)
  284. }
  285. // Formats the given hCounter using a large int (int64). The result is set into the specialized union struct pValue.
  286. // This function does not directly translate to a Windows counterpart due to union specialization tricks.
  287. func PdhGetFormattedCounterValueLarge(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_LARGE) uint32 {
  288. ret, _, _ := pdh_GetFormattedCounterValue.Call(
  289. uintptr(hCounter),
  290. uintptr(PDH_FMT_LARGE),
  291. uintptr(unsafe.Pointer(lpdwType)),
  292. uintptr(unsafe.Pointer(pValue)))
  293. return uint32(ret)
  294. }
  295. // Formats the given hCounter using a 'long'. The result is set into the specialized union struct pValue.
  296. // This function does not directly translate to a Windows counterpart due to union specialization tricks.
  297. //
  298. // BUG(krpors): Testing this function on multiple systems yielded inconsistent results. For instance,
  299. // the pValue.LongValue kept the value '192' on test system A, but on B this was '0', while the padding
  300. // bytes of the struct got the correct value. Until someone can figure out this behaviour, prefer to use
  301. // the Double or Large counterparts instead. These functions provide actually the same data, except in
  302. // a different, working format.
  303. func PdhGetFormattedCounterValueLong(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_LONG) uint32 {
  304. ret, _, _ := pdh_GetFormattedCounterValue.Call(
  305. uintptr(hCounter),
  306. uintptr(PDH_FMT_LONG),
  307. uintptr(unsafe.Pointer(lpdwType)),
  308. uintptr(unsafe.Pointer(pValue)))
  309. return uint32(ret)
  310. }
  311. // Returns an array of formatted counter values. Use this function when you want to format the counter values of a
  312. // counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE.
  313. // An example of how this function can be used:
  314. //
  315. // okPath := "\\Process(*)\\% Processor Time" // notice the wildcard * character
  316. //
  317. // // ommitted all necessary stuff ...
  318. //
  319. // var bufSize uint32
  320. // var bufCount uint32
  321. // var size uint32 = uint32(unsafe.Sizeof(win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{}))
  322. // var emptyBuf [1]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // need at least 1 addressable null ptr.
  323. //
  324. // for {
  325. // // collect
  326. // ret := win.PdhCollectQueryData(queryHandle)
  327. // if ret == win.ERROR_SUCCESS {
  328. // ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN.
  329. // if ret == win.PDH_MORE_DATA {
  330. // filledBuf := make([]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size)
  331. // ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &filledBuf[0])
  332. // for i := 0; i < int(bufCount); i++ {
  333. // c := filledBuf[i]
  334. // var s string = win.UTF16PtrToString(c.SzName)
  335. // fmt.Printf("Index %d -> %s, value %v\n", i, s, c.FmtValue.DoubleValue)
  336. // }
  337. //
  338. // filledBuf = nil
  339. // // Need to at least set bufSize to zero, because if not, the function will not
  340. // // return PDH_MORE_DATA and will not set the bufSize.
  341. // bufCount = 0
  342. // bufSize = 0
  343. // }
  344. //
  345. // time.Sleep(2000 * time.Millisecond)
  346. // }
  347. // }
  348. func PdhGetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_DOUBLE) uint32 {
  349. ret, _, _ := pdh_GetFormattedCounterArrayW.Call(
  350. uintptr(hCounter),
  351. uintptr(PDH_FMT_DOUBLE),
  352. uintptr(unsafe.Pointer(lpdwBufferSize)),
  353. uintptr(unsafe.Pointer(lpdwBufferCount)),
  354. uintptr(unsafe.Pointer(itemBuffer)))
  355. return uint32(ret)
  356. }
  357. // Returns an array of formatted counter values. Use this function when you want to format the counter values of a
  358. // counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_LARGE.
  359. // For an example usage, see PdhGetFormattedCounterArrayDouble.
  360. func PdhGetFormattedCounterArrayLarge(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_LARGE) uint32 {
  361. ret, _, _ := pdh_GetFormattedCounterArrayW.Call(
  362. uintptr(hCounter),
  363. uintptr(PDH_FMT_LARGE),
  364. uintptr(unsafe.Pointer(lpdwBufferSize)),
  365. uintptr(unsafe.Pointer(lpdwBufferCount)),
  366. uintptr(unsafe.Pointer(itemBuffer)))
  367. return uint32(ret)
  368. }
  369. // Returns an array of formatted counter values. Use this function when you want to format the counter values of a
  370. // counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_LONG.
  371. // For an example usage, see PdhGetFormattedCounterArrayDouble.
  372. //
  373. // BUG(krpors): See description of PdhGetFormattedCounterValueLong().
  374. func PdhGetFormattedCounterArrayLong(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_LONG) uint32 {
  375. ret, _, _ := pdh_GetFormattedCounterArrayW.Call(
  376. uintptr(hCounter),
  377. uintptr(PDH_FMT_LONG),
  378. uintptr(unsafe.Pointer(lpdwBufferSize)),
  379. uintptr(unsafe.Pointer(lpdwBufferCount)),
  380. uintptr(unsafe.Pointer(itemBuffer)))
  381. return uint32(ret)
  382. }
  383. // Creates a new query that is used to manage the collection of performance data.
  384. // szDataSource is a null terminated string that specifies the name of the log file from which to
  385. // retrieve the performance data. If 0, performance data is collected from a real-time data source.
  386. // dwUserData is a user-defined value to associate with this query. To retrieve the user data later,
  387. // call PdhGetCounterInfo and access dwQueryUserData of the PDH_COUNTER_INFO structure. phQuery is
  388. // the handle to the query, and must be used in subsequent calls. This function returns a PDH_
  389. // constant error code, or ERROR_SUCCESS if the call succeeded.
  390. func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY) uint32 {
  391. ret, _, _ := pdh_OpenQuery.Call(
  392. szDataSource,
  393. dwUserData,
  394. uintptr(unsafe.Pointer(phQuery)))
  395. return uint32(ret)
  396. }
  397. // Validates a path. Will return ERROR_SUCCESS when ok, or PDH_CSTATUS_BAD_COUNTERNAME when the path is
  398. // erroneous.
  399. func PdhValidatePath(path string) uint32 {
  400. ptxt, _ := syscall.UTF16PtrFromString(path)
  401. ret, _, _ := pdh_ValidatePathW.Call(uintptr(unsafe.Pointer(ptxt)))
  402. return uint32(ret)
  403. }
  404. func UTF16PtrToString(s *uint16) string {
  405. if s == nil {
  406. return ""
  407. }
  408. return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:])
  409. }