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