1 /* 2 * PROJECT: ReactOS Services 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/applications/mscutils/servman/propsheet_recovery.c 5 * PURPOSE: Recovery property page 6 * COPYRIGHT: Eric Kohl 7 */ 8 9 #include "precomp.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 typedef struct _RECOVERYDATA 15 { 16 ENUM_SERVICE_STATUS_PROCESS *pService; 17 LPSERVICE_FAILURE_ACTIONS pServiceFailure; 18 BOOL bChanged; 19 } RECOVERYDATA, *PRECOVERYDATA; 20 21 static 22 VOID 23 InitRecoveryPage( 24 HWND hwndDlg) 25 { 26 LPWSTR lpAction; 27 INT id; 28 29 for (id = IDS_NO_ACTION; id <= IDS_RESTART_COMPUTER; id++) 30 { 31 if (AllocAndLoadString(&lpAction, 32 hInstance, 33 id)) 34 { 35 SendDlgItemMessageW(hwndDlg, 36 IDC_FIRST_FAILURE, 37 CB_ADDSTRING, 38 0, 39 (LPARAM)lpAction); 40 41 SendDlgItemMessageW(hwndDlg, 42 IDC_SECOND_FAILURE, 43 CB_ADDSTRING, 44 0, 45 (LPARAM)lpAction); 46 47 SendDlgItemMessageW(hwndDlg, 48 IDC_SUBSEQUENT_FAILURES, 49 CB_ADDSTRING, 50 0, 51 (LPARAM)lpAction); 52 53 LocalFree(lpAction); 54 } 55 } 56 57 SendDlgItemMessageW(hwndDlg, 58 IDC_FIRST_FAILURE, 59 CB_SETCURSEL, 60 0, 61 0); 62 63 SendDlgItemMessageW(hwndDlg, 64 IDC_SECOND_FAILURE, 65 CB_SETCURSEL, 66 0, 67 0); 68 69 SendDlgItemMessageW(hwndDlg, 70 IDC_SUBSEQUENT_FAILURES, 71 CB_SETCURSEL, 72 0, 73 0); 74 75 SendDlgItemMessageW(hwndDlg, 76 IDC_RESET_TIME, 77 WM_SETTEXT, 78 0, 79 (LPARAM)L"0"); 80 81 SendDlgItemMessageW(hwndDlg, 82 IDC_RESTART_TIME, 83 WM_SETTEXT, 84 0, 85 (LPARAM)L"1"); 86 87 for (id = IDC_RESTART_TEXT1; id <= IDC_RESTART_OPTIONS; id++) 88 EnableWindow(GetDlgItem(hwndDlg, id), FALSE); 89 } 90 91 92 static 93 BOOL 94 GetServiceFailure( 95 PRECOVERYDATA pRecoveryData) 96 { 97 LPSERVICE_FAILURE_ACTIONS pServiceFailure = NULL; 98 SC_HANDLE hManager = NULL; 99 SC_HANDLE hService = NULL; 100 BOOL bResult = TRUE; 101 DWORD cbBytesNeeded = 0; 102 103 hManager = OpenSCManager(NULL, 104 NULL, 105 SC_MANAGER_CONNECT); 106 if (hManager == NULL) 107 { 108 bResult = FALSE; 109 goto done; 110 } 111 112 hService = OpenService(hManager, pRecoveryData->pService->lpServiceName, SERVICE_QUERY_CONFIG); 113 if (hService == NULL) 114 { 115 bResult = FALSE; 116 goto done; 117 } 118 119 if (!QueryServiceConfig2(hService, 120 SERVICE_CONFIG_FAILURE_ACTIONS, 121 NULL, 122 0, 123 &cbBytesNeeded)) 124 { 125 if (cbBytesNeeded == 0) 126 { 127 bResult = FALSE; 128 goto done; 129 } 130 } 131 132 pServiceFailure = HeapAlloc(GetProcessHeap(), 0, cbBytesNeeded); 133 if (pServiceFailure == NULL) 134 { 135 SetLastError(ERROR_OUTOFMEMORY); 136 bResult = FALSE; 137 goto done; 138 } 139 140 if (!QueryServiceConfig2(hService, 141 SERVICE_CONFIG_FAILURE_ACTIONS, 142 (LPBYTE)pServiceFailure, 143 cbBytesNeeded, 144 &cbBytesNeeded)) 145 { 146 bResult = FALSE; 147 goto done; 148 } 149 150 pRecoveryData->pServiceFailure = pServiceFailure; 151 152 done: 153 if (bResult == FALSE && pServiceFailure != NULL) 154 HeapFree(GetProcessHeap(), 0, pServiceFailure); 155 156 if (hService) 157 CloseServiceHandle(hService); 158 159 if (hManager) 160 CloseServiceHandle(hManager); 161 162 return bResult; 163 } 164 165 static 166 VOID 167 ShowFailureActions( 168 HWND hwndDlg, 169 PRECOVERYDATA pRecoveryData) 170 { 171 WCHAR szBuffer[256]; 172 PWSTR startPtr, endPtr; 173 INT index, id, length; 174 DWORD i; 175 176 for (i = 0; i < min(pRecoveryData->pServiceFailure->cActions, 3); i++) 177 { 178 index = -1; 179 180 switch (pRecoveryData->pServiceFailure->lpsaActions[i].Type) 181 { 182 case SC_ACTION_NONE: 183 index = 0; 184 break; 185 186 case SC_ACTION_RESTART: 187 index = 1; 188 189 wsprintf(szBuffer, L"%lu", pRecoveryData->pServiceFailure->lpsaActions[i].Delay / 60000); 190 SendDlgItemMessageW(hwndDlg, 191 IDC_RESTART_TIME, 192 WM_SETTEXT, 193 0, 194 (LPARAM)szBuffer); 195 196 for (id = IDC_RESTART_TEXT1; id <= IDC_RESTART_TEXT2; id++) 197 EnableWindow(GetDlgItem(hwndDlg, id), TRUE); 198 break; 199 200 case SC_ACTION_REBOOT: 201 index = 3; 202 203 EnableWindow(GetDlgItem(hwndDlg, IDC_RESTART_OPTIONS), TRUE); 204 break; 205 206 case SC_ACTION_RUN_COMMAND: 207 index = 2; 208 209 for (id = IDC_RUN_GROUPBOX; id <= IDC_ADD_FAILCOUNT; id++) 210 EnableWindow(GetDlgItem(hwndDlg, id), TRUE); 211 break; 212 } 213 214 if (index != -1) 215 { 216 SendDlgItemMessageW(hwndDlg, 217 IDC_FIRST_FAILURE + i, 218 CB_SETCURSEL, 219 index, 220 0); 221 } 222 } 223 224 wsprintf(szBuffer, L"%lu", pRecoveryData->pServiceFailure->dwResetPeriod / 86400); 225 SendDlgItemMessageW(hwndDlg, 226 IDC_RESET_TIME, 227 WM_SETTEXT, 228 0, 229 (LPARAM)szBuffer); 230 231 if (pRecoveryData->pServiceFailure->lpCommand != NULL) 232 { 233 ZeroMemory(szBuffer, sizeof(szBuffer)); 234 235 startPtr = pRecoveryData->pServiceFailure->lpCommand; 236 if (*startPtr == L'\"') 237 startPtr++; 238 239 endPtr = wcschr(startPtr, L'\"'); 240 if (endPtr != NULL) 241 { 242 length = (INT)((LONG_PTR)endPtr - (LONG_PTR)startPtr); 243 CopyMemory(szBuffer, startPtr, length); 244 } 245 else 246 { 247 wcscpy(szBuffer, startPtr); 248 } 249 250 SendDlgItemMessageW(hwndDlg, 251 IDC_PROGRAM, 252 WM_SETTEXT, 253 0, 254 (LPARAM)szBuffer); 255 256 ZeroMemory(szBuffer, sizeof(szBuffer)); 257 258 if (endPtr != NULL) 259 { 260 startPtr = endPtr + 1; 261 while (iswspace(*startPtr)) 262 startPtr++; 263 264 endPtr = wcsstr(pRecoveryData->pServiceFailure->lpCommand, L"/fail=%1%"); 265 if (endPtr != NULL) 266 { 267 while (iswspace(*(endPtr - 1))) 268 endPtr--; 269 270 length = (INT)((LONG_PTR)endPtr - (LONG_PTR)startPtr); 271 CopyMemory(szBuffer, startPtr, length); 272 } 273 else 274 { 275 wcscpy(szBuffer, startPtr); 276 } 277 278 SendDlgItemMessageW(hwndDlg, 279 IDC_PARAMETERS, 280 WM_SETTEXT, 281 0, 282 (LPARAM)szBuffer); 283 284 endPtr = wcsstr(pRecoveryData->pServiceFailure->lpCommand, L"/fail=%1%"); 285 if (endPtr != NULL) 286 { 287 SendDlgItemMessageW(hwndDlg, 288 IDC_ADD_FAILCOUNT, 289 BM_SETCHECK, 290 BST_CHECKED, 291 0); 292 } 293 } 294 } 295 } 296 297 298 static 299 VOID 300 UpdateFailureActions( 301 HWND hwndDlg, 302 PRECOVERYDATA pRecoveryData) 303 { 304 INT id, index; 305 BOOL bRestartService = FALSE; 306 BOOL bRunProgram = FALSE; 307 BOOL bRebootComputer = FALSE; 308 309 for (id = IDC_FIRST_FAILURE; id <= IDC_SUBSEQUENT_FAILURES; id++) 310 { 311 index = SendDlgItemMessageW(hwndDlg, 312 id, 313 CB_GETCURSEL, 314 0, 315 0); 316 switch (index) 317 { 318 case 1: /* Restart Service */ 319 bRestartService = TRUE; 320 break; 321 322 case 2: /* Run Program */ 323 bRunProgram = TRUE; 324 break; 325 326 case 3: /* Reboot Computer */ 327 bRebootComputer = TRUE; 328 break; 329 } 330 } 331 332 for (id = IDC_RESTART_TEXT1; id <= IDC_RESTART_TEXT2; id++) 333 EnableWindow(GetDlgItem(hwndDlg, id), bRestartService); 334 335 for (id = IDC_RUN_GROUPBOX; id <= IDC_ADD_FAILCOUNT; id++) 336 EnableWindow(GetDlgItem(hwndDlg, id), bRunProgram); 337 338 EnableWindow(GetDlgItem(hwndDlg, IDC_RESTART_OPTIONS), bRebootComputer); 339 } 340 341 342 static 343 VOID 344 BrowseFile( 345 HWND hwndDlg) 346 { 347 WCHAR szFile[MAX_PATH] = {'\0'}; 348 PWCHAR pszFilter = L"Executable Files (*.exe;*.com;*.cmd;*.bat)\0*.exe;*.com;*.cmd;*.bat\0"; 349 OPENFILENAME ofn; 350 351 ZeroMemory(&ofn, sizeof(ofn)); 352 353 ofn.lStructSize = sizeof(ofn); 354 ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ENABLESIZING; 355 ofn.hwndOwner = hwndDlg; 356 ofn.lpstrFilter = pszFilter; 357 ofn.lpstrFile = szFile; 358 ofn.nMaxFile = MAX_PATH; 359 360 if (GetOpenFileName(&ofn)) 361 { 362 SendDlgItemMessageW(hwndDlg, 363 IDC_PROGRAM, 364 WM_SETTEXT, 365 0, 366 (LPARAM)szFile); 367 } 368 } 369 370 371 static 372 VOID 373 SetFailureActions( 374 HWND hwndDlg) 375 { 376 SERVICE_FAILURE_ACTIONS FailureActions; 377 BOOL bRestartService = FALSE; 378 BOOL bRunProgram = FALSE; 379 BOOL bRebootComputer = FALSE; 380 INT id, index; 381 382 ZeroMemory(&FailureActions, sizeof(FailureActions)); 383 384 /* Count the number of valid failure actions */ 385 for (id = IDC_FIRST_FAILURE; id <= IDC_SUBSEQUENT_FAILURES; id++) 386 { 387 index = SendDlgItemMessageW(hwndDlg, 388 id, 389 CB_GETCURSEL, 390 0, 391 0); 392 switch (index) 393 { 394 case 1: /* Restart Service */ 395 bRestartService = TRUE; 396 FailureActions.cActions++; 397 break; 398 399 case 2: /* Run Program */ 400 bRunProgram = TRUE; 401 FailureActions.cActions++; 402 break; 403 404 case 3: /* Reboot Computer */ 405 bRebootComputer = TRUE; 406 FailureActions.cActions++; 407 break; 408 } 409 } 410 411 if (bRestartService) 412 { 413 // IDC_RESTART_TIME 414 } 415 416 if (bRunProgram) 417 { 418 // IDC_RESTART_TIME 419 } 420 421 if (bRebootComputer) 422 { 423 // IDC_RESTART_TIME 424 } 425 426 427 #if 0 428 typedef struct _SERVICE_FAILURE_ACTIONS { 429 DWORD dwResetPeriod; 430 LPTSTR lpRebootMsg; 431 LPTSTR lpCommand; 432 DWORD cActions; 433 SC_ACTION *lpsaActions; 434 } SERVICE_FAILURE_ACTIONS, *LPSERVICE_FAILURE_ACTIONS; 435 #endif 436 } 437 438 439 INT_PTR 440 CALLBACK 441 RecoveryPageProc( 442 HWND hwndDlg, 443 UINT uMsg, 444 WPARAM wParam, 445 LPARAM lParam) 446 { 447 PRECOVERYDATA pRecoveryData; 448 449 /* Get the window context */ 450 pRecoveryData = (PRECOVERYDATA)GetWindowLongPtr(hwndDlg, 451 GWLP_USERDATA); 452 if (pRecoveryData == NULL && uMsg != WM_INITDIALOG) 453 return FALSE; 454 455 switch (uMsg) 456 { 457 case WM_INITDIALOG: 458 pRecoveryData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RECOVERYDATA)); 459 if (pRecoveryData != NULL) 460 { 461 SetWindowLongPtr(hwndDlg, 462 GWLP_USERDATA, 463 (LONG_PTR)pRecoveryData); 464 465 pRecoveryData->pService = ((PSERVICEPROPSHEET)(((LPPROPSHEETPAGE)lParam)->lParam))->pService; 466 467 InitRecoveryPage(hwndDlg); 468 469 if (GetServiceFailure(pRecoveryData)) 470 { 471 ShowFailureActions(hwndDlg, pRecoveryData); 472 } 473 } 474 break; 475 476 case WM_DESTROY: 477 if (pRecoveryData != NULL) 478 { 479 if (pRecoveryData->pServiceFailure != NULL) 480 HeapFree(GetProcessHeap(), 0, pRecoveryData->pServiceFailure); 481 482 HeapFree(GetProcessHeap(), 0, pRecoveryData); 483 } 484 break; 485 486 case WM_COMMAND: 487 switch(LOWORD(wParam)) 488 { 489 case IDC_FIRST_FAILURE: 490 case IDC_SECOND_FAILURE: 491 case IDC_SUBSEQUENT_FAILURES: 492 if (HIWORD(wParam) == CBN_SELCHANGE) 493 { 494 UpdateFailureActions(hwndDlg, pRecoveryData); 495 pRecoveryData->bChanged = TRUE; 496 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 497 } 498 break; 499 500 case IDC_RESET_TIME: 501 case IDC_RESTART_TIME: 502 case IDC_PROGRAM: 503 case IDC_PARAMETERS: 504 if (HIWORD(wParam) == EN_CHANGE) 505 { 506 pRecoveryData->bChanged = TRUE; 507 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 508 } 509 break; 510 511 case IDC_ADD_FAILCOUNT: 512 if (HIWORD(wParam) == BN_CLICKED) 513 { 514 pRecoveryData->bChanged = TRUE; 515 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 516 } 517 break; 518 519 case IDC_BROWSE_PROGRAM: 520 BrowseFile(hwndDlg); 521 break; 522 523 case IDC_RESTART_OPTIONS: 524 break; 525 } 526 break; 527 528 case WM_NOTIFY: 529 switch (((LPNMHDR)lParam)->code) 530 { 531 case PSN_APPLY: 532 if (pRecoveryData->bChanged) 533 { 534 SetFailureActions(hwndDlg); 535 pRecoveryData->bChanged = FALSE; 536 } 537 break; 538 } 539 break; 540 } 541 542 return FALSE; 543 } 544