* Sync with trunk r64401.
[reactos.git] / base / applications / mscutils / servman / control.c
1 /*
2 * PROJECT: ReactOS Services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/mscutils/servman/control.c
5 * PURPOSE: Pauses and resumes a service
6 * COPYRIGHT: Copyright 2006-2010 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include "precomp.h"
11
12 static BOOL
13 DoControl(PMAIN_WND_INFO Info,
14 HWND hProgress,
15 DWORD Control)
16 {
17 SC_HANDLE hSCManager;
18 SC_HANDLE hService;
19 SERVICE_STATUS_PROCESS ServiceStatus = {0};
20 SERVICE_STATUS Status;
21 DWORD BytesNeeded = 0;
22 DWORD dwStartTickCount;
23 DWORD dwOldCheckPoint;
24 DWORD dwWaitTime;
25 DWORD dwMaxWait;
26 DWORD dwReqState;
27 BOOL bRet = FALSE;
28
29 /* Set the state we're interested in */
30 switch (Control)
31 {
32 case SERVICE_CONTROL_PAUSE:
33 dwReqState = SERVICE_PAUSED;
34 break;
35 case SERVICE_CONTROL_CONTINUE:
36 dwReqState = SERVICE_RUNNING;
37 break;
38 default:
39 /* Unhandled control code */
40 return FALSE;
41 }
42
43 hSCManager = OpenSCManager(NULL,
44 NULL,
45 SC_MANAGER_CONNECT);
46 if (hSCManager)
47 {
48 hService = OpenService(hSCManager,
49 Info->pCurrentService->lpServiceName,
50 SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_QUERY_STATUS);
51 if (hService)
52 {
53 if (hProgress)
54 {
55 /* Increment the progress bar */
56 IncrementProgressBar(hProgress, DEFAULT_STEP);
57 }
58
59 /* Send the control message to the service */
60 if (ControlService(hService,
61 Control,
62 &Status))
63 {
64 /* Get the service status */
65 if (QueryServiceStatusEx(hService,
66 SC_STATUS_PROCESS_INFO,
67 (LPBYTE)&ServiceStatus,
68 sizeof(SERVICE_STATUS_PROCESS),
69 &BytesNeeded))
70 {
71 /* We don't want to wait for more than 30 seconds */
72 dwMaxWait = 30000;
73 dwStartTickCount = GetTickCount();
74
75 /* Loop until it's at the correct state */
76 while (ServiceStatus.dwCurrentState != dwReqState)
77 {
78 dwOldCheckPoint = ServiceStatus.dwCheckPoint;
79 dwWaitTime = ServiceStatus.dwWaitHint / 10;
80
81 /* Get the latest status info */
82 if (!QueryServiceStatusEx(hService,
83 SC_STATUS_PROCESS_INFO,
84 (LPBYTE)&ServiceStatus,
85 sizeof(SERVICE_STATUS_PROCESS),
86 &BytesNeeded))
87 {
88 /* Something went wrong... */
89 break;
90 }
91
92 /* Is the service making progress? */
93 if (ServiceStatus.dwCheckPoint > dwOldCheckPoint)
94 {
95 /* It is, get the latest tickcount to reset the max wait time */
96 dwStartTickCount = GetTickCount();
97 dwOldCheckPoint = ServiceStatus.dwCheckPoint;
98 IncrementProgressBar(hProgress, DEFAULT_STEP);
99 }
100 else
101 {
102 /* It's not, make sure we haven't exceeded our wait time */
103 if(GetTickCount() >= dwStartTickCount + dwMaxWait)
104 {
105 /* We have, give up */
106 break;
107 }
108 }
109
110 /* Adjust the wait hint times */
111 if (dwWaitTime < 200)
112 dwWaitTime = 200;
113 else if (dwWaitTime > 10000)
114 dwWaitTime = 10000;
115
116 /* Wait before trying again */
117 Sleep(dwWaitTime);
118 }
119 }
120
121 if (ServiceStatus.dwCurrentState == dwReqState)
122 {
123 bRet = TRUE;
124 }
125 }
126
127 CloseServiceHandle(hService);
128 }
129
130 CloseServiceHandle(hSCManager);
131 }
132
133 return bRet;
134 }
135
136 BOOL
137 DoPause(PMAIN_WND_INFO Info)
138 {
139 HWND hProgress;
140 BOOL bRet = FALSE;
141
142 /* Create a progress window to track the progress of the pausing service */
143 hProgress = CreateProgressDialog(Info->hMainWnd,
144 IDS_PROGRESS_INFO_PAUSE);
145 if (hProgress)
146 {
147 /* Set the service name and reset the progress bag */
148 InitializeProgressDialog(hProgress, Info->pCurrentService->lpServiceName);
149
150 /* Resume the requested service */
151 bRet = DoControl(Info, hProgress, SERVICE_CONTROL_PAUSE);
152
153 /* Complete and destroy the progress bar */
154 DestroyProgressDialog(hProgress, bRet);
155 }
156
157 return bRet;
158 }
159
160 BOOL
161 DoResume(PMAIN_WND_INFO Info)
162 {
163 HWND hProgress;
164 BOOL bRet = FALSE;
165
166 /* Create a progress window to track the progress of the resuming service */
167 hProgress = CreateProgressDialog(Info->hMainWnd,
168 IDS_PROGRESS_INFO_RESUME);
169 if (hProgress)
170 {
171 /* Set the service name and reset the progress bag */
172 InitializeProgressDialog(hProgress, Info->pCurrentService->lpServiceName);
173
174 /* Resume the requested service */
175 bRet = DoControl(Info, hProgress, SERVICE_CONTROL_CONTINUE);
176
177 /* Complete and destroy the progress bar */
178 DestroyProgressDialog(hProgress, bRet);
179 }
180
181 return bRet;
182 }