@@ -35,11 +35,20 @@ const (
3535type Cmd uint32
3636
3737const (
38- Stop = Cmd (windows .SERVICE_CONTROL_STOP )
39- Pause = Cmd (windows .SERVICE_CONTROL_PAUSE )
40- Continue = Cmd (windows .SERVICE_CONTROL_CONTINUE )
41- Interrogate = Cmd (windows .SERVICE_CONTROL_INTERROGATE )
42- Shutdown = Cmd (windows .SERVICE_CONTROL_SHUTDOWN )
38+ Stop = Cmd (windows .SERVICE_CONTROL_STOP )
39+ Pause = Cmd (windows .SERVICE_CONTROL_PAUSE )
40+ Continue = Cmd (windows .SERVICE_CONTROL_CONTINUE )
41+ Interrogate = Cmd (windows .SERVICE_CONTROL_INTERROGATE )
42+ Shutdown = Cmd (windows .SERVICE_CONTROL_SHUTDOWN )
43+ ParamChange = Cmd (windows .SERVICE_CONTROL_PARAMCHANGE )
44+ NetBindAdd = Cmd (windows .SERVICE_CONTROL_NETBINDADD )
45+ NetBindRemove = Cmd (windows .SERVICE_CONTROL_NETBINDREMOVE )
46+ NetBindEnable = Cmd (windows .SERVICE_CONTROL_NETBINDENABLE )
47+ NetBindDisable = Cmd (windows .SERVICE_CONTROL_NETBINDDISABLE )
48+ DeviceEvent = Cmd (windows .SERVICE_CONTROL_DEVICEEVENT )
49+ HardwareProfileChange = Cmd (windows .SERVICE_CONTROL_HARDWAREPROFILECHANGE )
50+ PowerEvent = Cmd (windows .SERVICE_CONTROL_POWEREVENT )
51+ SessionChange = Cmd (windows .SERVICE_CONTROL_SESSIONCHANGE )
4352)
4453
4554// Accepted is used to describe commands accepted by the service.
@@ -63,6 +72,8 @@ type Status struct {
6372// ChangeRequest is sent to the service Handler to request service status change.
6473type ChangeRequest struct {
6574 Cmd Cmd
75+ EventType uint32
76+ EventData uintptr
6677 CurrentStatus Status
6778}
6879
@@ -85,29 +96,33 @@ type Handler interface {
8596
8697var (
8798 // These are used by asm code.
88- goWaitsH uintptr
89- cWaitsH uintptr
90- ssHandle uintptr
91- sName * uint16
92- sArgc uintptr
93- sArgv * * uint16
94- ctlHandlerProc uintptr
95- cSetEvent uintptr
96- cWaitForSingleObject uintptr
97- cRegisterServiceCtrlHandlerW uintptr
99+ goWaitsH uintptr
100+ cWaitsH uintptr
101+ ssHandle uintptr
102+ sName * uint16
103+ sArgc uintptr
104+ sArgv * * uint16
105+ ctlHandlerExProc uintptr
106+ cSetEvent uintptr
107+ cWaitForSingleObject uintptr
108+ cRegisterServiceCtrlHandlerExW uintptr
98109)
99110
100111func init () {
101112 k := syscall .MustLoadDLL ("kernel32.dll" )
102113 cSetEvent = k .MustFindProc ("SetEvent" ).Addr ()
103114 cWaitForSingleObject = k .MustFindProc ("WaitForSingleObject" ).Addr ()
104115 a := syscall .MustLoadDLL ("advapi32.dll" )
105- cRegisterServiceCtrlHandlerW = a .MustFindProc ("RegisterServiceCtrlHandlerW " ).Addr ()
116+ cRegisterServiceCtrlHandlerExW = a .MustFindProc ("RegisterServiceCtrlHandlerExW " ).Addr ()
106117}
107118
119+ // The HandlerEx prototype also has a context pointer but since we don't use
120+ // it at start-up time we don't have to pass it over either.
108121type ctlEvent struct {
109- cmd Cmd
110- errno uint32
122+ cmd Cmd
123+ eventType uint32
124+ eventData uintptr
125+ errno uint32
111126}
112127
113128// service provides access to windows service api.
@@ -208,6 +223,8 @@ func (s *service) run() {
208223 var outch chan ChangeRequest
209224 inch := s .c
210225 var cmd Cmd
226+ var evtype uint32
227+ var evdata uintptr
211228loop:
212229 for {
213230 select {
@@ -219,7 +236,9 @@ loop:
219236 inch = nil
220237 outch = cmdsToHandler
221238 cmd = r .cmd
222- case outch <- ChangeRequest {cmd , status }:
239+ evtype = r .eventType
240+ evdata = r .eventData
241+ case outch <- ChangeRequest {cmd , evtype , evdata , status }:
223242 inch = s .c
224243 outch = nil
225244 case c := <- changesFromHandler :
@@ -276,8 +295,8 @@ func Run(name string, handler Handler) error {
276295 return err
277296 }
278297
279- ctlHandler := func (ctl uint32 ) uintptr {
280- e := ctlEvent {cmd : Cmd (ctl )}
298+ ctlHandler := func (ctl uint32 , evtype uint32 , evdata uintptr , context uintptr ) uintptr {
299+ e := ctlEvent {cmd : Cmd (ctl ), eventType : evtype , eventData : evdata }
281300 // We assume that this callback function is running on
282301 // the same thread as Run. Nowhere in MS documentation
283302 // I could find statement to guarantee that. So putting
@@ -288,6 +307,7 @@ func Run(name string, handler Handler) error {
288307 e .errno = sysErrNewThreadInCallback
289308 }
290309 s .c <- e
310+ // Always return NO_ERROR (0) for now.
291311 return 0
292312 }
293313
@@ -301,7 +321,7 @@ func Run(name string, handler Handler) error {
301321 goWaitsH = uintptr (s .goWaits .h )
302322 cWaitsH = uintptr (s .cWaits .h )
303323 sName = t [0 ].ServiceName
304- ctlHandlerProc , err = newCallback (ctlHandler )
324+ ctlHandlerExProc , err = newCallback (ctlHandler )
305325 if err != nil {
306326 return err
307327 }
@@ -314,3 +334,10 @@ func Run(name string, handler Handler) error {
314334 }
315335 return nil
316336}
337+
338+ // StatusHandle returns service status handle. It is safe to call this function
339+ // from inside the Handler.Execute because then it is guaranteed to be set.
340+ // This code will have to change once multiple services are possible per process.
341+ func StatusHandle () windows.Handle {
342+ return windows .Handle (ssHandle )
343+ }
0 commit comments