reactos/base/applications/msconfig_new/srvpage.cpp

1124 lines
43 KiB
C++

/*
* 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 <Christoph@ApiViewer.de>
* Copyright 2011-2012 Hermes BELUSCA - MAITO <hermes.belusca@sfr.fr>
*
*/
#include "precomp.h"
#include "utils.h"
#include "regutils.h"
#include "stringutils.h"
// #include "CmdLineParser.h"
#include "listview.h"
#include "uxthemesupp.h"
#include <winsvc.h>
// #include <atlbase.h>
#include <atlcoll.h>
#include <atlstr.h>
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<CAtlStringW> 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 = &params;
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 = &params;
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<LPARAM>(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(&params.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<ServiceItem*>(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<ServiceItem*>(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>*/ int(lParam), bNewCheckState, !HideEssentialServiceWarning()))
{
UpdateBtnStates(hDlg);
PropSheet_Changed(GetParent(hServicesPage), hServicesPage);
}
return TRUE;
}
case WM_NOTIFY:
{
if (reinterpret_cast<LPNMHDR>(lParam)->hwndFrom == hServicesListCtrl)
{
switch (reinterpret_cast<LPNMHDR>(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<LPNMLVKEYDOWN>(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<LPNMLISTVIEW>(lParam)->iSubItem;
ListView_SortEx(hServicesListCtrl, iSortingColumn, iSortedColumn);
iSortedColumn = iSortingColumn;
return TRUE;
}
}
}
else
{
switch (reinterpret_cast<LPNMHDR>(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 = &params;
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 = &params;
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;
}
}