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 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 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 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 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 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 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 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 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