process_windows.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. // +build windows
  2. package process
  3. import (
  4. "context"
  5. "fmt"
  6. "os"
  7. "strings"
  8. "syscall"
  9. "time"
  10. "unsafe"
  11. "github.com/StackExchange/wmi"
  12. cpu "github.com/shirou/gopsutil/cpu"
  13. "github.com/shirou/gopsutil/internal/common"
  14. net "github.com/shirou/gopsutil/net"
  15. "github.com/shirou/w32"
  16. "golang.org/x/sys/windows"
  17. )
  18. const (
  19. NoMoreFiles = 0x12
  20. MaxPathLength = 260
  21. )
  22. var (
  23. modpsapi = windows.NewLazyDLL("psapi.dll")
  24. procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
  25. )
  26. type SystemProcessInformation struct {
  27. NextEntryOffset uint64
  28. NumberOfThreads uint64
  29. Reserved1 [48]byte
  30. Reserved2 [3]byte
  31. UniqueProcessID uintptr
  32. Reserved3 uintptr
  33. HandleCount uint64
  34. Reserved4 [4]byte
  35. Reserved5 [11]byte
  36. PeakPagefileUsage uint64
  37. PrivatePageCount uint64
  38. Reserved6 [6]uint64
  39. }
  40. // Memory_info_ex is different between OSes
  41. type MemoryInfoExStat struct {
  42. }
  43. type MemoryMapsStat struct {
  44. }
  45. type Win32_Process struct {
  46. Name string
  47. ExecutablePath *string
  48. CommandLine *string
  49. Priority uint32
  50. CreationDate *time.Time
  51. ProcessID uint32
  52. ThreadCount uint32
  53. Status *string
  54. ReadOperationCount uint64
  55. ReadTransferCount uint64
  56. WriteOperationCount uint64
  57. WriteTransferCount uint64
  58. CSCreationClassName string
  59. CSName string
  60. Caption *string
  61. CreationClassName string
  62. Description *string
  63. ExecutionState *uint16
  64. HandleCount uint32
  65. KernelModeTime uint64
  66. MaximumWorkingSetSize *uint32
  67. MinimumWorkingSetSize *uint32
  68. OSCreationClassName string
  69. OSName string
  70. OtherOperationCount uint64
  71. OtherTransferCount uint64
  72. PageFaults uint32
  73. PageFileUsage uint32
  74. ParentProcessID uint32
  75. PeakPageFileUsage uint32
  76. PeakVirtualSize uint64
  77. PeakWorkingSetSize uint32
  78. PrivatePageCount uint64
  79. TerminationDate *time.Time
  80. UserModeTime uint64
  81. WorkingSetSize uint64
  82. }
  83. func init() {
  84. wmi.DefaultClient.AllowMissingFields = true
  85. }
  86. func Pids() ([]int32, error) {
  87. return PidsWithContext(context.Background())
  88. }
  89. func PidsWithContext(ctx context.Context) ([]int32, error) {
  90. // inspired by https://gist.github.com/henkman/3083408
  91. // and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
  92. var ret []int32
  93. var read uint32 = 0
  94. var psSize uint32 = 1024
  95. const dwordSize uint32 = 4
  96. for {
  97. ps := make([]uint32, psSize)
  98. if !w32.EnumProcesses(ps, uint32(len(ps)), &read) {
  99. return nil, fmt.Errorf("could not get w32.EnumProcesses")
  100. }
  101. if uint32(len(ps)) == read { // ps buffer was too small to host every results, retry with a bigger one
  102. psSize += 1024
  103. continue
  104. }
  105. for _, pid := range ps[:read/dwordSize] {
  106. ret = append(ret, int32(pid))
  107. }
  108. return ret, nil
  109. }
  110. }
  111. func (p *Process) Ppid() (int32, error) {
  112. return p.PpidWithContext(context.Background())
  113. }
  114. func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
  115. ppid, _, _, err := getFromSnapProcess(p.Pid)
  116. if err != nil {
  117. return 0, err
  118. }
  119. return ppid, nil
  120. }
  121. func GetWin32Proc(pid int32) ([]Win32_Process, error) {
  122. return GetWin32ProcWithContext(context.Background(), pid)
  123. }
  124. func GetWin32ProcWithContext(ctx context.Context, pid int32) ([]Win32_Process, error) {
  125. var dst []Win32_Process
  126. query := fmt.Sprintf("WHERE ProcessId = %d", pid)
  127. q := wmi.CreateQuery(&dst, query)
  128. err := common.WMIQueryWithContext(ctx, q, &dst)
  129. if err != nil {
  130. return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
  131. }
  132. if len(dst) == 0 {
  133. return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty")
  134. }
  135. return dst, nil
  136. }
  137. func (p *Process) Name() (string, error) {
  138. return p.NameWithContext(context.Background())
  139. }
  140. func (p *Process) NameWithContext(ctx context.Context) (string, error) {
  141. _, _, name, err := getFromSnapProcess(p.Pid)
  142. if err != nil {
  143. return "", fmt.Errorf("could not get Name: %s", err)
  144. }
  145. return name, nil
  146. }
  147. func (p *Process) Tgid() (int32, error) {
  148. return 0, common.ErrNotImplementedError
  149. }
  150. func (p *Process) Exe() (string, error) {
  151. return p.ExeWithContext(context.Background())
  152. }
  153. func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
  154. dst, err := GetWin32Proc(p.Pid)
  155. if err != nil {
  156. return "", fmt.Errorf("could not get ExecutablePath: %s", err)
  157. }
  158. return *dst[0].ExecutablePath, nil
  159. }
  160. func (p *Process) Cmdline() (string, error) {
  161. return p.CmdlineWithContext(context.Background())
  162. }
  163. func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
  164. dst, err := GetWin32Proc(p.Pid)
  165. if err != nil {
  166. return "", fmt.Errorf("could not get CommandLine: %s", err)
  167. }
  168. return *dst[0].CommandLine, nil
  169. }
  170. // CmdlineSlice returns the command line arguments of the process as a slice with each
  171. // element being an argument. This merely returns the CommandLine informations passed
  172. // to the process split on the 0x20 ASCII character.
  173. func (p *Process) CmdlineSlice() ([]string, error) {
  174. return p.CmdlineSliceWithContext(context.Background())
  175. }
  176. func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
  177. cmdline, err := p.Cmdline()
  178. if err != nil {
  179. return nil, err
  180. }
  181. return strings.Split(cmdline, " "), nil
  182. }
  183. func (p *Process) CreateTime() (int64, error) {
  184. return p.CreateTimeWithContext(context.Background())
  185. }
  186. func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
  187. ru, err := getRusage(p.Pid)
  188. if err != nil {
  189. return 0, fmt.Errorf("could not get CreationDate: %s", err)
  190. }
  191. return ru.CreationTime.Nanoseconds() / 1000000, nil
  192. }
  193. func (p *Process) Cwd() (string, error) {
  194. return p.CwdWithContext(context.Background())
  195. }
  196. func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
  197. return "", common.ErrNotImplementedError
  198. }
  199. func (p *Process) Parent() (*Process, error) {
  200. return p.ParentWithContext(context.Background())
  201. }
  202. func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
  203. ppid, err := p.PpidWithContext(ctx)
  204. if err != nil {
  205. return nil, fmt.Errorf("could not get ParentProcessID: %s", err)
  206. }
  207. return NewProcess(ppid)
  208. }
  209. func (p *Process) Status() (string, error) {
  210. return p.StatusWithContext(context.Background())
  211. }
  212. func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
  213. return "", common.ErrNotImplementedError
  214. }
  215. func (p *Process) Username() (string, error) {
  216. return p.UsernameWithContext(context.Background())
  217. }
  218. func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
  219. pid := p.Pid
  220. // 0x1000 is PROCESS_QUERY_LIMITED_INFORMATION
  221. c, err := syscall.OpenProcess(0x1000, false, uint32(pid))
  222. if err != nil {
  223. return "", err
  224. }
  225. defer syscall.CloseHandle(c)
  226. var token syscall.Token
  227. err = syscall.OpenProcessToken(c, syscall.TOKEN_QUERY, &token)
  228. if err != nil {
  229. return "", err
  230. }
  231. defer token.Close()
  232. tokenUser, err := token.GetTokenUser()
  233. if err != nil {
  234. return "", err
  235. }
  236. user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
  237. return domain + "\\" + user, err
  238. }
  239. func (p *Process) Uids() ([]int32, error) {
  240. return p.UidsWithContext(context.Background())
  241. }
  242. func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
  243. var uids []int32
  244. return uids, common.ErrNotImplementedError
  245. }
  246. func (p *Process) Gids() ([]int32, error) {
  247. return p.GidsWithContext(context.Background())
  248. }
  249. func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
  250. var gids []int32
  251. return gids, common.ErrNotImplementedError
  252. }
  253. func (p *Process) Terminal() (string, error) {
  254. return p.TerminalWithContext(context.Background())
  255. }
  256. func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
  257. return "", common.ErrNotImplementedError
  258. }
  259. // Nice returns priority in Windows
  260. func (p *Process) Nice() (int32, error) {
  261. return p.NiceWithContext(context.Background())
  262. }
  263. func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
  264. dst, err := GetWin32Proc(p.Pid)
  265. if err != nil {
  266. return 0, fmt.Errorf("could not get Priority: %s", err)
  267. }
  268. return int32(dst[0].Priority), nil
  269. }
  270. func (p *Process) IOnice() (int32, error) {
  271. return p.IOniceWithContext(context.Background())
  272. }
  273. func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
  274. return 0, common.ErrNotImplementedError
  275. }
  276. func (p *Process) Rlimit() ([]RlimitStat, error) {
  277. return p.RlimitWithContext(context.Background())
  278. }
  279. func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
  280. var rlimit []RlimitStat
  281. return rlimit, common.ErrNotImplementedError
  282. }
  283. func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
  284. return p.RlimitUsageWithContext(context.Background(), gatherUsed)
  285. }
  286. func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
  287. var rlimit []RlimitStat
  288. return rlimit, common.ErrNotImplementedError
  289. }
  290. func (p *Process) IOCounters() (*IOCountersStat, error) {
  291. return p.IOCountersWithContext(context.Background())
  292. }
  293. func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
  294. dst, err := GetWin32Proc(p.Pid)
  295. if err != nil || len(dst) == 0 {
  296. return nil, fmt.Errorf("could not get Win32Proc: %s", err)
  297. }
  298. ret := &IOCountersStat{
  299. ReadCount: uint64(dst[0].ReadOperationCount),
  300. ReadBytes: uint64(dst[0].ReadTransferCount),
  301. WriteCount: uint64(dst[0].WriteOperationCount),
  302. WriteBytes: uint64(dst[0].WriteTransferCount),
  303. }
  304. return ret, nil
  305. }
  306. func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
  307. return p.NumCtxSwitchesWithContext(context.Background())
  308. }
  309. func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
  310. return nil, common.ErrNotImplementedError
  311. }
  312. func (p *Process) NumFDs() (int32, error) {
  313. return p.NumFDsWithContext(context.Background())
  314. }
  315. func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
  316. return 0, common.ErrNotImplementedError
  317. }
  318. func (p *Process) NumThreads() (int32, error) {
  319. return p.NumThreadsWithContext(context.Background())
  320. }
  321. func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
  322. dst, err := GetWin32Proc(p.Pid)
  323. if err != nil {
  324. return 0, fmt.Errorf("could not get ThreadCount: %s", err)
  325. }
  326. return int32(dst[0].ThreadCount), nil
  327. }
  328. func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
  329. return p.ThreadsWithContext(context.Background())
  330. }
  331. func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
  332. ret := make(map[int32]*cpu.TimesStat)
  333. return ret, common.ErrNotImplementedError
  334. }
  335. func (p *Process) Times() (*cpu.TimesStat, error) {
  336. return p.TimesWithContext(context.Background())
  337. }
  338. func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
  339. sysTimes, err := getProcessCPUTimes(p.Pid)
  340. if err != nil {
  341. return nil, err
  342. }
  343. // User and kernel times are represented as a FILETIME structure
  344. // which contains a 64-bit value representing the number of
  345. // 100-nanosecond intervals since January 1, 1601 (UTC):
  346. // http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
  347. // To convert it into a float representing the seconds that the
  348. // process has executed in user/kernel mode I borrowed the code
  349. // below from psutil's _psutil_windows.c, and in turn from Python's
  350. // Modules/posixmodule.c
  351. user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
  352. kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
  353. return &cpu.TimesStat{
  354. User: user,
  355. System: kernel,
  356. }, nil
  357. }
  358. func (p *Process) CPUAffinity() ([]int32, error) {
  359. return p.CPUAffinityWithContext(context.Background())
  360. }
  361. func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
  362. return nil, common.ErrNotImplementedError
  363. }
  364. func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
  365. return p.MemoryInfoWithContext(context.Background())
  366. }
  367. func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
  368. mem, err := getMemoryInfo(p.Pid)
  369. if err != nil {
  370. return nil, err
  371. }
  372. ret := &MemoryInfoStat{
  373. RSS: uint64(mem.WorkingSetSize),
  374. VMS: uint64(mem.PagefileUsage),
  375. }
  376. return ret, nil
  377. }
  378. func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
  379. return p.MemoryInfoExWithContext(context.Background())
  380. }
  381. func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
  382. return nil, common.ErrNotImplementedError
  383. }
  384. func (p *Process) Children() ([]*Process, error) {
  385. return p.ChildrenWithContext(context.Background())
  386. }
  387. func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
  388. var dst []Win32_Process
  389. query := wmi.CreateQuery(&dst, fmt.Sprintf("Where ParentProcessId = %d", p.Pid))
  390. err := common.WMIQueryWithContext(ctx, query, &dst)
  391. if err != nil {
  392. return nil, err
  393. }
  394. out := []*Process{}
  395. for _, proc := range dst {
  396. p, err := NewProcess(int32(proc.ProcessID))
  397. if err != nil {
  398. continue
  399. }
  400. out = append(out, p)
  401. }
  402. return out, nil
  403. }
  404. func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
  405. return p.OpenFilesWithContext(context.Background())
  406. }
  407. func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
  408. return nil, common.ErrNotImplementedError
  409. }
  410. func (p *Process) Connections() ([]net.ConnectionStat, error) {
  411. return p.ConnectionsWithContext(context.Background())
  412. }
  413. func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
  414. return nil, common.ErrNotImplementedError
  415. }
  416. func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
  417. return p.NetIOCountersWithContext(context.Background(), pernic)
  418. }
  419. func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
  420. return nil, common.ErrNotImplementedError
  421. }
  422. func (p *Process) IsRunning() (bool, error) {
  423. return p.IsRunningWithContext(context.Background())
  424. }
  425. func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
  426. return true, common.ErrNotImplementedError
  427. }
  428. func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
  429. return p.MemoryMapsWithContext(context.Background(), grouped)
  430. }
  431. func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
  432. var ret []MemoryMapsStat
  433. return &ret, common.ErrNotImplementedError
  434. }
  435. func NewProcess(pid int32) (*Process, error) {
  436. p := &Process{Pid: pid}
  437. return p, nil
  438. }
  439. func (p *Process) SendSignal(sig windows.Signal) error {
  440. return p.SendSignalWithContext(context.Background(), sig)
  441. }
  442. func (p *Process) SendSignalWithContext(ctx context.Context, sig windows.Signal) error {
  443. return common.ErrNotImplementedError
  444. }
  445. func (p *Process) Suspend() error {
  446. return p.SuspendWithContext(context.Background())
  447. }
  448. func (p *Process) SuspendWithContext(ctx context.Context) error {
  449. return common.ErrNotImplementedError
  450. }
  451. func (p *Process) Resume() error {
  452. return p.ResumeWithContext(context.Background())
  453. }
  454. func (p *Process) ResumeWithContext(ctx context.Context) error {
  455. return common.ErrNotImplementedError
  456. }
  457. func (p *Process) Terminate() error {
  458. return p.TerminateWithContext(context.Background())
  459. }
  460. func (p *Process) TerminateWithContext(ctx context.Context) error {
  461. // PROCESS_TERMINATE = 0x0001
  462. proc := w32.OpenProcess(0x0001, false, uint32(p.Pid))
  463. ret := w32.TerminateProcess(proc, 0)
  464. w32.CloseHandle(proc)
  465. if ret == false {
  466. return windows.GetLastError()
  467. } else {
  468. return nil
  469. }
  470. }
  471. func (p *Process) Kill() error {
  472. return p.KillWithContext(context.Background())
  473. }
  474. func (p *Process) KillWithContext(ctx context.Context) error {
  475. process := os.Process{Pid: int(p.Pid)}
  476. return process.Kill()
  477. }
  478. func getFromSnapProcess(pid int32) (int32, int32, string, error) {
  479. snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid))
  480. if snap == 0 {
  481. return 0, 0, "", windows.GetLastError()
  482. }
  483. defer w32.CloseHandle(snap)
  484. var pe32 w32.PROCESSENTRY32
  485. pe32.DwSize = uint32(unsafe.Sizeof(pe32))
  486. if w32.Process32First(snap, &pe32) == false {
  487. return 0, 0, "", windows.GetLastError()
  488. }
  489. if pe32.Th32ProcessID == uint32(pid) {
  490. szexe := windows.UTF16ToString(pe32.SzExeFile[:])
  491. return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
  492. }
  493. for w32.Process32Next(snap, &pe32) {
  494. if pe32.Th32ProcessID == uint32(pid) {
  495. szexe := windows.UTF16ToString(pe32.SzExeFile[:])
  496. return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
  497. }
  498. }
  499. return 0, 0, "", fmt.Errorf("Couldn't find pid: %d", pid)
  500. }
  501. // Get processes
  502. func Processes() ([]*Process, error) {
  503. return ProcessesWithContext(context.Background())
  504. }
  505. func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
  506. pids, err := Pids()
  507. if err != nil {
  508. return []*Process{}, fmt.Errorf("could not get Processes %s", err)
  509. }
  510. results := []*Process{}
  511. for _, pid := range pids {
  512. p, err := NewProcess(int32(pid))
  513. if err != nil {
  514. continue
  515. }
  516. results = append(results, p)
  517. }
  518. return results, nil
  519. }
  520. func getProcInfo(pid int32) (*SystemProcessInformation, error) {
  521. initialBufferSize := uint64(0x4000)
  522. bufferSize := initialBufferSize
  523. buffer := make([]byte, bufferSize)
  524. var sysProcInfo SystemProcessInformation
  525. ret, _, _ := common.ProcNtQuerySystemInformation.Call(
  526. uintptr(unsafe.Pointer(&sysProcInfo)),
  527. uintptr(unsafe.Pointer(&buffer[0])),
  528. uintptr(unsafe.Pointer(&bufferSize)),
  529. uintptr(unsafe.Pointer(&bufferSize)))
  530. if ret != 0 {
  531. return nil, windows.GetLastError()
  532. }
  533. return &sysProcInfo, nil
  534. }
  535. func getRusage(pid int32) (*windows.Rusage, error) {
  536. var CPU windows.Rusage
  537. c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
  538. if err != nil {
  539. return nil, err
  540. }
  541. defer windows.CloseHandle(c)
  542. if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
  543. return nil, err
  544. }
  545. return &CPU, nil
  546. }
  547. func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
  548. var mem PROCESS_MEMORY_COUNTERS
  549. // PROCESS_QUERY_LIMITED_INFORMATION is 0x1000
  550. c, err := windows.OpenProcess(0x1000, false, uint32(pid))
  551. if err != nil {
  552. return mem, err
  553. }
  554. defer windows.CloseHandle(c)
  555. if err := getProcessMemoryInfo(c, &mem); err != nil {
  556. return mem, err
  557. }
  558. return mem, err
  559. }
  560. func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
  561. r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
  562. if r1 == 0 {
  563. if e1 != 0 {
  564. err = error(e1)
  565. } else {
  566. err = syscall.EINVAL
  567. }
  568. }
  569. return
  570. }
  571. type SYSTEM_TIMES struct {
  572. CreateTime syscall.Filetime
  573. ExitTime syscall.Filetime
  574. KernelTime syscall.Filetime
  575. UserTime syscall.Filetime
  576. }
  577. func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
  578. var times SYSTEM_TIMES
  579. // PROCESS_QUERY_LIMITED_INFORMATION is 0x1000
  580. h, err := windows.OpenProcess(0x1000, false, uint32(pid))
  581. if err != nil {
  582. return times, err
  583. }
  584. defer windows.CloseHandle(h)
  585. err = syscall.GetProcessTimes(
  586. syscall.Handle(h),
  587. &times.CreateTime,
  588. &times.ExitTime,
  589. &times.KernelTime,
  590. &times.UserTime,
  591. )
  592. return times, err
  593. }