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