...
1
2
3 package winservices
4
5 import (
6 "context"
7 "unsafe"
8
9 "golang.org/x/sys/windows"
10 "golang.org/x/sys/windows/svc"
11 "golang.org/x/sys/windows/svc/mgr"
12 )
13
14
15 type Service struct {
16 Name string
17 Config mgr.Config
18 Status ServiceStatus
19 srv *mgr.Service
20 }
21
22
23 type ServiceStatus struct {
24 State svc.State
25 Accepts svc.Accepted
26 Pid uint32
27 Win32ExitCode uint32
28 }
29
30
31 func NewService(name string) (*Service, error) {
32
33
34 service, err := getService(name)
35 if err != nil {
36 return nil, err
37 }
38 return &Service{
39 Name: name,
40 srv: service,
41 }, nil
42 }
43
44
45 func (s *Service) GetServiceDetail() error {
46 return s.GetServiceDetailWithContext(context.Background())
47 }
48
49
50 func (s *Service) GetServiceDetailWithContext(ctx context.Context) error {
51 config, err := s.QueryServiceConfigWithContext(ctx)
52 if err != nil {
53 return err
54 }
55 s.Config = config
56
57 status, err := s.QueryStatusWithContext(ctx)
58 if err != nil {
59 return err
60 }
61 s.Status = status
62
63 return nil
64 }
65
66
67 func (s *Service) QueryServiceConfig() (mgr.Config, error) {
68 return s.QueryServiceConfigWithContext(context.Background())
69 }
70
71
72
73 func (s *Service) QueryServiceConfigWithContext(ctx context.Context) (mgr.Config, error) {
74 return s.srv.Config()
75 }
76
77
78 func (s *Service) QueryStatus() (ServiceStatus, error) {
79 return s.QueryStatusWithContext(context.Background())
80 }
81
82
83 func (s *Service) QueryStatusWithContext(ctx context.Context) (ServiceStatus, error) {
84 var p *windows.SERVICE_STATUS_PROCESS
85 var bytesNeeded uint32
86 var buf []byte
87
88 if err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); err != windows.ERROR_INSUFFICIENT_BUFFER {
89 return ServiceStatus{}, err
90 }
91
92 buf = make([]byte, bytesNeeded)
93 p = (*windows.SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))
94 if err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, &buf[0], uint32(len(buf)), &bytesNeeded); err != nil {
95 return ServiceStatus{}, err
96 }
97
98 return ServiceStatus{
99 State: svc.State(p.CurrentState),
100 Accepts: svc.Accepted(p.ControlsAccepted),
101 Pid: p.ProcessId,
102 Win32ExitCode: p.Win32ExitCode,
103 }, nil
104 }
105
106
107
108 func ListServices() ([]Service, error) {
109 m, err := openSCManager()
110 if err != nil {
111 return nil, err
112 }
113 defer m.close()
114
115 names, err := m.mgr.ListServices()
116 if err != nil {
117 return nil, err
118 }
119
120 services := make([]Service, 0)
121 for _, name := range names {
122 services = append(services, Service{Name: name})
123 }
124
125 return services, nil
126 }
127
View as plain text