1 /*
2 * PROJECT: ReactOS Services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/mscutils/servman/progress.c
5 * PURPOSE: Progress dialog box message handler
6 * COPYRIGHT: Copyright 2006-2015 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include "precomp.h"
11
12 #include <process.h>
13
14 #define PROGRESS_RANGE 20
15 #define PROGRESS_STEP_MAX 15
16
17 typedef struct _PROGRESS_DATA
18 {
19 HWND hDlg;
20 HWND hProgress;
21 LPWSTR ServiceName;
22 ULONG Action;
23 BOOL StopDepends;
24 LPWSTR ServiceList;
25 PVOID Param;
26
27 } PROGRESS_DATA, *PPROGRESS_DATA;
28
ShowError(DWORD dwLastError)29 VOID ShowError(DWORD dwLastError)
30 {
31 LPWSTR lpMsg;
32
33 if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
34 FORMAT_MESSAGE_FROM_SYSTEM |
35 FORMAT_MESSAGE_IGNORE_INSERTS,
36 NULL,
37 dwLastError,
38 LANG_USER_DEFAULT,
39 (LPWSTR)&lpMsg,
40 0, NULL))
41 {
42 return;
43 }
44
45 MessageBoxW(NULL, lpMsg, NULL, MB_OK | MB_ICONERROR);
46 LocalFree(lpMsg);
47 }
48
49 static VOID
ResetProgressDialog(HWND hDlg,LPWSTR ServiceName,ULONG LabelId)50 ResetProgressDialog(HWND hDlg,
51 LPWSTR ServiceName,
52 ULONG LabelId)
53 {
54 LPWSTR lpProgStr;
55
56 /* Load the label Id */
57 if (AllocAndLoadString(&lpProgStr,
58 hInstance,
59 LabelId))
60 {
61 /* Write it to the dialog */
62 SendDlgItemMessageW(hDlg,
63 IDC_SERVCON_INFO,
64 WM_SETTEXT,
65 0,
66 (LPARAM)lpProgStr);
67
68 LocalFree(lpProgStr);
69 }
70
71 /* Write the service name to the dialog */
72 SendDlgItemMessageW(hDlg,
73 IDC_SERVCON_NAME,
74 WM_SETTEXT,
75 0,
76 (LPARAM)ServiceName);
77
78 /* Set the progress bar to the start */
79 SendDlgItemMessageW(hDlg,
80 IDC_SERVCON_PROGRESS,
81 PBM_SETPOS,
82 0,
83 0);
84 }
85
ActionThread(void * Param)86 unsigned int __stdcall ActionThread(void* Param)
87 {
88 PPROGRESS_DATA ProgressData = (PPROGRESS_DATA)Param;
89 DWORD dwResult;
90
91 if (ProgressData->Action == ACTION_START)
92 {
93 /* Setup the progress dialog for this action */
94 ResetProgressDialog(ProgressData->hDlg,
95 ProgressData->ServiceName,
96 IDS_PROGRESS_INFO_START);
97
98 /* Start the service */
99 dwResult = DoStartService(ProgressData->ServiceName,
100 ProgressData->hProgress,
101 ProgressData->Param);
102 if (dwResult == ERROR_SUCCESS)
103 {
104 /* We're done, slide the progress bar up to the top */
105 CompleteProgressBar(ProgressData->hProgress);
106 }
107 else
108 {
109 ShowError(dwResult);
110 }
111 }
112 else if (ProgressData->Action == ACTION_STOP || ProgressData->Action == ACTION_RESTART)
113 {
114 /* Check if there are and dependants to stop */
115 if (ProgressData->StopDepends && ProgressData->ServiceList)
116 {
117 LPWSTR lpStr = ProgressData->ServiceList;
118
119 /* Loop through all the services in the list */
120 for (;;)
121 {
122 /* Break when we hit the double null */
123 if (*lpStr == L'\0' && *(lpStr + 1) == L'\0')
124 break;
125
126 /* If this isn't our first time in the loop we'll
127 have been left on a null char */
128 if (*lpStr == L'\0')
129 lpStr++;
130
131 ResetProgressDialog(ProgressData->hDlg,
132 lpStr,
133 IDS_PROGRESS_INFO_STOP);
134
135 /* Stop the requested service */
136 dwResult = DoStopService(ProgressData->ServiceName,
137 ProgressData->hProgress);
138 if (dwResult == ERROR_SUCCESS)
139 {
140 CompleteProgressBar(ProgressData->hProgress);
141 }
142 else
143 {
144 ShowError(dwResult);
145 }
146
147 /* Move onto the next string */
148 while (*lpStr != L'\0')
149 lpStr++;
150 }
151 }
152
153 ResetProgressDialog(ProgressData->hDlg,
154 ProgressData->ServiceName,
155 IDS_PROGRESS_INFO_STOP);
156
157 dwResult = DoStopService(ProgressData->ServiceName,
158 ProgressData->hProgress);
159 if (dwResult == ERROR_SUCCESS)
160 {
161 CompleteProgressBar(ProgressData->hProgress);
162 }
163 else
164 {
165 ShowError(dwResult);
166 }
167
168
169 /* If this was a restart, we'll need to start the service back up */
170 if (ProgressData->Action == ACTION_RESTART)
171 {
172 /* Setup the progress dialog for this action */
173 ResetProgressDialog(ProgressData->hDlg,
174 ProgressData->ServiceName,
175 IDS_PROGRESS_INFO_START);
176
177 /* Start the service */
178 dwResult = DoStartService(ProgressData->ServiceName,
179 ProgressData->hProgress,
180 NULL);
181 if (dwResult == ERROR_SUCCESS)
182 {
183 /* We're done, slide the progress bar up to the top */
184 CompleteProgressBar(ProgressData->hProgress);
185 }
186 else
187 {
188 ShowError(dwResult);
189 }
190 }
191 }
192 else if (ProgressData->Action == ACTION_PAUSE)
193 {
194 /* Setup the progress dialog for this action */
195 ResetProgressDialog(ProgressData->hDlg,
196 ProgressData->ServiceName,
197 IDS_PROGRESS_INFO_PAUSE);
198
199 /* Pause the service */
200 dwResult = DoControlService(ProgressData->ServiceName,
201 ProgressData->hProgress,
202 SERVICE_CONTROL_PAUSE);
203 if (dwResult == ERROR_SUCCESS)
204 {
205 /* We're done, slide the progress bar up to the top */
206 CompleteProgressBar(ProgressData->hProgress);
207 }
208 else
209 {
210 ShowError(dwResult);
211 }
212 }
213 else if (ProgressData->Action == ACTION_RESUME)
214 {
215 /* Setup the progress dialog for this action */
216 ResetProgressDialog(ProgressData->hDlg,
217 ProgressData->ServiceName,
218 IDS_PROGRESS_INFO_RESUME);
219
220 /* resume the service */
221 dwResult = DoControlService(ProgressData->ServiceName,
222 ProgressData->hProgress,
223 SERVICE_CONTROL_CONTINUE);
224 if (dwResult == ERROR_SUCCESS)
225 {
226 /* We're done, slide the progress bar up to the top */
227 CompleteProgressBar(ProgressData->hProgress);
228 }
229 else
230 {
231 ShowError(dwResult);
232 }
233 }
234
235
236 EndDialog(ProgressData->hDlg, IDOK);
237
238 _endthreadex(0);
239 return 0;
240 }
241
242 static BOOL
InitProgressDialog(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)243 InitProgressDialog(HWND hDlg,
244 UINT Message,
245 WPARAM wParam,
246 LPARAM lParam)
247 {
248 PPROGRESS_DATA ProgressData = (PPROGRESS_DATA)lParam;
249 HANDLE hThread;
250
251 ProgressData->hDlg = hDlg;
252
253 /* Get a handle to the progress bar */
254 ProgressData->hProgress = GetDlgItem(hDlg,
255 IDC_SERVCON_PROGRESS);
256 if (!ProgressData->hProgress)
257 return FALSE;
258
259 /* Set the progress bar range */
260 SendMessageW(ProgressData->hProgress,
261 PBM_SETRANGE,
262 0,
263 MAKELPARAM(0, PROGRESS_RANGE));
264
265 /* Set the progress bar step */
266 SendMessageW(ProgressData->hProgress,
267 PBM_SETSTEP,
268 (WPARAM)1,
269 0);
270
271 /* Create a thread to handle the service control */
272 hThread = (HANDLE)_beginthreadex(NULL, 0, &ActionThread, ProgressData, 0, NULL);
273 if (!hThread) return FALSE;
274
275 CloseHandle(hThread);
276
277 return TRUE;
278 }
279
280 INT_PTR CALLBACK
ProgressDialogProc(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)281 ProgressDialogProc(HWND hDlg,
282 UINT Message,
283 WPARAM wParam,
284 LPARAM lParam)
285 {
286 switch(Message)
287 {
288 case WM_INITDIALOG:
289 {
290 return InitProgressDialog(hDlg, Message, wParam, lParam);
291 }
292
293 case WM_COMMAND:
294 switch(LOWORD(wParam))
295 {
296 case IDOK:
297 EndDialog(hDlg, wParam);
298 break;
299
300 }
301 break;
302
303 default:
304 return FALSE;
305 }
306
307 return TRUE;
308 }
309
310 VOID
CompleteProgressBar(HANDLE hProgress)311 CompleteProgressBar(HANDLE hProgress)
312 {
313 HWND hProgBar = (HWND)hProgress;
314 UINT Pos = 0;
315
316 /* Get the current position */
317 Pos = SendMessageW(hProgBar,
318 PBM_GETPOS,
319 0,
320 0);
321
322 /* Loop until we hit the max */
323 while (Pos <= PROGRESS_RANGE)
324 {
325 /* Increment the progress bar */
326 SendMessageW(hProgBar,
327 PBM_DELTAPOS,
328 Pos,
329 0);
330
331 /* Wait for 15ms to give it a smooth feel */
332 Sleep(15);
333 Pos++;
334 }
335 }
336
337 VOID
IncrementProgressBar(HANDLE hProgress,UINT Step)338 IncrementProgressBar(HANDLE hProgress,
339 UINT Step)
340 {
341 HWND hProgBar = (HWND)hProgress;
342 UINT Position;
343
344 /* Don't allow the progress to reach to complete*/
345 Position = SendMessageW(hProgBar,
346 PBM_GETPOS,
347 0,
348 0);
349 if (Position < PROGRESS_STEP_MAX)
350 {
351 /* Do we want to increment the default amount? */
352 if (Step == DEFAULT_STEP)
353 {
354 /* Use the step value we set on create */
355 SendMessageW(hProgBar,
356 PBM_STEPIT,
357 0,
358 0);
359 }
360 else
361 {
362 /* Use the value passed */
363 SendMessageW(hProgBar,
364 PBM_SETPOS,
365 Step,
366 0);
367 }
368 }
369 }
370
371 BOOL
RunActionWithProgress(HWND hParent,LPWSTR ServiceName,LPWSTR DisplayName,UINT Action,PVOID Param)372 RunActionWithProgress(HWND hParent,
373 LPWSTR ServiceName,
374 LPWSTR DisplayName,
375 UINT Action,
376 PVOID Param)
377 {
378 PROGRESS_DATA ProgressData;
379 LPWSTR ServiceList;
380 BOOL StopDepends;
381 INT_PTR Result;
382
383 StopDepends = FALSE;
384 ServiceList = NULL;
385
386
387 /* Check if we'll be stopping the service */
388 if (Action == ACTION_STOP || Action == ACTION_RESTART)
389 {
390 /* Does the service have any dependent services which need stopping first */
391 ServiceList = GetListOfServicesToStop(ServiceName);
392 if (ServiceList)
393 {
394 /* Ask the user if they want to stop the dependants */
395 StopDepends = CreateStopDependsDialog(hParent,
396 ServiceName,
397 DisplayName,
398 ServiceList);
399
400 /* Exit early if the user decided not to stop the dependants */
401 if (StopDepends == FALSE)
402 {
403 HeapFree(GetProcessHeap(), 0, ServiceList);
404 return FALSE;
405 }
406 }
407 }
408
409 ProgressData.hDlg = NULL;
410 ProgressData.ServiceName = ServiceName;
411 ProgressData.Action = Action;
412 ProgressData.StopDepends = StopDepends;
413 ProgressData.ServiceList = ServiceList;
414 ProgressData.Param = Param;
415
416 Result = DialogBoxParamW(hInstance,
417 MAKEINTRESOURCEW(IDD_DLG_PROGRESS),
418 hParent,
419 ProgressDialogProc,
420 (LPARAM)&ProgressData);
421
422 if (ServiceList)
423 HeapFree(GetProcessHeap(), 0, ServiceList);
424
425 return (Result == IDOK);
426 }
427