[MSCONFIG_NEW] Add missing header guard. Rename Update_Btn_States() and iSortedColumn...
[reactos.git] / base / applications / msconfig_new / srvpage.cpp
1 /*
2 * PROJECT: ReactOS Applications
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: base/applications/msconfig_new/srvpage.cpp
5 * PURPOSE: Services page message handler
6 * COPYRIGHT: Copyright 2005-2006 Christoph von Wittich <Christoph@ApiViewer.de>
7 * Copyright 2011-2012 Hermes BELUSCA - MAITO <hermes.belusca@sfr.fr>
8 *
9 */
10
11 #include "precomp.h"
12 #include "utils.h"
13 #include "regutils.h"
14 #include "stringutils.h"
15 // #include "CmdLineParser.h"
16 #include "listview.h"
17 #include "uxthemesupp.h"
18
19 #include <winsvc.h>
20
21 // #include <atlbase.h>
22 #include <atlcoll.h>
23 #include <atlstr.h>
24
25 static HWND hServicesPage = NULL;
26 static HWND hServicesListCtrl = NULL;
27 static int iSortedColumn = 0;
28 static BOOL bMaskProprietarySvcs = FALSE;
29
30 DWORD GetServicesActivation(VOID)
31 {
32 DWORD dwServices = 0;
33 RegGetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\state", L"services", &dwServices);
34 return dwServices;
35 }
36
37 BOOL SetServicesActivation(DWORD dwState)
38 {
39 return (RegSetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\state", L"services", TRUE, dwState) == ERROR_SUCCESS);
40 }
41
42 static BOOL
43 RegisterNoMsgAnymore(VOID)
44 {
45 return (RegSetDWORDValue(HKEY_CURRENT_USER /* HKEY_LOCAL_MACHINE ?? */,
46 L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig",
47 L"HideEssentialServiceWarning",
48 TRUE, 1) == ERROR_SUCCESS);
49 }
50
51 BOOL
52 HideEssentialServiceWarning(VOID)
53 {
54 BOOL bRetVal = FALSE;
55 DWORD dwValue = 0;
56
57 bRetVal = ( (RegGetDWORDValue(HKEY_CURRENT_USER /* HKEY_LOCAL_MACHINE ?? */,
58 L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig",
59 L"HideEssentialServiceWarning",
60 &dwValue) == ERROR_SUCCESS) &&
61 (dwValue == 1) );
62
63 return bRetVal;
64 }
65
66 struct ServiceItem
67 {
68 ServiceItem(const LPCWSTR lpszSvcName,
69 BOOL bIsEnabled,
70 BOOL bIsRequired) :
71 m_lpszSvcName(lpszSvcName),
72 m_bIsEnabled(bIsEnabled),
73 m_bIsRequired(bIsRequired)
74 { }
75
76 ~ServiceItem(void)
77 { }
78
79 CAtlStringW m_lpszSvcName;
80 BOOL m_bIsEnabled;
81 BOOL m_bIsRequired;
82 };
83
84 struct RegistryDisabledServiceItemParams
85 {
86 BOOL bIsPresent;
87 BOOL bIsKeyed; // bIsKeyed == TRUE for a keyed-registered service ; == FALSE for a valued-registered service.
88 DWORD dwStartType;
89 SYSTEMTIME time;
90 };
91
92 static CAtlList<CAtlStringW> userModificationsList;
93
94 QUERY_REGISTRY_VALUES_ROUTINE(GetRegistryValuedDisabledServicesQueryRoutine)
95 {
96 UNREFERENCED_PARAMETER(KeyName);
97 UNREFERENCED_PARAMETER(ValueData);
98 UNREFERENCED_PARAMETER(ValueLength);
99
100 if (!EntryContext)
101 return ERROR_SUCCESS;
102
103 RegistryDisabledServiceItemParams* pContextParams = (RegistryDisabledServiceItemParams*)EntryContext;
104 if (pContextParams->bIsPresent)
105 return ERROR_SUCCESS;
106
107 if ( (hRootKey == HKEY_LOCAL_MACHINE) && (ValueType == REG_DWORD) && (ValueLength == sizeof(DWORD)) &&
108 (wcsicmp((LPCWSTR)Context, ValueName) == 0) )
109 {
110 pContextParams->bIsPresent = TRUE;
111 pContextParams->bIsKeyed = FALSE;
112 pContextParams->dwStartType = *(DWORD*)ValueData;
113 // pContextParams->time = {};
114 }
115 else
116 {
117 pContextParams->bIsPresent = FALSE;
118 pContextParams->bIsKeyed = FALSE;
119 pContextParams->dwStartType = 0;
120 // pContextParams->time = {};
121 }
122
123 return ERROR_SUCCESS;
124 }
125
126 QUERY_REGISTRY_KEYS_ROUTINE(GetRegistryKeyedDisabledServicesQueryRoutine)
127 {
128 UNREFERENCED_PARAMETER(hRootKey);
129 UNREFERENCED_PARAMETER(KeyName);
130
131 if (!EntryContext)
132 return ERROR_SUCCESS;
133
134 RegistryDisabledServiceItemParams* pContextParams = (RegistryDisabledServiceItemParams*)EntryContext;
135 if (pContextParams->bIsPresent)
136 return ERROR_SUCCESS;
137
138 DWORD dwType = 0, dwBufSize = 0;
139
140 // Be careful, the order of the operations in the comparison is very important.
141 if ( (wcsicmp((LPCWSTR)Context, SubKeyName) == 0) &&
142 (RegQueryValueEx(hOpenedSubKey, /* ValueName == */ SubKeyName, NULL, &dwType, NULL, &dwBufSize) == ERROR_SUCCESS) &&
143 (dwType == REG_DWORD) && (dwBufSize == sizeof(DWORD)) )
144 {
145 #if 1 // DisableDate
146 SYSTEMTIME disableDate = {};
147 DWORD dwRegData = 0;
148
149 dwRegData = 0;
150 RegGetDWORDValue(hOpenedSubKey, NULL, L"DAY", &dwRegData);
151 disableDate.wDay = LOWORD(dwRegData);
152
153 dwRegData = 0;
154 RegGetDWORDValue(hOpenedSubKey, NULL, L"HOUR", &dwRegData);
155 disableDate.wHour = LOWORD(dwRegData);
156
157 dwRegData = 0;
158 RegGetDWORDValue(hOpenedSubKey, NULL, L"MINUTE", &dwRegData);
159 disableDate.wMinute = LOWORD(dwRegData);
160
161 dwRegData = 0;
162 RegGetDWORDValue(hOpenedSubKey, NULL, L"MONTH", &dwRegData);
163 disableDate.wMonth = LOWORD(dwRegData);
164
165 dwRegData = 0;
166 RegGetDWORDValue(hOpenedSubKey, NULL, L"SECOND", &dwRegData);
167 disableDate.wSecond = LOWORD(dwRegData);
168
169 dwRegData = 0;
170 RegGetDWORDValue(hOpenedSubKey, NULL, L"YEAR", &dwRegData);
171 disableDate.wYear = LOWORD(dwRegData);
172 #endif
173
174 DWORD dwStartType = 0;
175 RegGetDWORDValue(hOpenedSubKey, NULL, SubKeyName /* Service name */, &dwStartType);
176
177 pContextParams->bIsPresent = TRUE;
178 pContextParams->bIsKeyed = TRUE;
179 pContextParams->dwStartType = dwStartType;
180 pContextParams->time = disableDate;
181 }
182 else
183 {
184 pContextParams->bIsPresent = FALSE;
185 pContextParams->bIsKeyed = TRUE;
186 pContextParams->dwStartType = 0;
187 // pContextParams->time = {};
188 }
189
190 return ERROR_SUCCESS;
191 }
192
193
194
195 static void AddService(SC_HANDLE hSCManager, LPENUM_SERVICE_STATUS_PROCESS Service, BOOL bHideOSVendorServices)
196 {
197 //
198 // Retrieve a handle to the service.
199 //
200 SC_HANDLE hService = OpenServiceW(hSCManager, Service->lpServiceName, SERVICE_QUERY_CONFIG);
201 if (hService == NULL)
202 return;
203
204 DWORD dwBytesNeeded = 0;
205 QueryServiceConfigW(hService, NULL, 0, &dwBytesNeeded);
206 // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
207
208 LPQUERY_SERVICE_CONFIG lpServiceConfig = (LPQUERY_SERVICE_CONFIG)MemAlloc(0, dwBytesNeeded);
209 if (!lpServiceConfig)
210 {
211 CloseServiceHandle(hService);
212 return;
213 }
214 QueryServiceConfigW(hService, lpServiceConfig, dwBytesNeeded, &dwBytesNeeded);
215
216 //
217 // Get the service's vendor...
218 //
219 LPWSTR lpszVendor = NULL;
220 {
221 // Isolate only the executable path, without any arguments.
222 // TODO: Correct at the level of CmdLineToArgv the potential bug when lpszFilename == NULL.
223 #if 0 // Disabled until CmdLineToArgv is included
224 unsigned int argc = 0;
225 LPWSTR* argv = NULL;
226 CmdLineToArgv(lpServiceConfig->lpBinaryPathName, &argc, &argv, L" \t");
227 if (argc >= 1 && argv[0])
228 lpszVendor = GetExecutableVendor(argv[0]);
229 #else
230 // Hackish solution taken from the original srvpage.c.
231 // Will be removed after CmdLineToArgv is introduced.
232 WCHAR FileName[MAX_PATH];
233 memset(&FileName, 0, sizeof(FileName));
234 if (wcscspn(lpServiceConfig->lpBinaryPathName, L"\""))
235 {
236 wcsncpy(FileName, lpServiceConfig->lpBinaryPathName, wcscspn(lpServiceConfig->lpBinaryPathName, L" ") );
237 }
238 else
239 {
240 wcscpy(FileName, lpServiceConfig->lpBinaryPathName);
241 }
242 lpszVendor = GetExecutableVendor(FileName);
243 #endif
244 if (!lpszVendor)
245 lpszVendor = LoadResourceString(hInst, IDS_UNKNOWN);
246 #if 0
247 MemFree(argv);
248 #endif
249 }
250
251 // ...and display or not the Microsoft / ReactOS services.
252 BOOL bContinue = TRUE;
253 if (bHideOSVendorServices)
254 {
255 if (FindSubStrI(lpszVendor, bIsWindows ? IDS_MICROSOFT : IDS_REACTOS))
256 bContinue = FALSE;
257 }
258
259 if (bContinue)
260 {
261 BOOL bIsServiceEnabled = (lpServiceConfig->dwStartType != SERVICE_DISABLED);
262 BOOL bAddServiceToList = FALSE;
263 BOOL bIsModifiedService = FALSE;
264 RegistryDisabledServiceItemParams params = {};
265
266 //
267 // Try to look into the user modifications list...
268 //
269 POSITION it = userModificationsList.Find(Service->lpServiceName);
270 if (it)
271 {
272 bAddServiceToList = TRUE;
273 bIsModifiedService = TRUE;
274 }
275
276 //
277 // ...if not found, try to find if the disabled service is in the registry.
278 //
279 if (!bAddServiceToList)
280 {
281 if (!bIsServiceEnabled)
282 {
283 QUERY_REGISTRY_KEYS_TABLE KeysQueryTable[2] = {};
284 KeysQueryTable[0].QueryRoutine = GetRegistryKeyedDisabledServicesQueryRoutine;
285 KeysQueryTable[0].EntryContext = &params;
286 RegQueryRegistryKeys(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", KeysQueryTable, Service->lpServiceName);
287
288 bAddServiceToList = params.bIsPresent;
289
290 if (bIsWindows && bIsPreVistaOSVersion && !bAddServiceToList)
291 {
292 QUERY_REGISTRY_VALUES_TABLE ValuesQueryTable[2] = {};
293 ValuesQueryTable[0].QueryRoutine = GetRegistryValuedDisabledServicesQueryRoutine;
294 ValuesQueryTable[0].EntryContext = &params;
295 RegQueryRegistryValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", ValuesQueryTable, Service->lpServiceName);
296
297 bAddServiceToList = params.bIsPresent;
298 }
299 }
300 else
301 {
302 bAddServiceToList = TRUE;
303 }
304 }
305
306 if (bAddServiceToList)
307 {
308 //
309 // Check if service is required by the system.
310 //
311 BOOL bIsRequired = FALSE;
312
313 dwBytesNeeded = 0;
314 QueryServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &dwBytesNeeded);
315 // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
316
317 LPSERVICE_FAILURE_ACTIONS lpServiceFailureActions = (LPSERVICE_FAILURE_ACTIONS)MemAlloc(0, dwBytesNeeded);
318 if (!lpServiceFailureActions)
319 {
320 MemFree(lpszVendor);
321 MemFree(lpServiceConfig);
322 CloseServiceHandle(hService);
323 return;
324 }
325
326 QueryServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)lpServiceFailureActions, dwBytesNeeded, &dwBytesNeeded);
327
328 // In Microsoft's MSConfig, things are done just like that!! (extracted string values from msconfig.exe)
329 if ( ( wcsicmp(Service->lpServiceName, L"rpcss" ) == 0 ||
330 wcsicmp(Service->lpServiceName, L"rpclocator") == 0 ||
331 wcsicmp(Service->lpServiceName, L"dcomlaunch") == 0 ) ||
332 ( lpServiceFailureActions &&
333 (lpServiceFailureActions->cActions >= 1) &&
334 (lpServiceFailureActions->lpsaActions[0].Type == SC_ACTION_REBOOT) ) ) // We add also this test, which corresponds to real life.
335 {
336 bIsRequired = TRUE;
337 }
338 MemFree(lpServiceFailureActions);
339
340 //
341 // Add the service into the list.
342 //
343 LVITEM item = {};
344 item.mask = LVIF_TEXT | LVIF_PARAM;
345 item.pszText = Service->lpDisplayName;
346 item.lParam = reinterpret_cast<LPARAM>(new ServiceItem(Service->lpServiceName, bIsServiceEnabled, bIsRequired));
347 item.iItem = ListView_InsertItem(hServicesListCtrl, &item);
348
349 if (bIsRequired)
350 {
351 LPWSTR lpszYes = LoadResourceString(hInst, IDS_YES);
352 ListView_SetItemText(hServicesListCtrl, item.iItem, 1, lpszYes);
353 MemFree(lpszYes);
354 }
355
356 ListView_SetItemText(hServicesListCtrl, item.iItem, 2, lpszVendor);
357
358 LPWSTR lpszStatus = LoadResourceString(hInst, ((Service->ServiceStatusProcess.dwCurrentState == SERVICE_STOPPED) ? IDS_SERVICES_STATUS_STOPPED : IDS_SERVICES_STATUS_RUNNING));
359 ListView_SetItemText(hServicesListCtrl, item.iItem, 3, lpszStatus);
360 MemFree(lpszStatus);
361
362 if (!bIsServiceEnabled)
363 {
364 LPWSTR lpszUnknown = LoadResourceString(hInst, IDS_UNKNOWN);
365
366 LPWSTR lpszDisableDate = FormatDateTime(&params.time);
367 ListView_SetItemText(hServicesListCtrl, item.iItem, 4, (lpszDisableDate ? lpszDisableDate : lpszUnknown));
368 FreeDateTime(lpszDisableDate);
369
370 MemFree(lpszUnknown);
371 }
372
373 ListView_SetCheckState(hServicesListCtrl, item.iItem, (!bIsModifiedService ? bIsServiceEnabled : !bIsServiceEnabled));
374 }
375 }
376
377 MemFree(lpszVendor);
378 MemFree(lpServiceConfig);
379 CloseServiceHandle(hService);
380
381 return;
382 }
383
384 static void ClearServicesList(void)
385 {
386 LVITEM lvitem = {};
387 lvitem.mask = LVIF_PARAM;
388 lvitem.iItem = -1; // From the beginning.
389
390 while ((lvitem.iItem = ListView_GetNextItem(hServicesListCtrl, lvitem.iItem, LVNI_ALL)) != -1)
391 {
392 ListView_GetItem(hServicesListCtrl, &lvitem);
393
394 delete reinterpret_cast<ServiceItem*>(lvitem.lParam);
395 lvitem.lParam = NULL;
396 }
397 ListView_DeleteAllItems(hServicesListCtrl);
398
399 return;
400 }
401
402 static void GetServices(BOOL bHideOSVendorServices = FALSE)
403 {
404 //
405 // First of all, clear the list.
406 //
407 ClearServicesList();
408
409 //
410 // Now, we can list the services.
411 //
412
413 // Open the Service Control Manager.
414 SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
415 if (hSCManager == NULL)
416 return;
417
418 // Enumerate all the Win32 services.
419 DWORD dwBytesNeeded = 0;
420 DWORD dwNumServices = 0;
421 // DWORD dwResumeHandle = 0;
422 EnumServicesStatusExW(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded, &dwNumServices, NULL /* &dwResumeHandle */, NULL);
423 // if (GetLastError() == ERROR_MORE_DATA)
424
425 LPENUM_SERVICE_STATUS_PROCESS lpServices = (LPENUM_SERVICE_STATUS_PROCESS)MemAlloc(0, dwBytesNeeded);
426 if (!lpServices)
427 {
428 CloseServiceHandle(hSCManager);
429 return;
430 }
431 EnumServicesStatusExW(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)lpServices, dwBytesNeeded, &dwBytesNeeded, &dwNumServices, NULL /* &dwResumeHandle */, NULL);
432
433 // Add them into the list.
434 for (DWORD i = 0 ; i < dwNumServices ; ++i)
435 {
436 AddService(hSCManager, lpServices + i, bHideOSVendorServices);
437 }
438
439 // Cleaning.
440 MemFree(lpServices);
441 CloseServiceHandle(hSCManager);
442
443 return;
444 }
445
446 INT_PTR CALLBACK
447 RequiredServicesDisablingDialogWndProc(HWND hDlg,
448 UINT message,
449 WPARAM wParam,
450 LPARAM lParam)
451 {
452 UNREFERENCED_PARAMETER(lParam);
453
454 switch (message)
455 {
456 case WM_INITDIALOG:
457 {
458 /* Correctly display message strings */
459 LPCWSTR szOSVendor;
460 size_t itemLength = 0;
461 LPWSTR szItem = NULL, szNewItem = NULL;
462
463 szOSVendor = (bIsWindows ? IDS_WINDOWS : IDS_REACTOS);
464
465 itemLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_STATIC_REQSVCSDIS_INFO)) + 1;
466 szItem = (LPWSTR)MemAlloc(0, itemLength * sizeof(WCHAR));
467 GetDlgItemText(hDlg, IDC_STATIC_REQSVCSDIS_INFO, szItem, (int)itemLength);
468 szNewItem = FormatString(szItem, szOSVendor);
469 SetDlgItemText(hDlg, IDC_STATIC_REQSVCSDIS_INFO, szNewItem);
470 MemFree(szNewItem);
471 MemFree(szItem);
472
473 return TRUE;
474 }
475
476 case WM_COMMAND:
477 {
478 switch (LOWORD(wParam))
479 {
480 case IDOK:
481 {
482 if (Button_GetCheck(GetDlgItem(hDlg, IDC_CBX_REQSVCSDIS_NO_MSG_ANYMORE)) == BST_CHECKED)
483 RegisterNoMsgAnymore();
484
485 EndDialog(hDlg, LOWORD(wParam));
486 return TRUE;
487 }
488
489 case IDCANCEL:
490 EndDialog(hDlg, LOWORD(wParam));
491 return TRUE;
492
493 default:
494 //break;
495 return FALSE;
496 }
497 }
498 }
499
500 return FALSE;
501 }
502
503 static BOOL ValidateItem(int index, BOOL bNewState, BOOL bDisplayErrors)
504 {
505 ServiceItem* pSvcItem = NULL;
506
507 LVITEM truc = {};
508 truc.mask = LVIF_PARAM;
509 truc.iItem = index;
510 ListView_GetItem(hServicesListCtrl, &truc);
511
512 // The lParam member must be valid.
513 pSvcItem = reinterpret_cast<ServiceItem*>(truc.lParam);
514 if (!pSvcItem)
515 return FALSE;
516
517 //
518 // Allow modifications only if the service is not a required service for the system,
519 // or allow only the activation of a disabled required service.
520 //
521 BOOL bOldState = !!(ListView_GetCheckState(hServicesListCtrl, truc.iItem /* == index */) % 2);
522
523 if ( !pSvcItem->m_bIsRequired ||
524 (pSvcItem->m_bIsRequired && !pSvcItem->m_bIsEnabled && bOldState == FALSE && bNewState == TRUE) )
525 {
526 if (bOldState == bNewState)
527 return FALSE;
528
529 ListView_SetCheckState(hServicesListCtrl, index, bNewState);
530
531 if (pSvcItem->m_bIsEnabled) // Enabled service.
532 {
533 if (bNewState == FALSE) // To be deactivated.
534 {
535 userModificationsList.AddTail(pSvcItem->m_lpszSvcName);
536 }
537 else if (bNewState == TRUE) // To be reactivated
538 {
539 POSITION it = userModificationsList.Find(pSvcItem->m_lpszSvcName);
540 if (it)
541 {
542 userModificationsList.RemoveAt(it);
543 }
544 else
545 {
546 OutputDebugString(_T("(1) \"WTF: What The Fukhurmajalmahamadahaldeliya ?!\" (The Dictator, Sacha Baron Cohen)\n"));
547 }
548 }
549 }
550 else // Disabled service.
551 {
552 if (bNewState == TRUE) // To be activated.
553 {
554 userModificationsList.AddTail(pSvcItem->m_lpszSvcName);
555 }
556 else if (bNewState == FALSE) // To be redeactivated
557 {
558 POSITION it = userModificationsList.Find(pSvcItem->m_lpszSvcName);
559 if (it)
560 {
561 userModificationsList.RemoveAt(it);
562 }
563 else
564 {
565 OutputDebugString(_T("(2) \"WTF: What The Fukhurmajalmahamadahaldeliya ?!\" (The Dictator, Sacha Baron Cohen)\n"));
566 }
567 }
568 }
569
570 return TRUE;
571 }
572 else
573 {
574 if (bDisplayErrors)
575 {
576 DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_REQUIRED_SERVICES_DISABLING_DIALOG), hServicesPage /* hMainWnd */, RequiredServicesDisablingDialogWndProc);
577 }
578
579 return FALSE;
580 }
581 }
582
583
584 static void
585 UpdateBtnStates(HWND hDlg)
586 {
587 // HWND hTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
588
589 //
590 // "Enable all" / "Disable all" buttons.
591 //
592 // UINT uRootCheckState = TreeView_GetRealSubtreeState(hTree, TVI_ROOT);
593 UINT uRootCheckState = ListView_GetCheckState(hServicesListCtrl, 0);
594 #define OP(a, b) ((a) == (b) ? (a) : 2)
595 int index = 0; // -1 // From the beginning + 1.
596 while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1)
597 {
598 UINT temp = ListView_GetCheckState(hServicesListCtrl, index);
599 uRootCheckState = OP(uRootCheckState, temp);
600 }
601
602 if (uRootCheckState == 0)
603 {
604 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , TRUE );
605 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), FALSE);
606 }
607 else if (uRootCheckState == 1)
608 {
609 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , FALSE);
610 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), TRUE );
611 }
612 else if (uRootCheckState == 2)
613 {
614 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , TRUE);
615 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), TRUE);
616 }
617 else
618 {
619 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , FALSE);
620 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), FALSE);
621 }
622
623 return;
624 }
625
626 extern "C" {
627
628 INT_PTR CALLBACK
629 ServicesPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
630 {
631 UNREFERENCED_PARAMETER(lParam);
632 UNREFERENCED_PARAMETER(wParam);
633
634 switch (message)
635 {
636 case WM_INITDIALOG:
637 {
638 hServicesPage = hDlg;
639 hServicesListCtrl = GetDlgItem(hServicesPage, IDC_SERVICES_LIST);
640
641 //
642 // Correctly display message strings.
643 //
644 LPCWSTR szOSVendor = (bIsWindows ? IDS_MICROSOFT : IDS_REACTOS);
645
646 size_t itemLength = 0;
647 LPWSTR szItem = NULL, szNewItem = NULL;
648
649 itemLength = GetWindowTextLength(GetDlgItem(hServicesPage, IDC_STATIC_SERVICES_WARNING)) + 1;
650 szItem = (LPWSTR)MemAlloc(0, itemLength * sizeof(WCHAR));
651 GetDlgItemText(hServicesPage, IDC_STATIC_SERVICES_WARNING, szItem, (int)itemLength);
652 szNewItem = FormatString(szItem, szOSVendor);
653 SetDlgItemText(hServicesPage, IDC_STATIC_SERVICES_WARNING, szNewItem);
654 MemFree(szNewItem);
655 MemFree(szItem);
656
657 itemLength = GetWindowTextLength(GetDlgItem(hServicesPage, IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS)) + 1;
658 szItem = (LPWSTR)MemAlloc(0, itemLength * sizeof(WCHAR));
659 GetDlgItemText(hServicesPage, IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS, szItem, (int)itemLength);
660 szNewItem = FormatString(szItem, szOSVendor);
661 SetDlgItemText(hServicesPage, IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS, szNewItem);
662 MemFree(szNewItem);
663 MemFree(szItem);
664
665 //
666 // Initialize the styles.
667 //
668 DWORD dwStyle = ListView_GetExtendedListViewStyle(hServicesListCtrl);
669 ListView_SetExtendedListViewStyle(hServicesListCtrl, dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
670 SetWindowTheme(hServicesListCtrl, L"Explorer", NULL);
671
672 //
673 // Initialize the application page's controls.
674 //
675 LVCOLUMN column = {};
676
677 // First column : Service's name.
678 column.mask = LVCF_TEXT | LVCF_WIDTH;
679 column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_SERVICE);
680 column.cx = 150;
681 ListView_InsertColumn(hServicesListCtrl, 0, &column);
682 MemFree(column.pszText);
683
684 // Second column : Whether the service is required or not.
685 column.mask = LVCF_TEXT | LVCF_WIDTH;
686 column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_REQ);
687 column.cx = 60;
688 ListView_InsertColumn(hServicesListCtrl, 1, &column);
689 MemFree(column.pszText);
690
691 // Third column : Service's vendor.
692 column.mask = LVCF_TEXT | LVCF_WIDTH;
693 column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_VENDOR);
694 column.cx = 150;
695 ListView_InsertColumn(hServicesListCtrl, 2, &column);
696 MemFree(column.pszText);
697
698 // Fourth column : Service's status.
699 column.mask = LVCF_TEXT | LVCF_WIDTH;
700 column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_STATUS);
701 column.cx = 60;
702 ListView_InsertColumn(hServicesListCtrl, 3, &column);
703 MemFree(column.pszText);
704
705 // Fifth column : Service's disabled date.
706 column.mask = LVCF_TEXT | LVCF_WIDTH;
707 column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_DATEDISABLED);
708 column.cx = 120;
709 ListView_InsertColumn(hServicesListCtrl, 4, &column);
710 MemFree(column.pszText);
711
712 //
713 // Populate and sort the list.
714 //
715 GetServices();
716 ListView_Sort(hServicesListCtrl, 0);
717 UpdateBtnStates(hDlg);
718
719 // Select the first item.
720 ListView_SetItemState(hServicesListCtrl, 0, LVIS_SELECTED, LVIS_SELECTED);
721
722 return TRUE;
723 }
724
725 case WM_DESTROY:
726 {
727 ClearServicesList();
728 userModificationsList.RemoveAll();
729 return 0;
730 }
731
732 case WM_COMMAND:
733 {
734 switch (LOWORD(wParam))
735 {
736 case IDC_BTN_SERVICES_ACTIVATE:
737 {
738 BOOL bAreThereMods = FALSE;
739
740 int index = -1; // From the beginning.
741 while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1)
742 {
743 bAreThereMods = ValidateItem(index, TRUE, FALSE) || bAreThereMods; // The order is verrrrrry important !!!!
744 }
745
746 if (bAreThereMods)
747 {
748 UpdateBtnStates(hDlg);
749 PropSheet_Changed(GetParent(hServicesPage), hServicesPage);
750 }
751
752 return TRUE;
753 }
754
755 case IDC_BTN_SERVICES_DEACTIVATE:
756 {
757 BOOL bAreThereMods = FALSE;
758
759 int index = -1; // From the beginning.
760 while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1)
761 {
762 bAreThereMods = ValidateItem(index, FALSE, FALSE) || bAreThereMods; // The order is verrrrrry important !!!!
763 }
764
765 if (bAreThereMods)
766 {
767 UpdateBtnStates(hDlg);
768 PropSheet_Changed(GetParent(hServicesPage), hServicesPage);
769 }
770
771 return TRUE;
772 }
773
774 case IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS:
775 {
776 bMaskProprietarySvcs = !bMaskProprietarySvcs;
777 GetServices(bMaskProprietarySvcs);
778 UpdateBtnStates(hDlg);
779
780 return TRUE;
781 }
782
783 default:
784 return FALSE;
785 }
786 return FALSE;
787 }
788
789 case UM_CHECKSTATECHANGE:
790 {
791 BOOL bNewCheckState = !!((ListView_GetCheckState(hServicesListCtrl, int(lParam)) + 1) % 2);
792
793 if (ValidateItem(/*reinterpret_cast<int>*/ int(lParam), bNewCheckState, !HideEssentialServiceWarning()))
794 {
795 UpdateBtnStates(hDlg);
796 PropSheet_Changed(GetParent(hServicesPage), hServicesPage);
797 }
798
799 return TRUE;
800 }
801
802 case WM_NOTIFY:
803 {
804 if (reinterpret_cast<LPNMHDR>(lParam)->hwndFrom == hServicesListCtrl)
805 {
806 switch (reinterpret_cast<LPNMHDR>(lParam)->code)
807 {
808 case NM_CLICK:
809 case NM_RCLICK:
810 {
811 DWORD dwpos = GetMessagePos();
812 LVHITTESTINFO ht = {};
813 ht.pt.x = GET_X_LPARAM(dwpos);
814 ht.pt.y = GET_Y_LPARAM(dwpos);
815 MapWindowPoints(HWND_DESKTOP /*NULL*/, hServicesListCtrl, &ht.pt, 1);
816
817 /*
818 * We use ListView_SubItemHitTest(...) and not ListView_HitTest(...)
819 * because ListView_HitTest(...) returns bad flags when one clicks
820 * on a sub-item different from 0. The flags then contain LVHT_ONITEMSTATEICON
821 * which must not be obviously present in this case.
822 */
823 ListView_SubItemHitTest(hServicesListCtrl, &ht);
824
825 if (LVHT_ONITEMSTATEICON & ht.flags)
826 {
827 PostMessage(hDlg, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.iItem);
828
829 // Disable default behaviour. Needed for the UM_CHECKSTATECHANGE
830 // custom notification to work as expected.
831 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
832 }
833
834 return TRUE;
835 }
836
837 case NM_DBLCLK:
838 case NM_RDBLCLK:
839 {
840 // We deactivate double-clicks.
841 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
842 return TRUE;
843 }
844
845 case LVN_KEYDOWN:
846 {
847 if (reinterpret_cast<LPNMLVKEYDOWN>(lParam)->wVKey == VK_SPACE)
848 {
849 int iItem = ListView_GetSelectionMark(hServicesListCtrl);
850 PostMessage(hDlg, UM_CHECKSTATECHANGE, 0, (LPARAM)iItem);
851
852 // Disable default behaviour. Needed for the UM_CHECKSTATECHANGE
853 // custom notification to work as expected.
854 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
855 }
856
857 return TRUE;
858 }
859
860 case LVN_COLUMNCLICK:
861 {
862 int iSortingColumn = reinterpret_cast<LPNMLISTVIEW>(lParam)->iSubItem;
863
864 ListView_SortEx(hServicesListCtrl, iSortingColumn, iSortedColumn);
865 iSortedColumn = iSortingColumn;
866
867 return TRUE;
868 }
869 }
870 }
871 else
872 {
873 switch (reinterpret_cast<LPNMHDR>(lParam)->code)
874 {
875 case PSN_APPLY:
876 {
877 // Try to apply the modifications to the system.
878 MessageBox(NULL, _T("In Services page: PSN_APPLY"), _T("Info"), MB_ICONINFORMATION);
879
880 /*
881 //
882 // Move this away...
883 //
884 int iRetVal = MessageBox(NULL, _T("Would you really want to modify the configuration of your system ?"), _T("Warning"), MB_ICONWARNING | MB_YESNOCANCEL);
885
886 if (iRetVal == IDYES /\* modifications are OK *\/)
887 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_NOERROR);
888 else if (iRetVal == IDNO /\* modifications are not OK *\/)
889 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_NOERROR);
890 else // if (iRetVal == IDCANCEL) // There was an error...
891 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_INVALID);
892 */
893
894 //
895 // We modify the services which are stored in the user modification list.
896 //
897
898 // 1- Open the Service Control Manager for modifications.
899 SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
900 if (hSCManager != NULL)
901 {
902 LPCWSTR svcName;
903
904 for (POSITION it = userModificationsList.GetHeadPosition(); it; userModificationsList.GetNext(it))
905 {
906 svcName = userModificationsList.GetAt(it);
907
908 // 2- Retrieve a handle to the service.
909 SC_HANDLE hService = OpenServiceW(hSCManager, svcName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
910 if (hService == NULL)
911 {
912 // TODO : Show a message box.
913 continue;
914 }
915
916 DWORD dwBytesNeeded = 0;
917 QueryServiceConfigW(hService, NULL, 0, &dwBytesNeeded);
918 // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
919
920 LPQUERY_SERVICE_CONFIG lpServiceConfig = (LPQUERY_SERVICE_CONFIG)MemAlloc(0, dwBytesNeeded);
921 if (!lpServiceConfig)
922 {
923 CloseServiceHandle(hService);
924 continue; // TODO ? Show a message box...
925 }
926 QueryServiceConfigW(hService, lpServiceConfig, dwBytesNeeded, &dwBytesNeeded);
927
928 if (lpServiceConfig->dwStartType == SERVICE_DISABLED) // We have a disabled service which is becoming to be enabled.
929 {
930 // 3a- Retrieve the properties of the disabled service from the registry.
931 RegistryDisabledServiceItemParams params = {};
932
933 QUERY_REGISTRY_KEYS_TABLE KeysQueryTable[2] = {};
934 KeysQueryTable[0].QueryRoutine = GetRegistryKeyedDisabledServicesQueryRoutine;
935 KeysQueryTable[0].EntryContext = &params;
936 RegQueryRegistryKeys(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", KeysQueryTable, (PVOID)svcName);
937
938 if (bIsWindows && bIsPreVistaOSVersion && !params.bIsPresent)
939 {
940 QUERY_REGISTRY_VALUES_TABLE ValuesQueryTable[2] = {};
941 ValuesQueryTable[0].QueryRoutine = GetRegistryValuedDisabledServicesQueryRoutine;
942 ValuesQueryTable[0].EntryContext = &params;
943 RegQueryRegistryValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", ValuesQueryTable, (PVOID)svcName);
944 }
945
946 if (params.bIsPresent)
947 {
948 // 4a- Modify the service.
949 ChangeServiceConfigW(hService, SERVICE_NO_CHANGE, params.dwStartType, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
950
951 // 5a- Remove the registry entry of the service.
952 if (params.bIsKeyed)
953 {
954 CAtlStringW serviceRegKey(L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services\\");
955 serviceRegKey += svcName;
956 RegDeleteKeyW(HKEY_LOCAL_MACHINE, serviceRegKey);
957
958 /***** HACK for Windows < Vista (e.g. 2000, Xp, 2003...) *****/
959 //
960 // Delete also the valued-entry of the service.
961 //
962 if (bIsWindows && bIsPreVistaOSVersion)
963 {
964 HKEY hSubKey = NULL;
965 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", 0, KEY_SET_VALUE /*KEY_READ*/, &hSubKey) == ERROR_SUCCESS)
966 {
967 RegDeleteValue(hSubKey, svcName);
968 RegCloseKey(hSubKey);
969 }
970 }
971 /*************************************************************/
972 }
973 else
974 {
975 HKEY hSubKey = NULL;
976 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", 0, KEY_SET_VALUE /*KEY_READ*/, &hSubKey) == ERROR_SUCCESS)
977 {
978 RegDeleteValue(hSubKey, svcName);
979 RegCloseKey(hSubKey);
980 }
981 }
982
983 ////////// HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK ///////////
984 // userModificationsList.RemoveAt(it);
985 }
986 else
987 {
988 // Ohoh !! We have a very big problem.
989 MessageBox(NULL, _T("WTF ??"), _T("FATAL ERROR !!!!"), MB_ICONERROR);
990 }
991 }
992 else // We have an enabled service which is becoming to be disabled.
993 {
994 // 3b- Retrieve the local time of disabling.
995 SYSTEMTIME disableDate = {};
996 GetLocalTime(&disableDate);
997
998 // 4b- Modify the service.
999 ChangeServiceConfigW(hService, SERVICE_NO_CHANGE, SERVICE_DISABLED, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1000
1001 // 5b- Register the service into the registry.
1002 CAtlStringW serviceRegKey(L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services\\");
1003 serviceRegKey += svcName;
1004 HKEY hSubKey = NULL;
1005 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, serviceRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
1006 {
1007 RegSetDWORDValue(hSubKey, NULL, svcName, FALSE, lpServiceConfig->dwStartType);
1008
1009 #if 1 // DisableDate
1010 RegSetDWORDValue(hSubKey, NULL, L"DAY" , FALSE, disableDate.wDay );
1011 RegSetDWORDValue(hSubKey, NULL, L"HOUR" , FALSE, disableDate.wHour );
1012 RegSetDWORDValue(hSubKey, NULL, L"MINUTE", FALSE, disableDate.wMinute);
1013 RegSetDWORDValue(hSubKey, NULL, L"MONTH" , FALSE, disableDate.wMonth );
1014 RegSetDWORDValue(hSubKey, NULL, L"SECOND", FALSE, disableDate.wSecond);
1015 RegSetDWORDValue(hSubKey, NULL, L"YEAR" , FALSE, disableDate.wYear );
1016 #endif
1017
1018 RegCloseKey(hSubKey);
1019 }
1020
1021 /***** HACK for Windows < Vista (e.g. 2000, Xp, 2003...) *****/
1022 //
1023 // Save also a valued-entry for the service.
1024 //
1025 if (bIsWindows && bIsPreVistaOSVersion)
1026 {
1027 RegSetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", svcName, TRUE, lpServiceConfig->dwStartType);
1028 }
1029 /*************************************************************/
1030
1031 ////////// HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK ///////////
1032 // userModificationsList.RemoveAt(it);
1033 }
1034
1035 MemFree(lpServiceConfig);
1036 CloseServiceHandle(hService);
1037 }
1038
1039 //////////// HACK HACK !!!! ////////////
1040 userModificationsList.RemoveAll();
1041 ////////////////////////////////////////
1042
1043 CloseServiceHandle(hSCManager);
1044
1045
1046 //// PropSheet_UnChanged(GetParent(hServicesPage), hServicesPage); ////
1047 PropSheet_CancelToClose(GetParent(hDlg));
1048
1049 /* Modifications are OK */
1050 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_NOERROR);
1051 }
1052 else
1053 {
1054 MessageBox(hDlg, _T("Impossible to open the SC manager..."), _T("Error"), MB_ICONERROR);
1055
1056 // There was an error...
1057 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_INVALID);
1058 }
1059
1060 GetServices(bMaskProprietarySvcs);
1061 UpdateBtnStates(hDlg);
1062
1063 return TRUE;
1064 }
1065
1066 case PSN_HELP:
1067 {
1068 MessageBox(hServicesPage, _T("Help not implemented yet!"), _T("Help"), MB_ICONINFORMATION | MB_OK);
1069 return TRUE;
1070 }
1071
1072 case PSN_KILLACTIVE: // Is going to lose activation.
1073 {
1074 // Changes are always valid of course.
1075 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, FALSE);
1076 return TRUE;
1077 }
1078
1079 case PSN_QUERYCANCEL:
1080 {
1081 // RefreshStartupList();
1082
1083 // Allows cancellation.
1084 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, FALSE);
1085
1086 return TRUE;
1087 }
1088
1089 case PSN_QUERYINITIALFOCUS:
1090 {
1091 // Give the focus on and select the first item.
1092 ListView_SetItemState(hServicesListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
1093
1094 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, (LONG_PTR)hServicesListCtrl);
1095 return TRUE;
1096 }
1097
1098 //
1099 // DO NOT TOUCH THESE NEXT MESSAGES, THEY ARE OK LIKE THIS...
1100 //
1101 case PSN_RESET: // Perform final cleaning, called before WM_DESTROY.
1102 return TRUE;
1103
1104 case PSN_SETACTIVE: // Is going to gain activation.
1105 {
1106 SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, 0);
1107 return TRUE;
1108 }
1109
1110 default:
1111 break;
1112 }
1113 }
1114 }
1115
1116 default:
1117 return FALSE;
1118 }
1119
1120 return FALSE;
1121 }
1122
1123 }