1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS Services
3c2c66affSColin Finck  * LICENSE:     GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:        base/applications/mscutils/servman/control.c
5c2c66affSColin Finck  * PURPOSE:     Pauses and resumes a service
6c2c66affSColin Finck  * COPYRIGHT:   Copyright 2006-2015 Ged Murphy <gedmurphy@reactos.org>
7c2c66affSColin Finck  *
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10c2c66affSColin Finck #include "precomp.h"
11c2c66affSColin Finck 
12*b3947d52SKyle Katarn #define NDEBUG
13*b3947d52SKyle Katarn #include <debug.h>
14*b3947d52SKyle Katarn 
15c2c66affSColin Finck #define MAX_WAIT_TIME   30000
16c2c66affSColin Finck 
17*b3947d52SKyle Katarn DWORD
DoControlService(LPWSTR ServiceName,HWND hProgress,DWORD Control)18c2c66affSColin Finck DoControlService(LPWSTR ServiceName,
19c2c66affSColin Finck                  HWND hProgress,
20c2c66affSColin Finck                  DWORD Control)
21c2c66affSColin Finck {
22c2c66affSColin Finck     SC_HANDLE hSCManager;
23c2c66affSColin Finck     SC_HANDLE hService;
24c2c66affSColin Finck     SERVICE_STATUS_PROCESS ServiceStatus = {0};
25c2c66affSColin Finck     SERVICE_STATUS Status;
26c2c66affSColin Finck     DWORD BytesNeeded = 0;
27c2c66affSColin Finck     DWORD StartTickCount;
28c2c66affSColin Finck     DWORD OldCheckPoint;
29c2c66affSColin Finck     DWORD WaitTime;
30c2c66affSColin Finck     DWORD MaxWait;
31c2c66affSColin Finck     DWORD ReqState, i;
32c2c66affSColin Finck     BOOL Result;
33*b3947d52SKyle Katarn     DWORD dwResult = ERROR_SUCCESS;
34c2c66affSColin Finck 
35c2c66affSColin Finck     /* Set the state we're interested in */
36c2c66affSColin Finck     switch (Control)
37c2c66affSColin Finck     {
38c2c66affSColin Finck         case SERVICE_CONTROL_PAUSE:
39c2c66affSColin Finck             ReqState = SERVICE_PAUSED;
40c2c66affSColin Finck             break;
41c2c66affSColin Finck         case SERVICE_CONTROL_CONTINUE:
42c2c66affSColin Finck             ReqState = SERVICE_RUNNING;
43c2c66affSColin Finck             break;
44c2c66affSColin Finck         default:
45c2c66affSColin Finck             /* Unhandled control code */
46*b3947d52SKyle Katarn             DPRINT1("Unknown control command: 0x%X\n", Control);
47*b3947d52SKyle Katarn             return ERROR_INVALID_SERVICE_CONTROL;
48c2c66affSColin Finck     }
49c2c66affSColin Finck 
50c2c66affSColin Finck     hSCManager = OpenSCManagerW(NULL,
51c2c66affSColin Finck                                 NULL,
52c2c66affSColin Finck                                 SC_MANAGER_CONNECT);
53*b3947d52SKyle Katarn     if (!hSCManager) return GetLastError();
54c2c66affSColin Finck 
55c2c66affSColin Finck     hService = OpenServiceW(hSCManager,
56c2c66affSColin Finck                             ServiceName,
57c2c66affSColin Finck                             SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_QUERY_STATUS);
58c2c66affSColin Finck     if (!hService)
59c2c66affSColin Finck     {
60*b3947d52SKyle Katarn         dwResult = GetLastError();
61c2c66affSColin Finck         CloseServiceHandle(hSCManager);
62*b3947d52SKyle Katarn         return dwResult;
63c2c66affSColin Finck     }
64c2c66affSColin Finck 
65c2c66affSColin Finck         /* Send the control message to the service */
66c2c66affSColin Finck     Result = ControlService(hService,
67c2c66affSColin Finck                             Control,
68c2c66affSColin Finck                             &Status);
69c2c66affSColin Finck     if (Result)
70c2c66affSColin Finck     {
71c2c66affSColin Finck         if (hProgress)
72c2c66affSColin Finck         {
73c2c66affSColin Finck             /* Increment the progress bar */
74c2c66affSColin Finck             IncrementProgressBar(hProgress, DEFAULT_STEP);
75c2c66affSColin Finck         }
76c2c66affSColin Finck 
77c2c66affSColin Finck         /* Get the service status */
78c2c66affSColin Finck         Result = QueryServiceStatusEx(hService,
79c2c66affSColin Finck                                       SC_STATUS_PROCESS_INFO,
80c2c66affSColin Finck                                       (LPBYTE)&ServiceStatus,
81c2c66affSColin Finck                                       sizeof(SERVICE_STATUS_PROCESS),
82c2c66affSColin Finck                                       &BytesNeeded);
83c2c66affSColin Finck         if (Result)
84c2c66affSColin Finck         {
85c2c66affSColin Finck             Result = FALSE;
86c2c66affSColin Finck             MaxWait = MAX_WAIT_TIME;
87c2c66affSColin Finck             OldCheckPoint = ServiceStatus.dwCheckPoint;
88c2c66affSColin Finck             StartTickCount = GetTickCount();
89c2c66affSColin Finck 
90c2c66affSColin Finck             /* Loop until it's at the correct state */
91c2c66affSColin Finck             while (ServiceStatus.dwCurrentState != ReqState)
92c2c66affSColin Finck             {
93c2c66affSColin Finck                 /* Fixup the wait time */
94c2c66affSColin Finck                 WaitTime = ServiceStatus.dwWaitHint / 10;
95c2c66affSColin Finck 
96c2c66affSColin Finck                 if (WaitTime < 1000) WaitTime = 1000;
97c2c66affSColin Finck                 else if (WaitTime > 10000) WaitTime = 10000;
98c2c66affSColin Finck 
99c2c66affSColin Finck                 /* We don't wanna wait for up to 10 secs without incrementing */
100c2c66affSColin Finck                 for (i = WaitTime / 1000; i > 0; i--)
101c2c66affSColin Finck                 {
102c2c66affSColin Finck                     Sleep(1000);
103c2c66affSColin Finck                     if (hProgress)
104c2c66affSColin Finck                     {
105c2c66affSColin Finck                         /* Increment the progress bar */
106c2c66affSColin Finck                         IncrementProgressBar(hProgress, DEFAULT_STEP);
107c2c66affSColin Finck                     }
108c2c66affSColin Finck                 }
109c2c66affSColin Finck 
110c2c66affSColin Finck                 /* Get the latest status info */
111c2c66affSColin Finck                 if (!QueryServiceStatusEx(hService,
112c2c66affSColin Finck                                             SC_STATUS_PROCESS_INFO,
113c2c66affSColin Finck                                             (LPBYTE)&ServiceStatus,
114c2c66affSColin Finck                                             sizeof(SERVICE_STATUS_PROCESS),
115c2c66affSColin Finck                                             &BytesNeeded))
116c2c66affSColin Finck                 {
117c2c66affSColin Finck                     /* Something went wrong... */
118*b3947d52SKyle Katarn                     dwResult = GetLastError();
119*b3947d52SKyle Katarn                     DPRINT1("QueryServiceStatusEx failed: %d\n", dwResult);
120c2c66affSColin Finck                     break;
121c2c66affSColin Finck                 }
122c2c66affSColin Finck 
123c2c66affSColin Finck                 /* Is the service making progress? */
124c2c66affSColin Finck                 if (ServiceStatus.dwCheckPoint > OldCheckPoint)
125c2c66affSColin Finck                 {
126c2c66affSColin Finck                     /* It is, get the latest tickcount to reset the max wait time */
127c2c66affSColin Finck                     StartTickCount = GetTickCount();
128c2c66affSColin Finck                     OldCheckPoint = ServiceStatus.dwCheckPoint;
129c2c66affSColin Finck                     IncrementProgressBar(hProgress, DEFAULT_STEP);
130c2c66affSColin Finck                 }
131c2c66affSColin Finck                 else
132c2c66affSColin Finck                 {
133c2c66affSColin Finck                     /* It's not, make sure we haven't exceeded our wait time */
134c2c66affSColin Finck                     if (GetTickCount() >= StartTickCount + MaxWait)
135c2c66affSColin Finck                     {
136c2c66affSColin Finck                         /* We have, give up */
137*b3947d52SKyle Katarn                         DPRINT1("Timeout\n");
138*b3947d52SKyle Katarn                         dwResult = ERROR_SERVICE_REQUEST_TIMEOUT;
139c2c66affSColin Finck                         break;
140c2c66affSColin Finck                     }
141c2c66affSColin Finck                 }
142c2c66affSColin Finck             }
143c2c66affSColin Finck         }
144*b3947d52SKyle Katarn         else
145*b3947d52SKyle Katarn         {
146*b3947d52SKyle Katarn             dwResult = GetLastError();
147*b3947d52SKyle Katarn         }
148c2c66affSColin Finck 
149c2c66affSColin Finck         if (ServiceStatus.dwCurrentState == ReqState)
150c2c66affSColin Finck         {
151*b3947d52SKyle Katarn             dwResult = ERROR_SUCCESS;
152c2c66affSColin Finck         }
153c2c66affSColin Finck     }
154*b3947d52SKyle Katarn     else
155*b3947d52SKyle Katarn     {
156*b3947d52SKyle Katarn         dwResult = GetLastError();
157*b3947d52SKyle Katarn     }
158c2c66affSColin Finck 
159c2c66affSColin Finck     CloseServiceHandle(hService);
160c2c66affSColin Finck     CloseServiceHandle(hSCManager);
161c2c66affSColin Finck 
162*b3947d52SKyle Katarn     return dwResult;
163c2c66affSColin Finck }
164