8e1612215156ef76e57fe720e80b89446a2fc070
[reactos.git] / base / applications / mscutils / servman / propsheet_recovery.c
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 i, index, id, length;
174
175 for (i = 0; i < min(pRecoveryData->pServiceFailure->cActions, 3); i++)
176 {
177 index = -1;
178
179 switch (pRecoveryData->pServiceFailure->lpsaActions[i].Type)
180 {
181 case SC_ACTION_NONE:
182 index = 0;
183 break;
184
185 case SC_ACTION_RESTART:
186 index = 1;
187
188 wsprintf(szBuffer, L"%lu", pRecoveryData->pServiceFailure->lpsaActions[i].Delay / 60000);
189 SendDlgItemMessageW(hwndDlg,
190 IDC_RESTART_TIME,
191 WM_SETTEXT,
192 0,
193 (LPARAM)szBuffer);
194
195 for (id = IDC_RESTART_TEXT1; id <= IDC_RESTART_TEXT2; id++)
196 EnableWindow(GetDlgItem(hwndDlg, id), TRUE);
197 break;
198
199 case SC_ACTION_REBOOT:
200 index = 3;
201
202 EnableWindow(GetDlgItem(hwndDlg, IDC_RESTART_OPTIONS), TRUE);
203 break;
204
205 case SC_ACTION_RUN_COMMAND:
206 index = 2;
207
208 for (id = IDC_RUN_GROUPBOX; id <= IDC_ADD_FAILCOUNT; id++)
209 EnableWindow(GetDlgItem(hwndDlg, id), TRUE);
210 break;
211 }
212
213 if (index != -1)
214 {
215 SendDlgItemMessageW(hwndDlg,
216 IDC_FIRST_FAILURE + i,
217 CB_SETCURSEL,
218 index,
219 0);
220 }
221 }
222
223 wsprintf(szBuffer, L"%lu", pRecoveryData->pServiceFailure->dwResetPeriod / 86400);
224 SendDlgItemMessageW(hwndDlg,
225 IDC_RESET_TIME,
226 WM_SETTEXT,
227 0,
228 (LPARAM)szBuffer);
229
230 if (pRecoveryData->pServiceFailure->lpCommand != NULL)
231 {
232 ZeroMemory(szBuffer, sizeof(szBuffer));
233
234 startPtr = pRecoveryData->pServiceFailure->lpCommand;
235 if (*startPtr == L'\"')
236 startPtr++;
237
238 endPtr = wcschr(startPtr, L'\"');
239 if (endPtr != NULL)
240 {
241 length = (INT)((LONG_PTR)endPtr - (LONG_PTR)startPtr);
242 CopyMemory(szBuffer, startPtr, length);
243 }
244 else
245 {
246 wcscpy(szBuffer, startPtr);
247 }
248
249 SendDlgItemMessageW(hwndDlg,
250 IDC_PROGRAM,
251 WM_SETTEXT,
252 0,
253 (LPARAM)szBuffer);
254
255 ZeroMemory(szBuffer, sizeof(szBuffer));
256
257 if (endPtr != NULL)
258 {
259 startPtr = endPtr + 1;
260 while (iswspace(*startPtr))
261 startPtr++;
262
263 endPtr = wcsstr(pRecoveryData->pServiceFailure->lpCommand, L"/fail=%1%");
264 if (endPtr != NULL)
265 {
266 while (iswspace(*(endPtr - 1)))
267 endPtr--;
268
269 length = (INT)((LONG_PTR)endPtr - (LONG_PTR)startPtr);
270 CopyMemory(szBuffer, startPtr, length);
271 }
272 else
273 {
274 wcscpy(szBuffer, startPtr);
275 }
276
277 SendDlgItemMessageW(hwndDlg,
278 IDC_PARAMETERS,
279 WM_SETTEXT,
280 0,
281 (LPARAM)szBuffer);
282
283 endPtr = wcsstr(pRecoveryData->pServiceFailure->lpCommand, L"/fail=%1%");
284 if (endPtr != NULL)
285 {
286 SendDlgItemMessageW(hwndDlg,
287 IDC_ADD_FAILCOUNT,
288 BM_SETCHECK,
289 BST_CHECKED,
290 0);
291 }
292 }
293 }
294 }
295
296
297 static
298 VOID
299 UpdateFailureActions(
300 HWND hwndDlg,
301 PRECOVERYDATA pRecoveryData)
302 {
303 INT id, index;
304 BOOL bRestartService = FALSE;
305 BOOL bRunProgram = FALSE;
306 BOOL bRebootComputer = FALSE;
307
308 for (id = IDC_FIRST_FAILURE; id <= IDC_SUBSEQUENT_FAILURES; id++)
309 {
310 index = SendDlgItemMessageW(hwndDlg,
311 id,
312 CB_GETCURSEL,
313 0,
314 0);
315 switch (index)
316 {
317 case 1: /* Restart Service */
318 bRestartService = TRUE;
319 break;
320
321 case 2: /* Run Program */
322 bRunProgram = TRUE;
323 break;
324
325 case 3: /* Reboot Computer */
326 bRebootComputer = TRUE;
327 break;
328 }
329 }
330
331 for (id = IDC_RESTART_TEXT1; id <= IDC_RESTART_TEXT2; id++)
332 EnableWindow(GetDlgItem(hwndDlg, id), bRestartService);
333
334 for (id = IDC_RUN_GROUPBOX; id <= IDC_ADD_FAILCOUNT; id++)
335 EnableWindow(GetDlgItem(hwndDlg, id), bRunProgram);
336
337 EnableWindow(GetDlgItem(hwndDlg, IDC_RESTART_OPTIONS), bRebootComputer);
338 }
339
340
341 static
342 VOID
343 BrowseFile(
344 HWND hwndDlg)
345 {
346 WCHAR szFile[MAX_PATH] = {'\0'};
347 PWCHAR pszFilter = L"Executable Files (*.exe;*.com;*.cmd;*.bat)\0*.exe;*.com;*.cmd;*.bat\0";
348 OPENFILENAME ofn;
349
350 ZeroMemory(&ofn, sizeof(ofn));
351
352 ofn.lStructSize = sizeof(ofn);
353 ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_ENABLESIZING;
354 ofn.hwndOwner = hwndDlg;
355 ofn.lpstrFilter = pszFilter;
356 ofn.lpstrFile = szFile;
357 ofn.nMaxFile = MAX_PATH;
358
359 if (GetOpenFileName(&ofn))
360 {
361 SendDlgItemMessageW(hwndDlg,
362 IDC_PROGRAM,
363 WM_SETTEXT,
364 0,
365 (LPARAM)szFile);
366 }
367 }
368
369
370 static
371 VOID
372 SetFailureActions(
373 HWND hwndDlg)
374 {
375 SERVICE_FAILURE_ACTIONS FailureActions;
376 BOOL bRestartService = FALSE;
377 BOOL bRunProgram = FALSE;
378 BOOL bRebootComputer = FALSE;
379 INT id, index;
380
381 ZeroMemory(&FailureActions, sizeof(FailureActions));
382
383 /* Count the number of valid failure actions */
384 for (id = IDC_FIRST_FAILURE; id <= IDC_SUBSEQUENT_FAILURES; id++)
385 {
386 index = SendDlgItemMessageW(hwndDlg,
387 id,
388 CB_GETCURSEL,
389 0,
390 0);
391 switch (index)
392 {
393 case 1: /* Restart Service */
394 bRestartService = TRUE;
395 FailureActions.cActions++;
396 break;
397
398 case 2: /* Run Program */
399 bRunProgram = TRUE;
400 FailureActions.cActions++;
401 break;
402
403 case 3: /* Reboot Computer */
404 bRebootComputer = TRUE;
405 FailureActions.cActions++;
406 break;
407 }
408 }
409
410 if (bRestartService)
411 {
412 // IDC_RESTART_TIME
413 }
414
415 if (bRunProgram)
416 {
417 // IDC_RESTART_TIME
418 }
419
420 if (bRebootComputer)
421 {
422 // IDC_RESTART_TIME
423 }
424
425
426 #if 0
427 typedef struct _SERVICE_FAILURE_ACTIONS {
428 DWORD dwResetPeriod;
429 LPTSTR lpRebootMsg;
430 LPTSTR lpCommand;
431 DWORD cActions;
432 SC_ACTION *lpsaActions;
433 } SERVICE_FAILURE_ACTIONS, *LPSERVICE_FAILURE_ACTIONS;
434 #endif
435 }
436
437
438 INT_PTR
439 CALLBACK
440 RecoveryPageProc(
441 HWND hwndDlg,
442 UINT uMsg,
443 WPARAM wParam,
444 LPARAM lParam)
445 {
446 PRECOVERYDATA pRecoveryData;
447
448 /* Get the window context */
449 pRecoveryData = (PRECOVERYDATA)GetWindowLongPtr(hwndDlg,
450 GWLP_USERDATA);
451 if (pRecoveryData == NULL && uMsg != WM_INITDIALOG)
452 return FALSE;
453
454 switch (uMsg)
455 {
456 case WM_INITDIALOG:
457 pRecoveryData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RECOVERYDATA));
458 if (pRecoveryData != NULL)
459 {
460 SetWindowLongPtr(hwndDlg,
461 GWLP_USERDATA,
462 (LONG_PTR)pRecoveryData);
463
464 pRecoveryData->pService = ((PSERVICEPROPSHEET)(((LPPROPSHEETPAGE)lParam)->lParam))->pService;
465
466 InitRecoveryPage(hwndDlg);
467
468 if (GetServiceFailure(pRecoveryData))
469 {
470 ShowFailureActions(hwndDlg, pRecoveryData);
471 }
472 }
473 break;
474
475 case WM_DESTROY:
476 if (pRecoveryData != NULL)
477 {
478 if (pRecoveryData->pServiceFailure != NULL)
479 HeapFree(GetProcessHeap(), 0, pRecoveryData->pServiceFailure);
480
481 HeapFree(GetProcessHeap(), 0, pRecoveryData);
482 }
483 break;
484
485 case WM_COMMAND:
486 switch(LOWORD(wParam))
487 {
488 case IDC_FIRST_FAILURE:
489 case IDC_SECOND_FAILURE:
490 case IDC_SUBSEQUENT_FAILURES:
491 if (HIWORD(wParam) == CBN_SELCHANGE)
492 {
493 UpdateFailureActions(hwndDlg, pRecoveryData);
494 pRecoveryData->bChanged = TRUE;
495 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
496 }
497 break;
498
499 case IDC_RESET_TIME:
500 case IDC_RESTART_TIME:
501 case IDC_PROGRAM:
502 case IDC_PARAMETERS:
503 if (HIWORD(wParam) == EN_CHANGE)
504 {
505 pRecoveryData->bChanged = TRUE;
506 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
507 }
508 break;
509
510 case IDC_ADD_FAILCOUNT:
511 if (HIWORD(wParam) == BN_CLICKED)
512 {
513 pRecoveryData->bChanged = TRUE;
514 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
515 }
516 break;
517
518 case IDC_BROWSE_PROGRAM:
519 BrowseFile(hwndDlg);
520 break;
521
522 case IDC_RESTART_OPTIONS:
523 break;
524 }
525 break;
526
527 case WM_NOTIFY:
528 switch (((LPNMHDR)lParam)->code)
529 {
530 case PSN_APPLY:
531 if (pRecoveryData->bChanged)
532 {
533 SetFailureActions(hwndDlg);
534 pRecoveryData->bChanged = FALSE;
535 }
536 break;
537 }
538 break;
539 }
540
541 return FALSE;
542 }