windows: support service PreShutdown service control signal

This adds support for the PreShutdown signal indicating the system will
be shutting down. This allows services which need time to shutdown
gracefully to use SERVICE_ACCEPT_PRESHUTDOWN to register for
SERVICE_CONTROL_PRESHUTDOWN events.

https://docs.microsoft.com/en-us/windows/win32/api/winsvc/nc-winsvc-lphandler_function_ex?redirectedfrom=MSDN

Change-Id: I380d366d49ff380972c1efe83f43610b30432f35
GitHub-Last-Rev: db8ea88b2529b0845053ec364584eb8fc3324aa9
GitHub-Pull-Request: golang/sys#85
Reviewed-on: https://go-review.googlesource.com/c/sys/+/253477
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Daniel Martí <mvdan@mvdan.cc>
diff --git a/windows/service.go b/windows/service.go
index 847e00b..f54ff90 100644
--- a/windows/service.go
+++ b/windows/service.go
@@ -65,6 +65,7 @@
 	SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
 	SERVICE_ACCEPT_POWEREVENT            = 64
 	SERVICE_ACCEPT_SESSIONCHANGE         = 128
+	SERVICE_ACCEPT_PRESHUTDOWN           = 256
 
 	SERVICE_CONTROL_STOP                  = 1
 	SERVICE_CONTROL_PAUSE                 = 2
@@ -80,6 +81,7 @@
 	SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
 	SERVICE_CONTROL_POWEREVENT            = 13
 	SERVICE_CONTROL_SESSIONCHANGE         = 14
+	SERVICE_CONTROL_PRESHUTDOWN           = 15
 
 	SERVICE_ACTIVE    = 1
 	SERVICE_INACTIVE  = 2
diff --git a/windows/svc/service.go b/windows/svc/service.go
index bae818d..f7f4ff5 100644
--- a/windows/svc/service.go
+++ b/windows/svc/service.go
@@ -50,6 +50,7 @@
 	HardwareProfileChange = Cmd(windows.SERVICE_CONTROL_HARDWAREPROFILECHANGE)
 	PowerEvent            = Cmd(windows.SERVICE_CONTROL_POWEREVENT)
 	SessionChange         = Cmd(windows.SERVICE_CONTROL_SESSIONCHANGE)
+	PreShutdown           = Cmd(windows.SERVICE_CONTROL_PRESHUTDOWN)
 )
 
 // Accepted is used to describe commands accepted by the service.
@@ -65,6 +66,7 @@
 	AcceptHardwareProfileChange = Accepted(windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
 	AcceptPowerEvent            = Accepted(windows.SERVICE_ACCEPT_POWEREVENT)
 	AcceptSessionChange         = Accepted(windows.SERVICE_ACCEPT_SESSIONCHANGE)
+	AcceptPreShutdown           = Accepted(windows.SERVICE_ACCEPT_PRESHUTDOWN)
 )
 
 // Status combines State and Accepted commands to fully describe running service.
@@ -202,6 +204,9 @@
 	if status.Accepts&AcceptSessionChange != 0 {
 		t.ControlsAccepted |= windows.SERVICE_ACCEPT_SESSIONCHANGE
 	}
+	if status.Accepts&AcceptPreShutdown != 0 {
+		t.ControlsAccepted |= windows.SERVICE_ACCEPT_PRESHUTDOWN
+	}
 	if ec.errno == 0 {
 		t.Win32ExitCode = windows.NO_ERROR
 		t.ServiceSpecificExitCode = windows.NO_ERROR