github.com/zhongdalu/gf@v1.0.0/third/golang.org/x/sys/windows/svc/mgr/mgr.go (about) 1 // Copyright 2012 The Go 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 5 // +build windows 6 7 // Package mgr can be used to manage Windows service programs. 8 // It can be used to install and remove them. It can also start, 9 // stop and pause them. The package can query / change current 10 // service state and config parameters. 11 // 12 package mgr 13 14 import ( 15 "syscall" 16 "unicode/utf16" 17 "unsafe" 18 19 "github.com/zhongdalu/gf/third/golang.org/x/sys/windows" 20 ) 21 22 // Mgr is used to manage Windows service. 23 type Mgr struct { 24 Handle windows.Handle 25 } 26 27 // Connect establishes a connection to the service control manager. 28 func Connect() (*Mgr, error) { 29 return ConnectRemote("") 30 } 31 32 // ConnectRemote establishes a connection to the 33 // service control manager on computer named host. 34 func ConnectRemote(host string) (*Mgr, error) { 35 var s *uint16 36 if host != "" { 37 s = syscall.StringToUTF16Ptr(host) 38 } 39 h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS) 40 if err != nil { 41 return nil, err 42 } 43 return &Mgr{Handle: h}, nil 44 } 45 46 // Disconnect closes connection to the service control manager m. 47 func (m *Mgr) Disconnect() error { 48 return windows.CloseServiceHandle(m.Handle) 49 } 50 51 func toPtr(s string) *uint16 { 52 if len(s) == 0 { 53 return nil 54 } 55 return syscall.StringToUTF16Ptr(s) 56 } 57 58 // toStringBlock terminates strings in ss with 0, and then 59 // concatenates them together. It also adds extra 0 at the end. 60 func toStringBlock(ss []string) *uint16 { 61 if len(ss) == 0 { 62 return nil 63 } 64 t := "" 65 for _, s := range ss { 66 if s != "" { 67 t += s + "\x00" 68 } 69 } 70 if t == "" { 71 return nil 72 } 73 t += "\x00" 74 return &utf16.Encode([]rune(t))[0] 75 } 76 77 // CreateService installs new service name on the system. 78 // The service will be executed by running exepath binary. 79 // Use config c to specify service parameters. 80 // Any args will be passed as command-line arguments when 81 // the service is started; these arguments are distinct from 82 // the arguments passed to Service.Start or via the "Start 83 // parameters" field in the service's Properties dialog box. 84 func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) { 85 if c.StartType == 0 { 86 c.StartType = StartManual 87 } 88 if c.ErrorControl == 0 { 89 c.ErrorControl = ErrorNormal 90 } 91 if c.ServiceType == 0 { 92 c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS 93 } 94 s := syscall.EscapeArg(exepath) 95 for _, v := range args { 96 s += " " + syscall.EscapeArg(v) 97 } 98 h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName), 99 windows.SERVICE_ALL_ACCESS, c.ServiceType, 100 c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup), 101 nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password)) 102 if err != nil { 103 return nil, err 104 } 105 if c.Description != "" { 106 err = updateDescription(h, c.Description) 107 if err != nil { 108 return nil, err 109 } 110 } 111 return &Service{Name: name, Handle: h}, nil 112 } 113 114 // OpenService retrieves access to service name, so it can 115 // be interrogated and controlled. 116 func (m *Mgr) OpenService(name string) (*Service, error) { 117 h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS) 118 if err != nil { 119 return nil, err 120 } 121 return &Service{Name: name, Handle: h}, nil 122 } 123 124 // ListServices enumerates services in the specified 125 // service control manager database m. 126 // If the caller does not have the SERVICE_QUERY_STATUS 127 // access right to a service, the service is silently 128 // omitted from the list of services returned. 129 func (m *Mgr) ListServices() ([]string, error) { 130 var err error 131 var bytesNeeded, servicesReturned uint32 132 var buf []byte 133 for { 134 var p *byte 135 if len(buf) > 0 { 136 p = &buf[0] 137 } 138 err = windows.EnumServicesStatusEx(m.Handle, windows.SC_ENUM_PROCESS_INFO, 139 windows.SERVICE_WIN32, windows.SERVICE_STATE_ALL, 140 p, uint32(len(buf)), &bytesNeeded, &servicesReturned, nil, nil) 141 if err == nil { 142 break 143 } 144 if err != syscall.ERROR_MORE_DATA { 145 return nil, err 146 } 147 if bytesNeeded <= uint32(len(buf)) { 148 return nil, err 149 } 150 buf = make([]byte, bytesNeeded) 151 } 152 if servicesReturned == 0 { 153 return nil, nil 154 } 155 services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned] 156 var names []string 157 for _, s := range services { 158 name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:]) 159 names = append(names, name) 160 } 161 return names, nil 162 }