...
1
2
3
4
5
6
7 package mgr
8
9 import (
10 "syscall"
11 "unsafe"
12
13 "golang.org/x/sys/windows"
14 "golang.org/x/sys/windows/svc"
15 )
16
17
18 type Service struct {
19 Name string
20 Handle windows.Handle
21 }
22
23
24 func (s *Service) Delete() error {
25 return windows.DeleteService(s.Handle)
26 }
27
28
29 func (s *Service) Close() error {
30 return windows.CloseServiceHandle(s.Handle)
31 }
32
33
34
35 func (s *Service) Start(args ...string) error {
36 var p **uint16
37 if len(args) > 0 {
38 vs := make([]*uint16, len(args))
39 for i := range vs {
40 vs[i] = syscall.StringToUTF16Ptr(args[i])
41 }
42 p = &vs[0]
43 }
44 return windows.StartService(s.Handle, uint32(len(args)), p)
45 }
46
47
48
49
50
51
52
53 func (s *Service) Control(c svc.Cmd) (svc.Status, error) {
54 var t windows.SERVICE_STATUS
55 err := windows.ControlService(s.Handle, uint32(c), &t)
56 if err != nil &&
57 err != windows.ERROR_INVALID_SERVICE_CONTROL &&
58 err != windows.ERROR_SERVICE_CANNOT_ACCEPT_CTRL &&
59 err != windows.ERROR_SERVICE_NOT_ACTIVE {
60 return svc.Status{}, err
61 }
62 return svc.Status{
63 State: svc.State(t.CurrentState),
64 Accepts: svc.Accepted(t.ControlsAccepted),
65 }, err
66 }
67
68
69 func (s *Service) Query() (svc.Status, error) {
70 var t windows.SERVICE_STATUS_PROCESS
71 var needed uint32
72 err := windows.QueryServiceStatusEx(s.Handle, windows.SC_STATUS_PROCESS_INFO, (*byte)(unsafe.Pointer(&t)), uint32(unsafe.Sizeof(t)), &needed)
73 if err != nil {
74 return svc.Status{}, err
75 }
76 return svc.Status{
77 State: svc.State(t.CurrentState),
78 Accepts: svc.Accepted(t.ControlsAccepted),
79 ProcessId: t.ProcessId,
80 Win32ExitCode: t.Win32ExitCode,
81 ServiceSpecificExitCode: t.ServiceSpecificExitCode,
82 }, nil
83 }
84
85
86 func (s *Service) ListDependentServices(status svc.ActivityStatus) ([]string, error) {
87 var bytesNeeded, returnedServiceCount uint32
88 var services []windows.ENUM_SERVICE_STATUS
89 for {
90 var servicesPtr *windows.ENUM_SERVICE_STATUS
91 if len(services) > 0 {
92 servicesPtr = &services[0]
93 }
94 allocatedBytes := uint32(len(services)) * uint32(unsafe.Sizeof(windows.ENUM_SERVICE_STATUS{}))
95 err := windows.EnumDependentServices(s.Handle, uint32(status), servicesPtr, allocatedBytes, &bytesNeeded,
96 &returnedServiceCount)
97 if err == nil {
98 break
99 }
100 if err != syscall.ERROR_MORE_DATA {
101 return nil, err
102 }
103 if bytesNeeded <= allocatedBytes {
104 return nil, err
105 }
106
107 requiredSliceLen := bytesNeeded / uint32(unsafe.Sizeof(windows.ENUM_SERVICE_STATUS{}))
108 if bytesNeeded%uint32(unsafe.Sizeof(windows.ENUM_SERVICE_STATUS{})) != 0 {
109 requiredSliceLen += 1
110 }
111 services = make([]windows.ENUM_SERVICE_STATUS, requiredSliceLen)
112 }
113 if returnedServiceCount == 0 {
114 return nil, nil
115 }
116
117
118
119 var dependents []string
120 for i := 0; i < int(returnedServiceCount); i++ {
121 dependents = append(dependents, windows.UTF16PtrToString(services[i].ServiceName))
122 }
123 return dependents, nil
124 }
125
View as plain text