common_windows.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // +build windows
  2. package common
  3. import (
  4. "context"
  5. "unsafe"
  6. "github.com/StackExchange/wmi"
  7. "golang.org/x/sys/windows"
  8. )
  9. // for double values
  10. type PDH_FMT_COUNTERVALUE_DOUBLE struct {
  11. CStatus uint32
  12. DoubleValue float64
  13. }
  14. // for 64 bit integer values
  15. type PDH_FMT_COUNTERVALUE_LARGE struct {
  16. CStatus uint32
  17. LargeValue int64
  18. }
  19. // for long values
  20. type PDH_FMT_COUNTERVALUE_LONG struct {
  21. CStatus uint32
  22. LongValue int32
  23. padding [4]byte
  24. }
  25. // windows system const
  26. const (
  27. ERROR_SUCCESS = 0
  28. ERROR_FILE_NOT_FOUND = 2
  29. DRIVE_REMOVABLE = 2
  30. DRIVE_FIXED = 3
  31. HKEY_LOCAL_MACHINE = 0x80000002
  32. RRF_RT_REG_SZ = 0x00000002
  33. RRF_RT_REG_DWORD = 0x00000010
  34. PDH_FMT_LONG = 0x00000100
  35. PDH_FMT_DOUBLE = 0x00000200
  36. PDH_FMT_LARGE = 0x00000400
  37. PDH_INVALID_DATA = 0xc0000bc6
  38. PDH_INVALID_HANDLE = 0xC0000bbc
  39. PDH_NO_DATA = 0x800007d5
  40. )
  41. var (
  42. Modkernel32 = windows.NewLazyDLL("kernel32.dll")
  43. ModNt = windows.NewLazyDLL("ntdll.dll")
  44. ModPdh = windows.NewLazyDLL("pdh.dll")
  45. ModPsapi = windows.NewLazyDLL("psapi.dll")
  46. ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
  47. ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
  48. PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
  49. PdhAddCounter = ModPdh.NewProc("PdhAddCounterW")
  50. PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
  51. PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
  52. PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
  53. )
  54. type FILETIME struct {
  55. DwLowDateTime uint32
  56. DwHighDateTime uint32
  57. }
  58. // borrowed from net/interface_windows.go
  59. func BytePtrToString(p *uint8) string {
  60. a := (*[10000]uint8)(unsafe.Pointer(p))
  61. i := 0
  62. for a[i] != 0 {
  63. i++
  64. }
  65. return string(a[:i])
  66. }
  67. // CounterInfo
  68. // copied from https://github.com/mackerelio/mackerel-agent/
  69. type CounterInfo struct {
  70. PostName string
  71. CounterName string
  72. Counter windows.Handle
  73. }
  74. // CreateQuery XXX
  75. // copied from https://github.com/mackerelio/mackerel-agent/
  76. func CreateQuery() (windows.Handle, error) {
  77. var query windows.Handle
  78. r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
  79. if r != 0 {
  80. return 0, err
  81. }
  82. return query, nil
  83. }
  84. // CreateCounter XXX
  85. func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {
  86. var counter windows.Handle
  87. r, _, err := PdhAddCounter.Call(
  88. uintptr(query),
  89. uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))),
  90. 0,
  91. uintptr(unsafe.Pointer(&counter)))
  92. if r != 0 {
  93. return nil, err
  94. }
  95. return &CounterInfo{
  96. PostName: pname,
  97. CounterName: cname,
  98. Counter: counter,
  99. }, nil
  100. }
  101. // WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
  102. func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
  103. if _, ok := ctx.Deadline(); !ok {
  104. ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
  105. defer cancel()
  106. ctx = ctxTimeout
  107. }
  108. errChan := make(chan error, 1)
  109. go func() {
  110. errChan <- wmi.Query(query, dst, connectServerArgs...)
  111. }()
  112. select {
  113. case <-ctx.Done():
  114. return ctx.Err()
  115. case err := <-errChan:
  116. return err
  117. }
  118. }