Synchronize with trunk's revision r57652.
[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
137 BOOL
138 DoPause(PMAIN_WND_INFO Info)
139 {
140 HWND hProgress;
141 BOOL bRet = FALSE;
142
143 /* Create a progress window to track the progress of the pausing service */
144 hProgress = CreateProgressDialog(Info->hMainWnd,
145 IDS_PROGRESS_INFO_PAUSE);
146 if (hProgress)
147 {
148 /* Set the service name and reset the progress bag */
149 InitializeProgressDialog(hProgress, Info->pCurrentService->lpServiceName);
150
151 /* Resume the requested service */
152 bRet = DoControl(Info, hProgress, SERVICE_CONTROL_PAUSE);
153
154 /* Complete and destroy the progress bar */
155 DestroyProgressDialog(hProgress, bRet);
156 }
157
158 return bRet;
159 }
160
161
162 BOOL
163 DoResume(PMAIN_WND_INFO Info)
164 {
165 HWND hProgress;
166 BOOL bRet = FALSE;
167
168 /* Create a progress window to track the progress of the resuming service */
169 hProgress = CreateProgressDialog(Info->hMainWnd,
170 IDS_PROGRESS_INFO_RESUME);
171 if (hProgress)
172 {
173 /* Set the service name and reset the progress bag */
174 InitializeProgressDialog(hProgress, Info->pCurrentService->lpServiceName);
175
176 /* Resume the requested service */
177 bRet = DoControl(Info, hProgress, SERVICE_CONTROL_CONTINUE);
178
179 /* Complete and destroy the progress bar */
180 DestroyProgressDialog(hProgress, bRet);
181 }
182
183 return bRet;
184 }