[TASKMGR] Process page: Allow using "Open File Location" functionality without runnin...
[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 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 }