You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

120 lines
3.1 KiB

  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. // +build windows
  5. // Package mgr can be used to manage Windows service programs.
  6. // It can be used to install and remove them. It can also start,
  7. // stop and pause them. The package can query / change current
  8. // service state and config parameters.
  9. //
  10. package mgr
  11. import (
  12. "syscall"
  13. "unicode/utf16"
  14. "golang.org/x/sys/windows"
  15. )
  16. // Mgr is used to manage Windows service.
  17. type Mgr struct {
  18. Handle windows.Handle
  19. }
  20. // Connect establishes a connection to the service control manager.
  21. func Connect() (*Mgr, error) {
  22. return ConnectRemote("")
  23. }
  24. // ConnectRemote establishes a connection to the
  25. // service control manager on computer named host.
  26. func ConnectRemote(host string) (*Mgr, error) {
  27. var s *uint16
  28. if host != "" {
  29. s = syscall.StringToUTF16Ptr(host)
  30. }
  31. h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
  32. if err != nil {
  33. return nil, err
  34. }
  35. return &Mgr{Handle: h}, nil
  36. }
  37. // Disconnect closes connection to the service control manager m.
  38. func (m *Mgr) Disconnect() error {
  39. return windows.CloseServiceHandle(m.Handle)
  40. }
  41. func toPtr(s string) *uint16 {
  42. if len(s) == 0 {
  43. return nil
  44. }
  45. return syscall.StringToUTF16Ptr(s)
  46. }
  47. // toStringBlock terminates strings in ss with 0, and then
  48. // concatenates them together. It also adds extra 0 at the end.
  49. func toStringBlock(ss []string) *uint16 {
  50. if len(ss) == 0 {
  51. return nil
  52. }
  53. t := ""
  54. for _, s := range ss {
  55. if s != "" {
  56. t += s + "\x00"
  57. }
  58. }
  59. if t == "" {
  60. return nil
  61. }
  62. t += "\x00"
  63. return &utf16.Encode([]rune(t))[0]
  64. }
  65. // CreateService installs new service name on the system.
  66. // The service will be executed by running exepath binary.
  67. // Use config c to specify service parameters.
  68. // If service StartType is set to StartAutomatic,
  69. // args will be passed to svc.Handle.Execute.
  70. func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
  71. if c.StartType == 0 {
  72. c.StartType = StartManual
  73. }
  74. if c.ErrorControl == 0 {
  75. c.ErrorControl = ErrorNormal
  76. }
  77. if c.ServiceType == 0 {
  78. c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
  79. }
  80. s := syscall.EscapeArg(exepath)
  81. for _, v := range args {
  82. s += " " + syscall.EscapeArg(v)
  83. }
  84. h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
  85. windows.SERVICE_ALL_ACCESS, c.ServiceType,
  86. c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
  87. nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
  88. if err != nil {
  89. return nil, err
  90. }
  91. if c.Description != "" {
  92. err = updateDescription(h, c.Description)
  93. if err != nil {
  94. return nil, err
  95. }
  96. }
  97. return &Service{Name: name, Handle: h}, nil
  98. }
  99. // OpenService retrieves access to service name, so it can
  100. // be interrogated and controlled.
  101. func (m *Mgr) OpenService(name string) (*Service, error) {
  102. h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
  103. if err != nil {
  104. return nil, err
  105. }
  106. return &Service{Name: name, Handle: h}, nil
  107. }