diff --git a/windows/service.go b/windows/service.go index 03383f1d..847e00bc 100644 --- a/windows/service.go +++ b/windows/service.go @@ -159,6 +159,10 @@ type SERVICE_DESCRIPTION struct { Description *uint16 } +type SERVICE_DELAYED_AUTO_START_INFO struct { + IsDelayedAutoStartUp uint32 +} + type SERVICE_STATUS_PROCESS struct { ServiceType uint32 CurrentState uint32 diff --git a/windows/svc/mgr/config.go b/windows/svc/mgr/config.go index 61447a58..8431edbe 100644 --- a/windows/svc/mgr/config.go +++ b/windows/svc/mgr/config.go @@ -43,6 +43,7 @@ type Config struct { Password string Description string SidType uint32 // one of SERVICE_SID_TYPE, the type of sid to use for the service + DelayedAutoStart bool // the service is started after other auto-start services are started plus a short delay } func toString(p *uint16) string { @@ -95,6 +96,16 @@ func (s *Service) Config() (Config, error) { } p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0])) + b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO) + if err != nil { + return Config{}, err + } + p3 := (*windows.SERVICE_DELAYED_AUTO_START_INFO)(unsafe.Pointer(&b[0])) + delayedStart := false + if p3.IsDelayedAutoStartUp != 0 { + delayedStart = true + } + return Config{ ServiceType: p.ServiceType, StartType: p.StartType, @@ -106,6 +117,7 @@ func (s *Service) Config() (Config, error) { ServiceStartName: toString(p.ServiceStartName), DisplayName: toString(p.DisplayName), Description: toString(p2.Description), + DelayedAutoStart: delayedStart, }, nil } @@ -119,6 +131,15 @@ func updateSidType(handle windows.Handle, sidType uint32) error { return windows.ChangeServiceConfig2(handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType))) } +func updateStartUp(handle windows.Handle, isDelayed bool) error { + var d windows.SERVICE_DELAYED_AUTO_START_INFO + if isDelayed { + d.IsDelayedAutoStartUp = 1 + } + return windows.ChangeServiceConfig2(handle, + windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (*byte)(unsafe.Pointer(&d))) +} + // UpdateConfig updates service s configuration parameters. func (s *Service) UpdateConfig(c Config) error { err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType, @@ -132,6 +153,12 @@ func (s *Service) UpdateConfig(c Config) error { if err != nil { return err } + + err = updateStartUp(s.Handle, c.DelayedAutoStart) + if err != nil { + return err + } + return updateDescription(s.Handle, c.Description) } diff --git a/windows/svc/mgr/mgr.go b/windows/svc/mgr/mgr.go index ad4cd6b6..8d1cfd8b 100644 --- a/windows/svc/mgr/mgr.go +++ b/windows/svc/mgr/mgr.go @@ -149,6 +149,14 @@ func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Se return nil, err } } + if c.DelayedAutoStart { + err = updateStartUp(h, c.DelayedAutoStart) + if err != nil { + windows.DeleteService(h) + windows.CloseHandle(h) + return nil, err + } + } return &Service{Name: name, Handle: h}, nil } diff --git a/windows/svc/mgr/mgr_test.go b/windows/svc/mgr/mgr_test.go index 9171f5bc..750ffe89 100644 --- a/windows/svc/mgr/mgr_test.go +++ b/windows/svc/mgr/mgr_test.go @@ -80,6 +80,9 @@ func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config { if err != nil { t.Fatalf("Config failed: %s", err) } + if should.DelayedAutoStart != is.DelayedAutoStart { + t.Fatalf("config mismatch: DelayedAutoStart is %v, but should have %v", is.DelayedAutoStart, should.DelayedAutoStart) + } if should.DisplayName != is.DisplayName { t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName) } @@ -257,6 +260,15 @@ func TestMyService(t *testing.T) { testConfig(t, s, c) + c.StartType = mgr.StartAutomatic + c.DelayedAutoStart = true + err = s.UpdateConfig(c) + if err != nil { + t.Fatalf("UpdateConfig failed: %v", err) + } + + testConfig(t, s, c) + svcnames, err := m.ListServices() if err != nil { t.Fatalf("ListServices failed: %v", err)