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 = ¶ms; 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 = ¶ms; 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(¶ms.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 = ¶ms; 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 = ¶ms; 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 } 1124