/* * PROJECT: ReactOS Applications * LICENSE: LGPL - See COPYING in the top level directory * FILE: base/applications/msconfig_new/srvpage.cpp * PURPOSE: Services page message handler * COPYRIGHT: Copyright 2005-2006 Christoph von Wittich * Copyright 2011-2012 Hermes BELUSCA - MAITO * */ #include "precomp.h" #include "utils.h" #include "regutils.h" #include "stringutils.h" // #include "CmdLineParser.h" #include "listview.h" #include "uxthemesupp.h" #include // #include #include #include static HWND hServicesPage = NULL; static HWND hServicesListCtrl = NULL; static int iSortedColumn = 0; static BOOL bMaskProprietarySvcs = FALSE; DWORD GetServicesActivation(VOID) { DWORD dwServices = 0; RegGetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\state", L"services", &dwServices); return dwServices; } BOOL SetServicesActivation(DWORD dwState) { return (RegSetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\state", L"services", TRUE, dwState) == ERROR_SUCCESS); } static BOOL RegisterNoMsgAnymore(VOID) { return (RegSetDWORDValue(HKEY_CURRENT_USER /* HKEY_LOCAL_MACHINE ?? */, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig", L"HideEssentialServiceWarning", TRUE, 1) == ERROR_SUCCESS); } BOOL HideEssentialServiceWarning(VOID) { BOOL bRetVal = FALSE; DWORD dwValue = 0; bRetVal = ( (RegGetDWORDValue(HKEY_CURRENT_USER /* HKEY_LOCAL_MACHINE ?? */, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig", L"HideEssentialServiceWarning", &dwValue) == ERROR_SUCCESS) && (dwValue == 1) ); return bRetVal; } struct ServiceItem { ServiceItem(const LPCWSTR lpszSvcName, BOOL bIsEnabled, BOOL bIsRequired) : m_lpszSvcName(lpszSvcName), m_bIsEnabled(bIsEnabled), m_bIsRequired(bIsRequired) { } ~ServiceItem(void) { } CAtlStringW m_lpszSvcName; BOOL m_bIsEnabled; BOOL m_bIsRequired; }; struct RegistryDisabledServiceItemParams { BOOL bIsPresent; BOOL bIsKeyed; // bIsKeyed == TRUE for a keyed-registered service ; == FALSE for a valued-registered service. DWORD dwStartType; SYSTEMTIME time; }; static CAtlList userModificationsList; QUERY_REGISTRY_VALUES_ROUTINE(GetRegistryValuedDisabledServicesQueryRoutine) { UNREFERENCED_PARAMETER(KeyName); UNREFERENCED_PARAMETER(ValueData); UNREFERENCED_PARAMETER(ValueLength); if (!EntryContext) return ERROR_SUCCESS; RegistryDisabledServiceItemParams* pContextParams = (RegistryDisabledServiceItemParams*)EntryContext; if (pContextParams->bIsPresent) return ERROR_SUCCESS; if ( (hRootKey == HKEY_LOCAL_MACHINE) && (ValueType == REG_DWORD) && (ValueLength == sizeof(DWORD)) && (wcsicmp((LPCWSTR)Context, ValueName) == 0) ) { pContextParams->bIsPresent = TRUE; pContextParams->bIsKeyed = FALSE; pContextParams->dwStartType = *(DWORD*)ValueData; // pContextParams->time = {}; } else { pContextParams->bIsPresent = FALSE; pContextParams->bIsKeyed = FALSE; pContextParams->dwStartType = 0; // pContextParams->time = {}; } return ERROR_SUCCESS; } QUERY_REGISTRY_KEYS_ROUTINE(GetRegistryKeyedDisabledServicesQueryRoutine) { UNREFERENCED_PARAMETER(hRootKey); UNREFERENCED_PARAMETER(KeyName); if (!EntryContext) return ERROR_SUCCESS; RegistryDisabledServiceItemParams* pContextParams = (RegistryDisabledServiceItemParams*)EntryContext; if (pContextParams->bIsPresent) return ERROR_SUCCESS; DWORD dwType = 0, dwBufSize = 0; // Be careful, the order of the operations in the comparison is very important. if ( (wcsicmp((LPCWSTR)Context, SubKeyName) == 0) && (RegQueryValueEx(hOpenedSubKey, /* ValueName == */ SubKeyName, NULL, &dwType, NULL, &dwBufSize) == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwBufSize == sizeof(DWORD)) ) { #if 1 // DisableDate SYSTEMTIME disableDate = {}; DWORD dwRegData = 0; dwRegData = 0; RegGetDWORDValue(hOpenedSubKey, NULL, L"DAY", &dwRegData); disableDate.wDay = LOWORD(dwRegData); dwRegData = 0; RegGetDWORDValue(hOpenedSubKey, NULL, L"HOUR", &dwRegData); disableDate.wHour = LOWORD(dwRegData); dwRegData = 0; RegGetDWORDValue(hOpenedSubKey, NULL, L"MINUTE", &dwRegData); disableDate.wMinute = LOWORD(dwRegData); dwRegData = 0; RegGetDWORDValue(hOpenedSubKey, NULL, L"MONTH", &dwRegData); disableDate.wMonth = LOWORD(dwRegData); dwRegData = 0; RegGetDWORDValue(hOpenedSubKey, NULL, L"SECOND", &dwRegData); disableDate.wSecond = LOWORD(dwRegData); dwRegData = 0; RegGetDWORDValue(hOpenedSubKey, NULL, L"YEAR", &dwRegData); disableDate.wYear = LOWORD(dwRegData); #endif DWORD dwStartType = 0; RegGetDWORDValue(hOpenedSubKey, NULL, SubKeyName /* Service name */, &dwStartType); pContextParams->bIsPresent = TRUE; pContextParams->bIsKeyed = TRUE; pContextParams->dwStartType = dwStartType; pContextParams->time = disableDate; } else { pContextParams->bIsPresent = FALSE; pContextParams->bIsKeyed = TRUE; pContextParams->dwStartType = 0; // pContextParams->time = {}; } return ERROR_SUCCESS; } static void AddService(SC_HANDLE hSCManager, LPENUM_SERVICE_STATUS_PROCESS Service, BOOL bHideOSVendorServices) { // // Retrieve a handle to the service. // SC_HANDLE hService = OpenServiceW(hSCManager, Service->lpServiceName, SERVICE_QUERY_CONFIG); if (hService == NULL) return; DWORD dwBytesNeeded = 0; QueryServiceConfigW(hService, NULL, 0, &dwBytesNeeded); // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) LPQUERY_SERVICE_CONFIG lpServiceConfig = (LPQUERY_SERVICE_CONFIG)MemAlloc(0, dwBytesNeeded); if (!lpServiceConfig) { CloseServiceHandle(hService); return; } QueryServiceConfigW(hService, lpServiceConfig, dwBytesNeeded, &dwBytesNeeded); // // Get the service's vendor... // LPWSTR lpszVendor = NULL; { // Isolate only the executable path, without any arguments. // TODO: Correct at the level of CmdLineToArgv the potential bug when lpszFilename == NULL. #if 0 // Disabled until CmdLineToArgv is included unsigned int argc = 0; LPWSTR* argv = NULL; CmdLineToArgv(lpServiceConfig->lpBinaryPathName, &argc, &argv, L" \t"); if (argc >= 1 && argv[0]) lpszVendor = GetExecutableVendor(argv[0]); #else // Hackish solution taken from the original srvpage.c. // Will be removed after CmdLineToArgv is introduced. WCHAR FileName[MAX_PATH]; memset(&FileName, 0, sizeof(FileName)); if (wcscspn(lpServiceConfig->lpBinaryPathName, L"\"")) { wcsncpy(FileName, lpServiceConfig->lpBinaryPathName, wcscspn(lpServiceConfig->lpBinaryPathName, L" ") ); } else { wcscpy(FileName, lpServiceConfig->lpBinaryPathName); } lpszVendor = GetExecutableVendor(FileName); #endif if (!lpszVendor) lpszVendor = LoadResourceString(hInst, IDS_UNKNOWN); #if 0 MemFree(argv); #endif } // ...and display or not the Microsoft / ReactOS services. BOOL bContinue = TRUE; if (bHideOSVendorServices) { if (FindSubStrI(lpszVendor, bIsWindows ? IDS_MICROSOFT : IDS_REACTOS)) bContinue = FALSE; } if (bContinue) { BOOL bIsServiceEnabled = (lpServiceConfig->dwStartType != SERVICE_DISABLED); BOOL bAddServiceToList = FALSE; BOOL bIsModifiedService = FALSE; RegistryDisabledServiceItemParams params = {}; // // Try to look into the user modifications list... // POSITION it = userModificationsList.Find(Service->lpServiceName); if (it) { bAddServiceToList = TRUE; bIsModifiedService = TRUE; } // // ...if not found, try to find if the disabled service is in the registry. // if (!bAddServiceToList) { if (!bIsServiceEnabled) { QUERY_REGISTRY_KEYS_TABLE KeysQueryTable[2] = {}; KeysQueryTable[0].QueryRoutine = GetRegistryKeyedDisabledServicesQueryRoutine; KeysQueryTable[0].EntryContext = ¶ms; RegQueryRegistryKeys(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", KeysQueryTable, Service->lpServiceName); bAddServiceToList = params.bIsPresent; if (bIsWindows && bIsPreVistaOSVersion && !bAddServiceToList) { QUERY_REGISTRY_VALUES_TABLE ValuesQueryTable[2] = {}; ValuesQueryTable[0].QueryRoutine = GetRegistryValuedDisabledServicesQueryRoutine; ValuesQueryTable[0].EntryContext = ¶ms; RegQueryRegistryValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", ValuesQueryTable, Service->lpServiceName); bAddServiceToList = params.bIsPresent; } } else { bAddServiceToList = TRUE; } } if (bAddServiceToList) { // // Check if service is required by the system. // BOOL bIsRequired = FALSE; dwBytesNeeded = 0; QueryServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, NULL, 0, &dwBytesNeeded); // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) LPSERVICE_FAILURE_ACTIONS lpServiceFailureActions = (LPSERVICE_FAILURE_ACTIONS)MemAlloc(0, dwBytesNeeded); if (!lpServiceFailureActions) { MemFree(lpszVendor); MemFree(lpServiceConfig); CloseServiceHandle(hService); return; } QueryServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)lpServiceFailureActions, dwBytesNeeded, &dwBytesNeeded); // In Microsoft's MSConfig, things are done just like that!! (extracted string values from msconfig.exe) if ( ( wcsicmp(Service->lpServiceName, L"rpcss" ) == 0 || wcsicmp(Service->lpServiceName, L"rpclocator") == 0 || wcsicmp(Service->lpServiceName, L"dcomlaunch") == 0 ) || ( lpServiceFailureActions && (lpServiceFailureActions->cActions >= 1) && (lpServiceFailureActions->lpsaActions[0].Type == SC_ACTION_REBOOT) ) ) // We add also this test, which corresponds to real life. { bIsRequired = TRUE; } MemFree(lpServiceFailureActions); // // Add the service into the list. // LVITEM item = {}; item.mask = LVIF_TEXT | LVIF_PARAM; item.pszText = Service->lpDisplayName; item.lParam = reinterpret_cast(new ServiceItem(Service->lpServiceName, bIsServiceEnabled, bIsRequired)); item.iItem = ListView_InsertItem(hServicesListCtrl, &item); if (bIsRequired) { LPWSTR lpszYes = LoadResourceString(hInst, IDS_YES); ListView_SetItemText(hServicesListCtrl, item.iItem, 1, lpszYes); MemFree(lpszYes); } ListView_SetItemText(hServicesListCtrl, item.iItem, 2, lpszVendor); LPWSTR lpszStatus = LoadResourceString(hInst, ((Service->ServiceStatusProcess.dwCurrentState == SERVICE_STOPPED) ? IDS_SERVICES_STATUS_STOPPED : IDS_SERVICES_STATUS_RUNNING)); ListView_SetItemText(hServicesListCtrl, item.iItem, 3, lpszStatus); MemFree(lpszStatus); if (!bIsServiceEnabled) { LPWSTR lpszUnknown = LoadResourceString(hInst, IDS_UNKNOWN); LPWSTR lpszDisableDate = FormatDateTime(¶ms.time); ListView_SetItemText(hServicesListCtrl, item.iItem, 4, (lpszDisableDate ? lpszDisableDate : lpszUnknown)); FreeDateTime(lpszDisableDate); MemFree(lpszUnknown); } ListView_SetCheckState(hServicesListCtrl, item.iItem, (!bIsModifiedService ? bIsServiceEnabled : !bIsServiceEnabled)); } } MemFree(lpszVendor); MemFree(lpServiceConfig); CloseServiceHandle(hService); return; } static void ClearServicesList(void) { LVITEM lvitem = {}; lvitem.mask = LVIF_PARAM; lvitem.iItem = -1; // From the beginning. while ((lvitem.iItem = ListView_GetNextItem(hServicesListCtrl, lvitem.iItem, LVNI_ALL)) != -1) { ListView_GetItem(hServicesListCtrl, &lvitem); delete reinterpret_cast(lvitem.lParam); lvitem.lParam = NULL; } ListView_DeleteAllItems(hServicesListCtrl); return; } static void GetServices(BOOL bHideOSVendorServices = FALSE) { // // First of all, clear the list. // ClearServicesList(); // // Now, we can list the services. // // Open the Service Control Manager. SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); if (hSCManager == NULL) return; // Enumerate all the Win32 services. DWORD dwBytesNeeded = 0; DWORD dwNumServices = 0; // DWORD dwResumeHandle = 0; EnumServicesStatusExW(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded, &dwNumServices, NULL /* &dwResumeHandle */, NULL); // if (GetLastError() == ERROR_MORE_DATA) LPENUM_SERVICE_STATUS_PROCESS lpServices = (LPENUM_SERVICE_STATUS_PROCESS)MemAlloc(0, dwBytesNeeded); if (!lpServices) { CloseServiceHandle(hSCManager); return; } EnumServicesStatusExW(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)lpServices, dwBytesNeeded, &dwBytesNeeded, &dwNumServices, NULL /* &dwResumeHandle */, NULL); // Add them into the list. for (DWORD i = 0 ; i < dwNumServices ; ++i) { AddService(hSCManager, lpServices + i, bHideOSVendorServices); } // Cleaning. MemFree(lpServices); CloseServiceHandle(hSCManager); return; } INT_PTR CALLBACK RequiredServicesDisablingDialogWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: { /* Correctly display message strings */ LPCWSTR szOSVendor; size_t itemLength = 0; LPWSTR szItem = NULL, szNewItem = NULL; szOSVendor = (bIsWindows ? IDS_WINDOWS : IDS_REACTOS); itemLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_STATIC_REQSVCSDIS_INFO)) + 1; szItem = (LPWSTR)MemAlloc(0, itemLength * sizeof(WCHAR)); GetDlgItemText(hDlg, IDC_STATIC_REQSVCSDIS_INFO, szItem, (int)itemLength); szNewItem = FormatString(szItem, szOSVendor); SetDlgItemText(hDlg, IDC_STATIC_REQSVCSDIS_INFO, szNewItem); MemFree(szNewItem); MemFree(szItem); return TRUE; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDOK: { if (Button_GetCheck(GetDlgItem(hDlg, IDC_CBX_REQSVCSDIS_NO_MSG_ANYMORE)) == BST_CHECKED) RegisterNoMsgAnymore(); EndDialog(hDlg, LOWORD(wParam)); return TRUE; } case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); return TRUE; default: //break; return FALSE; } } } return FALSE; } static BOOL ValidateItem(int index, BOOL bNewState, BOOL bDisplayErrors) { ServiceItem* pSvcItem = NULL; LVITEM truc = {}; truc.mask = LVIF_PARAM; truc.iItem = index; ListView_GetItem(hServicesListCtrl, &truc); // The lParam member must be valid. pSvcItem = reinterpret_cast(truc.lParam); if (!pSvcItem) return FALSE; // // Allow modifications only if the service is not a required service for the system, // or allow only the activation of a disabled required service. // BOOL bOldState = !!(ListView_GetCheckState(hServicesListCtrl, truc.iItem /* == index */) % 2); if ( !pSvcItem->m_bIsRequired || (pSvcItem->m_bIsRequired && !pSvcItem->m_bIsEnabled && bOldState == FALSE && bNewState == TRUE) ) { if (bOldState == bNewState) return FALSE; ListView_SetCheckState(hServicesListCtrl, index, bNewState); if (pSvcItem->m_bIsEnabled) // Enabled service. { if (bNewState == FALSE) // To be deactivated. { userModificationsList.AddTail(pSvcItem->m_lpszSvcName); } else if (bNewState == TRUE) // To be reactivated { POSITION it = userModificationsList.Find(pSvcItem->m_lpszSvcName); if (it) { userModificationsList.RemoveAt(it); } else { OutputDebugString(_T("(1) \"WTF: What The Fukhurmajalmahamadahaldeliya ?!\" (The Dictator, Sacha Baron Cohen)\n")); } } } else // Disabled service. { if (bNewState == TRUE) // To be activated. { userModificationsList.AddTail(pSvcItem->m_lpszSvcName); } else if (bNewState == FALSE) // To be redeactivated { POSITION it = userModificationsList.Find(pSvcItem->m_lpszSvcName); if (it) { userModificationsList.RemoveAt(it); } else { OutputDebugString(_T("(2) \"WTF: What The Fukhurmajalmahamadahaldeliya ?!\" (The Dictator, Sacha Baron Cohen)\n")); } } } return TRUE; } else { if (bDisplayErrors) { DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_REQUIRED_SERVICES_DISABLING_DIALOG), hServicesPage /* hMainWnd */, RequiredServicesDisablingDialogWndProc); } return FALSE; } } static void UpdateBtnStates(HWND hDlg) { // HWND hTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE); // // "Enable all" / "Disable all" buttons. // // UINT uRootCheckState = TreeView_GetRealSubtreeState(hTree, TVI_ROOT); UINT uRootCheckState = ListView_GetCheckState(hServicesListCtrl, 0); #define OP(a, b) ((a) == (b) ? (a) : 2) int index = 0; // -1 // From the beginning + 1. while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1) { UINT temp = ListView_GetCheckState(hServicesListCtrl, index); uRootCheckState = OP(uRootCheckState, temp); } if (uRootCheckState == 0) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , TRUE ); EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), FALSE); } else if (uRootCheckState == 1) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , FALSE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), TRUE ); } else if (uRootCheckState == 2) { EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , TRUE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), TRUE); } else { EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_ACTIVATE) , FALSE); EnableWindow(GetDlgItem(hDlg, IDC_BTN_SERVICES_DEACTIVATE), FALSE); } return; } extern "C" { INT_PTR CALLBACK ServicesPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(wParam); switch (message) { case WM_INITDIALOG: { hServicesPage = hDlg; hServicesListCtrl = GetDlgItem(hServicesPage, IDC_SERVICES_LIST); // // Correctly display message strings. // LPCWSTR szOSVendor = (bIsWindows ? IDS_MICROSOFT : IDS_REACTOS); size_t itemLength = 0; LPWSTR szItem = NULL, szNewItem = NULL; itemLength = GetWindowTextLength(GetDlgItem(hServicesPage, IDC_STATIC_SERVICES_WARNING)) + 1; szItem = (LPWSTR)MemAlloc(0, itemLength * sizeof(WCHAR)); GetDlgItemText(hServicesPage, IDC_STATIC_SERVICES_WARNING, szItem, (int)itemLength); szNewItem = FormatString(szItem, szOSVendor); SetDlgItemText(hServicesPage, IDC_STATIC_SERVICES_WARNING, szNewItem); MemFree(szNewItem); MemFree(szItem); itemLength = GetWindowTextLength(GetDlgItem(hServicesPage, IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS)) + 1; szItem = (LPWSTR)MemAlloc(0, itemLength * sizeof(WCHAR)); GetDlgItemText(hServicesPage, IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS, szItem, (int)itemLength); szNewItem = FormatString(szItem, szOSVendor); SetDlgItemText(hServicesPage, IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS, szNewItem); MemFree(szNewItem); MemFree(szItem); // // Initialize the styles. // DWORD dwStyle = ListView_GetExtendedListViewStyle(hServicesListCtrl); ListView_SetExtendedListViewStyle(hServicesListCtrl, dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); SetWindowTheme(hServicesListCtrl, L"Explorer", NULL); // // Initialize the application page's controls. // LVCOLUMN column = {}; // First column : Service's name. column.mask = LVCF_TEXT | LVCF_WIDTH; column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_SERVICE); column.cx = 150; ListView_InsertColumn(hServicesListCtrl, 0, &column); MemFree(column.pszText); // Second column : Whether the service is required or not. column.mask = LVCF_TEXT | LVCF_WIDTH; column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_REQ); column.cx = 60; ListView_InsertColumn(hServicesListCtrl, 1, &column); MemFree(column.pszText); // Third column : Service's vendor. column.mask = LVCF_TEXT | LVCF_WIDTH; column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_VENDOR); column.cx = 150; ListView_InsertColumn(hServicesListCtrl, 2, &column); MemFree(column.pszText); // Fourth column : Service's status. column.mask = LVCF_TEXT | LVCF_WIDTH; column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_STATUS); column.cx = 60; ListView_InsertColumn(hServicesListCtrl, 3, &column); MemFree(column.pszText); // Fifth column : Service's disabled date. column.mask = LVCF_TEXT | LVCF_WIDTH; column.pszText = LoadResourceString(hInst, IDS_SERVICES_COLUMN_DATEDISABLED); column.cx = 120; ListView_InsertColumn(hServicesListCtrl, 4, &column); MemFree(column.pszText); // // Populate and sort the list. // GetServices(); ListView_Sort(hServicesListCtrl, 0); UpdateBtnStates(hDlg); // Select the first item. ListView_SetItemState(hServicesListCtrl, 0, LVIS_SELECTED, LVIS_SELECTED); return TRUE; } case WM_DESTROY: { ClearServicesList(); userModificationsList.RemoveAll(); return 0; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_BTN_SERVICES_ACTIVATE: { BOOL bAreThereMods = FALSE; int index = -1; // From the beginning. while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1) { bAreThereMods = ValidateItem(index, TRUE, FALSE) || bAreThereMods; // The order is verrrrrry important !!!! } if (bAreThereMods) { UpdateBtnStates(hDlg); PropSheet_Changed(GetParent(hServicesPage), hServicesPage); } return TRUE; } case IDC_BTN_SERVICES_DEACTIVATE: { BOOL bAreThereMods = FALSE; int index = -1; // From the beginning. while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1) { bAreThereMods = ValidateItem(index, FALSE, FALSE) || bAreThereMods; // The order is verrrrrry important !!!! } if (bAreThereMods) { UpdateBtnStates(hDlg); PropSheet_Changed(GetParent(hServicesPage), hServicesPage); } return TRUE; } case IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS: { bMaskProprietarySvcs = !bMaskProprietarySvcs; GetServices(bMaskProprietarySvcs); UpdateBtnStates(hDlg); return TRUE; } default: return FALSE; } return FALSE; } case UM_CHECKSTATECHANGE: { BOOL bNewCheckState = !!((ListView_GetCheckState(hServicesListCtrl, int(lParam)) + 1) % 2); if (ValidateItem(/*reinterpret_cast*/ int(lParam), bNewCheckState, !HideEssentialServiceWarning())) { UpdateBtnStates(hDlg); PropSheet_Changed(GetParent(hServicesPage), hServicesPage); } return TRUE; } case WM_NOTIFY: { if (reinterpret_cast(lParam)->hwndFrom == hServicesListCtrl) { switch (reinterpret_cast(lParam)->code) { case NM_CLICK: case NM_RCLICK: { DWORD dwpos = GetMessagePos(); LVHITTESTINFO ht = {}; ht.pt.x = GET_X_LPARAM(dwpos); ht.pt.y = GET_Y_LPARAM(dwpos); MapWindowPoints(HWND_DESKTOP /*NULL*/, hServicesListCtrl, &ht.pt, 1); /* * We use ListView_SubItemHitTest(...) and not ListView_HitTest(...) * because ListView_HitTest(...) returns bad flags when one clicks * on a sub-item different from 0. The flags then contain LVHT_ONITEMSTATEICON * which must not be obviously present in this case. */ ListView_SubItemHitTest(hServicesListCtrl, &ht); if (LVHT_ONITEMSTATEICON & ht.flags) { PostMessage(hDlg, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.iItem); // Disable default behaviour. Needed for the UM_CHECKSTATECHANGE // custom notification to work as expected. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); } return TRUE; } case NM_DBLCLK: case NM_RDBLCLK: { // We deactivate double-clicks. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); return TRUE; } case LVN_KEYDOWN: { if (reinterpret_cast(lParam)->wVKey == VK_SPACE) { int iItem = ListView_GetSelectionMark(hServicesListCtrl); PostMessage(hDlg, UM_CHECKSTATECHANGE, 0, (LPARAM)iItem); // Disable default behaviour. Needed for the UM_CHECKSTATECHANGE // custom notification to work as expected. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); } return TRUE; } case LVN_COLUMNCLICK: { int iSortingColumn = reinterpret_cast(lParam)->iSubItem; ListView_SortEx(hServicesListCtrl, iSortingColumn, iSortedColumn); iSortedColumn = iSortingColumn; return TRUE; } } } else { switch (reinterpret_cast(lParam)->code) { case PSN_APPLY: { // Try to apply the modifications to the system. MessageBox(NULL, _T("In Services page: PSN_APPLY"), _T("Info"), MB_ICONINFORMATION); /* // // Move this away... // int iRetVal = MessageBox(NULL, _T("Would you really want to modify the configuration of your system ?"), _T("Warning"), MB_ICONWARNING | MB_YESNOCANCEL); if (iRetVal == IDYES /\* modifications are OK *\/) SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_NOERROR); else if (iRetVal == IDNO /\* modifications are not OK *\/) SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_NOERROR); else // if (iRetVal == IDCANCEL) // There was an error... SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_INVALID); */ // // We modify the services which are stored in the user modification list. // // 1- Open the Service Control Manager for modifications. SC_HANDLE hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCManager != NULL) { LPCWSTR svcName; for (POSITION it = userModificationsList.GetHeadPosition(); it; userModificationsList.GetNext(it)) { svcName = userModificationsList.GetAt(it); // 2- Retrieve a handle to the service. SC_HANDLE hService = OpenServiceW(hSCManager, svcName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG); if (hService == NULL) { // TODO : Show a message box. continue; } DWORD dwBytesNeeded = 0; QueryServiceConfigW(hService, NULL, 0, &dwBytesNeeded); // if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) LPQUERY_SERVICE_CONFIG lpServiceConfig = (LPQUERY_SERVICE_CONFIG)MemAlloc(0, dwBytesNeeded); if (!lpServiceConfig) { CloseServiceHandle(hService); continue; // TODO ? Show a message box... } QueryServiceConfigW(hService, lpServiceConfig, dwBytesNeeded, &dwBytesNeeded); if (lpServiceConfig->dwStartType == SERVICE_DISABLED) // We have a disabled service which is becoming to be enabled. { // 3a- Retrieve the properties of the disabled service from the registry. RegistryDisabledServiceItemParams params = {}; QUERY_REGISTRY_KEYS_TABLE KeysQueryTable[2] = {}; KeysQueryTable[0].QueryRoutine = GetRegistryKeyedDisabledServicesQueryRoutine; KeysQueryTable[0].EntryContext = ¶ms; RegQueryRegistryKeys(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", KeysQueryTable, (PVOID)svcName); if (bIsWindows && bIsPreVistaOSVersion && !params.bIsPresent) { QUERY_REGISTRY_VALUES_TABLE ValuesQueryTable[2] = {}; ValuesQueryTable[0].QueryRoutine = GetRegistryValuedDisabledServicesQueryRoutine; ValuesQueryTable[0].EntryContext = ¶ms; RegQueryRegistryValues(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", ValuesQueryTable, (PVOID)svcName); } if (params.bIsPresent) { // 4a- Modify the service. ChangeServiceConfigW(hService, SERVICE_NO_CHANGE, params.dwStartType, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); // 5a- Remove the registry entry of the service. if (params.bIsKeyed) { CAtlStringW serviceRegKey(L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services\\"); serviceRegKey += svcName; RegDeleteKeyW(HKEY_LOCAL_MACHINE, serviceRegKey); /***** HACK for Windows < Vista (e.g. 2000, Xp, 2003...) *****/ // // Delete also the valued-entry of the service. // if (bIsWindows && bIsPreVistaOSVersion) { HKEY hSubKey = NULL; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", 0, KEY_SET_VALUE /*KEY_READ*/, &hSubKey) == ERROR_SUCCESS) { RegDeleteValue(hSubKey, svcName); RegCloseKey(hSubKey); } } /*************************************************************/ } else { HKEY hSubKey = NULL; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", 0, KEY_SET_VALUE /*KEY_READ*/, &hSubKey) == ERROR_SUCCESS) { RegDeleteValue(hSubKey, svcName); RegCloseKey(hSubKey); } } ////////// HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK /////////// // userModificationsList.RemoveAt(it); } else { // Ohoh !! We have a very big problem. MessageBox(NULL, _T("WTF ??"), _T("FATAL ERROR !!!!"), MB_ICONERROR); } } else // We have an enabled service which is becoming to be disabled. { // 3b- Retrieve the local time of disabling. SYSTEMTIME disableDate = {}; GetLocalTime(&disableDate); // 4b- Modify the service. ChangeServiceConfigW(hService, SERVICE_NO_CHANGE, SERVICE_DISABLED, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); // 5b- Register the service into the registry. CAtlStringW serviceRegKey(L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services\\"); serviceRegKey += svcName; HKEY hSubKey = NULL; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, serviceRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL) == ERROR_SUCCESS) { RegSetDWORDValue(hSubKey, NULL, svcName, FALSE, lpServiceConfig->dwStartType); #if 1 // DisableDate RegSetDWORDValue(hSubKey, NULL, L"DAY" , FALSE, disableDate.wDay ); RegSetDWORDValue(hSubKey, NULL, L"HOUR" , FALSE, disableDate.wHour ); RegSetDWORDValue(hSubKey, NULL, L"MINUTE", FALSE, disableDate.wMinute); RegSetDWORDValue(hSubKey, NULL, L"MONTH" , FALSE, disableDate.wMonth ); RegSetDWORDValue(hSubKey, NULL, L"SECOND", FALSE, disableDate.wSecond); RegSetDWORDValue(hSubKey, NULL, L"YEAR" , FALSE, disableDate.wYear ); #endif RegCloseKey(hSubKey); } /***** HACK for Windows < Vista (e.g. 2000, Xp, 2003...) *****/ // // Save also a valued-entry for the service. // if (bIsWindows && bIsPreVistaOSVersion) { RegSetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\services", svcName, TRUE, lpServiceConfig->dwStartType); } /*************************************************************/ ////////// HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK /////////// // userModificationsList.RemoveAt(it); } MemFree(lpServiceConfig); CloseServiceHandle(hService); } //////////// HACK HACK !!!! //////////// userModificationsList.RemoveAll(); //////////////////////////////////////// CloseServiceHandle(hSCManager); //// PropSheet_UnChanged(GetParent(hServicesPage), hServicesPage); //// PropSheet_CancelToClose(GetParent(hDlg)); /* Modifications are OK */ SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_NOERROR); } else { MessageBox(hDlg, _T("Impossible to open the SC manager..."), _T("Error"), MB_ICONERROR); // There was an error... SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, PSNRET_INVALID); } GetServices(bMaskProprietarySvcs); UpdateBtnStates(hDlg); return TRUE; } case PSN_HELP: { MessageBox(hServicesPage, _T("Help not implemented yet!"), _T("Help"), MB_ICONINFORMATION | MB_OK); return TRUE; } case PSN_KILLACTIVE: // Is going to lose activation. { // Changes are always valid of course. SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, FALSE); return TRUE; } case PSN_QUERYCANCEL: { // RefreshStartupList(); // Allows cancellation. SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, FALSE); return TRUE; } case PSN_QUERYINITIALFOCUS: { // Give the focus on and select the first item. ListView_SetItemState(hServicesListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, (LONG_PTR)hServicesListCtrl); return TRUE; } // // DO NOT TOUCH THESE NEXT MESSAGES, THEY ARE OK LIKE THIS... // case PSN_RESET: // Perform final cleaning, called before WM_DESTROY. return TRUE; case PSN_SETACTIVE: // Is going to gain activation. { SetWindowLongPtr(hServicesPage, DWLP_MSGRESULT, 0); return TRUE; } default: break; } } } default: return FALSE; } return FALSE; } }