/
mgr.go
110 lines (99 loc) · 2.92 KB
/
mgr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package mgr can be used to manage Windows service programs.
// It can be used to install and remove them. It can also start,
// stop, pause and so on. It can query current service state.
// It can query service config parameters and change them.
//
package mgr
import (
"code.google.com/p/winsvc/winapi"
"syscall"
"unicode/utf16"
)
// Mgr is used to manage Windows service.
type Mgr struct {
Handle syscall.Handle
}
// Connect establishes a connection to the service control manager.
func Connect() (*Mgr, error) {
return ConnectRemote("")
}
// ConnectRemote establishes a connection to the
// service control manager on computer named host.
func ConnectRemote(host string) (*Mgr, error) {
var s *uint16
if host != "" {
s = syscall.StringToUTF16Ptr(host)
}
h, err := winapi.OpenSCManager(s, nil, winapi.SC_MANAGER_ALL_ACCESS)
if err != nil {
return nil, err
}
return &Mgr{Handle: h}, nil
}
// Disconnect closes connection m to servise control manager.
func (m *Mgr) Disconnect() error {
return winapi.CloseServiceHandle(m.Handle)
}
func toPtr(s string) *uint16 {
if len(s) == 0 {
return nil
}
return syscall.StringToUTF16Ptr(s)
}
// toStringBlock terminates strings in ss with 0, and then
// concatenates them together. It also adds extra 0 at the end.
func toStringBlock(ss []string) *uint16 {
if len(ss) == 0 {
return nil
}
t := ""
for _, s := range ss {
if s != "" {
t += s + "\x00"
}
}
if t == "" {
return nil
}
t += "\x00"
return &utf16.Encode([]rune(t))[0]
}
// CreateService installs new service name on the system.
// The service will be executed by running exepath binary,
// while service settings are specified in config c.
func (m *Mgr) CreateService(name, exepath string, c Config) (*Service, error) {
if c.StartType == 0 {
c.StartType = StartManual
}
if c.ErrorControl == 0 {
c.ErrorControl = ErrorNormal
}
c.BinaryPathName = exepath // execpath is important, do not rely on BinaryPathName field to be set
h, err := winapi.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
winapi.SERVICE_ALL_ACCESS, winapi.SERVICE_WIN32_OWN_PROCESS,
c.StartType, c.ErrorControl, toPtr(exepath), toPtr(c.LoadOrderGroup),
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
if err != nil {
return nil, err
}
if c.Description != "" {
err = updateDescription(h, c.Description)
if err != nil {
return nil, err
}
}
return &Service{Name: name, Handle: h}, nil
}
// OpenService retrievs access to service name, so it can
// be interrogated and controlled.
func (m *Mgr) OpenService(name string) (*Service, error) {
h, err := winapi.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), winapi.SERVICE_ALL_ACCESS)
if err != nil {
return nil, err
}
return &Service{Name: name, Handle: h}, nil
}