Пример #1
0
//---------------------------------------------------------------------------
Service & Service::install(SC_HANDLE hSCManager)
{
  install();
  utf8::WideString serviceNameW(serviceName_.getUNICODEString());
  utf8::WideString displayNameW(displayName_.getUNICODEString());
  utf8::WideString binaryPathNameW((!args_.isNull() ? binaryPathName_ + args_ : binaryPathName_).getUNICODEString());
  utf8::WideString loadOrderGroupW(loadOrderGroup_.getUNICODEString());
  utf8::WideString dependenciesW(dependencies_.getUNICODEString());
  utf8::WideString serviceStartNameW(serviceStartName_.getUNICODEString());
  utf8::WideString passwordW(password_.getUNICODEString());
  SC_HANDLE handle = CreateServiceW(
    hSCManager,
    serviceNameW,
    displayNameW,
    SERVICE_ALL_ACCESS,
    serviceType_,
    startType_,
    errorControl_,
    binaryPathNameW,
    !loadOrderGroup_.isNull() ? (wchar_t *) loadOrderGroupW : NULL,
    (serviceType_ == SERVICE_KERNEL_DRIVER || serviceType_ == SERVICE_FILE_SYSTEM_DRIVER) &&
    (startType_ == SERVICE_BOOT_START || startType_ == SERVICE_SYSTEM_START) ?
    &tagId_ : NULL,
    !dependencies_.isNull() ? (wchar_t *) dependenciesW : NULL,
    !serviceStartName_.isNull() ? (wchar_t *) serviceStartNameW : NULL,
    !password_.isNull() ? (wchar_t *) passwordW : NULL
  );
  if( handle == NULL ){
    int32_t err = GetLastError();
    if( err == ERROR_SERVICE_EXISTS ){
      SetLastError(err = ERROR_SUCCESS);
      handle = OpenServiceW(hSCManager,serviceNameW,SERVICE_ALL_ACCESS);
      if( handle == NULL ||
          ChangeServiceConfigW(handle,
            serviceType_,
            startType_,
            errorControl_,
            binaryPathNameW,
            !loadOrderGroup_.isNull() ? (wchar_t *) loadOrderGroupW : NULL,
            (serviceType_ == SERVICE_KERNEL_DRIVER || serviceType_ == SERVICE_FILE_SYSTEM_DRIVER) &&
            (startType_ == SERVICE_BOOT_START || startType_ == SERVICE_SYSTEM_START) ?
            &tagId_ : NULL,
            !dependencies_.isNull() ? (wchar_t *) dependenciesW : NULL,
            !serviceStartName_.isNull() ? (wchar_t *) serviceStartNameW : NULL,
            !password_.isNull() ? (wchar_t *) passwordW : NULL,
            displayNameW
      ) == 0 ) err = GetLastError();
    }
    if( err != ERROR_SUCCESS ){
      if( handle != NULL ) CloseServiceHandle(handle);
      newObjectV1C2<Exception>(err + errorOffset,__PRETTY_FUNCTION__)->throwSP();
    }
  }
  CloseServiceHandle(handle);
  return *this;
}
Пример #2
0
/**
 * Determines if the MozillaMaintenance service path needs to be updated
 * and fixes it if it is wrong.
 *
 * @param service             A handle to the service to fix.
 * @param currentServicePath  The current (possibly wrong) path that is used.
 * @param servicePathWasWrong Out parameter set to TRUE if a fix was needed.
 * @return TRUE if the service path is now correct.
*/
BOOL
FixServicePath(SC_HANDLE service,
               LPCWSTR currentServicePath,
               BOOL &servicePathWasWrong)
{
  // When we originally upgraded the MozillaMaintenance service we
  // would uninstall the service on each upgrade.  This had an
  // intermittent error which could cause the service to use the file
  // maintenanceservice_tmp.exe as the install path.  Only a small number
  // of Nightly users would be affected by this, but we check for this
  // state here and fix the user if they are affected.
  //
  // We also fix the path in the case of the path not being quoted.
  size_t currentServicePathLen = wcslen(currentServicePath);
  bool doesServiceHaveCorrectPath =
    currentServicePathLen > 2 &&
    !wcsstr(currentServicePath, L"maintenanceservice_tmp.exe") &&
    currentServicePath[0] == L'\"' &&
    currentServicePath[currentServicePathLen - 1] == L'\"';

  if (doesServiceHaveCorrectPath) {
    LOG(("The MozillaMaintenance service path is correct."));
    servicePathWasWrong = FALSE;
    return TRUE;
  }
  // This is a recoverable situation so not logging as a warning
  LOG(("The MozillaMaintenance path is NOT correct. It was: %ls",
       currentServicePath));

  servicePathWasWrong = TRUE;
  WCHAR fixedPath[MAX_PATH + 1] = { L'\0' };
  wcsncpy(fixedPath, currentServicePath, MAX_PATH);
  PathUnquoteSpacesW(fixedPath);
  if (!PathRemoveFileSpecW(fixedPath)) {
    LOG_WARN(("Couldn't remove file spec.  (%d)", GetLastError()));
    return FALSE;
  }
  if (!PathAppendSafe(fixedPath, L"maintenanceservice.exe")) {
    LOG_WARN(("Couldn't append file spec.  (%d)", GetLastError()));
    return FALSE;
  }
  PathQuoteSpacesW(fixedPath);


  if (!ChangeServiceConfigW(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
                            SERVICE_NO_CHANGE, fixedPath, nullptr, nullptr,
                            nullptr, nullptr, nullptr, nullptr)) {
    LOG_WARN(("Could not fix service path.  (%d)", GetLastError()));
    return FALSE;
  }

  LOG(("Fixed service path to: %ls.", fixedPath));
  return TRUE;
}
Пример #3
0
BOOL
SetServiceConfig(LPQUERY_SERVICE_CONFIG pServiceConfig,
                 LPWSTR lpServiceName,
                 LPWSTR lpPassword)
{
    SC_HANDLE hSCManager;
    SC_HANDLE hSc;
    SC_LOCK scLock;
    BOOL bRet = FALSE;

    hSCManager = OpenSCManagerW(NULL,
                                NULL,
                                SC_MANAGER_LOCK);
    if (hSCManager)
    {
        scLock = LockServiceDatabase(hSCManager);
        if (scLock)
        {
            hSc = OpenServiceW(hSCManager,
                               lpServiceName,
                               SERVICE_CHANGE_CONFIG);
            if (hSc)
            {
                if (ChangeServiceConfigW(hSc,
                                         pServiceConfig->dwServiceType,
                                         pServiceConfig->dwStartType,
                                         pServiceConfig->dwErrorControl,
                                         pServiceConfig->lpBinaryPathName,
                                         pServiceConfig->lpLoadOrderGroup,
                                         pServiceConfig->dwTagId ? &pServiceConfig->dwTagId : NULL,
                                         pServiceConfig->lpDependencies,
                                         pServiceConfig->lpServiceStartName,
                                         lpPassword,
                                         pServiceConfig->lpDisplayName))
                {
                    bRet = TRUE;
                }

                CloseServiceHandle(hSc);
            }

            UnlockServiceDatabase(scLock);
        }

        CloseServiceHandle(hSCManager);
    }

    if (!bRet)
        GetError();

    return bRet;
}
Пример #4
0
static BOOL
EnableUserModePnpManager(VOID)
{
    SC_HANDLE hSCManager = NULL;
    SC_HANDLE hService = NULL;
    BOOL bRet = FALSE;

    hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    if (hSCManager == NULL)
    {
        DPRINT1("Unable to open the service control manager.\n");
        DPRINT1("Last Error %d\n", GetLastError());
        goto cleanup;
    }

    hService = OpenServiceW(hSCManager,
                            L"PlugPlay",
                            SERVICE_CHANGE_CONFIG | SERVICE_START);
    if (hService == NULL)
    {
        DPRINT1("Unable to open PlugPlay service\n");
        goto cleanup;
    }

    bRet = ChangeServiceConfigW(hService,
                               SERVICE_NO_CHANGE,
                               SERVICE_AUTO_START,
                               SERVICE_NO_CHANGE,
                               NULL, NULL, NULL,
                               NULL, NULL, NULL, NULL);
    if (!bRet)
    {
        DPRINT1("Unable to change the service configuration\n");
        goto cleanup;
    }

    bRet = StartServiceW(hService, 0, NULL);
    if (!bRet && (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING))
    {
        DPRINT1("Unable to start service\n");
        goto cleanup;
    }

    bRet = TRUE;

cleanup:
    if (hService != NULL)
        CloseServiceHandle(hService);
    if (hSCManager != NULL)
        CloseServiceHandle(hSCManager);
    return bRet;
}
Пример #5
0
/**
 * Determines if the MozillaMaintenance service path needs to be updated
 * and fixes it if it is wrong.
 *
 * @param service             A handle to the service to fix.
 * @param currentServicePath  The current (possibly wrong) path that is used.
 * @param servicePathWasWrong Out parameter set to TRUE if a fix was needed.
 * @return TRUE if the service path is now correct.
*/
BOOL
FixServicePath(SC_HANDLE service,
               LPCWSTR currentServicePath,
               BOOL &servicePathWasWrong)
{
  // When we originally upgraded the MozillaMaintenance service we
  // would uninstall the service on each upgrade.  This had an
  // intermittent error which could cause the service to use the file
  // maintenanceservice_tmp.exe as the install path.  Only a small number
  // of Nightly users would be affected by this, but we check for this
  // state here and fix the user if they are affected.
  bool doesServiceHaveCorrectPath =
    !wcsstr(currentServicePath, L"maintenanceservice_tmp.exe");
  if (doesServiceHaveCorrectPath) {
    LOG(("The MozillaMaintenance service path is correct.\n"));
    servicePathWasWrong = FALSE;
    return TRUE;
  }
  LOG(("The MozillaMaintenance path is NOT correct.\n"));
  servicePathWasWrong = TRUE;

  WCHAR fixedPath[MAX_PATH + 1] = { L'\0' };
  wcsncpy(fixedPath, currentServicePath, MAX_PATH);
  PathUnquoteSpacesW(fixedPath);
  if (!PathRemoveFileSpecW(fixedPath)) {
    LOG(("Couldn't remove file spec. (%d)\n", GetLastError()));
    return FALSE;
  }
  if (!PathAppendSafe(fixedPath, L"maintenanceservice.exe")) {
    LOG(("Couldn't append file spec. (%d)\n", GetLastError()));
    return FALSE;
  }
  PathQuoteSpacesW(fixedPath);


  if (!ChangeServiceConfigW(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
                            SERVICE_NO_CHANGE, fixedPath, NULL, NULL, NULL,
                            NULL, NULL, NULL)) {
    LOG(("Could not fix service path. (%d)\n", GetLastError()));
    return FALSE;
  }

  LOG(("Fixed service path to: %ls.\n", fixedPath));
  return TRUE;
}
Пример #6
0
static VOID
RpcSsConfigureAsNetworkService(VOID)
{
    SC_HANDLE hSCManager, hService;

    /* Open the service controller */
    hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
    if (!hSCManager)
    {
        ERR("OpenSCManager() failed with error 0x%lx\n", GetLastError());
        return;
    }

    /* Open the RPCSS service */
    hService = OpenServiceW(hSCManager, L"RPCSS", SERVICE_CHANGE_CONFIG);
    if (!hService)
        ERR("OpenService(\"RPCSS\") failed with error 0x%lx\n", GetLastError());
    if (hService)
    {
        /* Use the NetworkService account */
        if (!ChangeServiceConfigW(hService,
                                  SERVICE_NO_CHANGE,
                                  SERVICE_NO_CHANGE,
                                  SERVICE_NO_CHANGE,
                                  NULL,
                                  NULL,
                                  NULL,
                                  NULL,
                                  L"NT AUTHORITY\\NetworkService",
                                  L"",
                                  NULL))
        {
            ERR("ChangeServiceConfig(\"RPCSS\") failed with error 0x%lx\n", GetLastError());
        }

        CloseServiceHandle(hService);
    }

    CloseServiceHandle(hSCManager);
}
Пример #7
0
void CSystemService::Install(LPCWSTR displayname)
{
	WCHAR startcmd[MAX_PATH+5];
	TCHAR filename[MAX_PATH];
	if(0==::GetModuleFileName(nullptr,filename,MAX_PATH)) return;
	if(0==swprintf_s(startcmd,L"\"%s\" -s",filename))return;

	SC_HANDLE newService=nullptr, scm=nullptr;
	SERVICE_STATUS status;
	__try
	{
		scm = OpenSCManager(0, 0,
			SC_MANAGER_CREATE_SERVICE);
		if (!scm)
			__leave;
		// Install the new service
		newService = OpenServiceW(scm,ServiceTable[0].lpServiceName,SERVICE_ALL_ACCESS);
		if(newService)
		{
			QUERY_SERVICE_CONFIG* querybuff=nullptr;
			DWORD bufsz=0;
			if(QueryServiceConfig(newService,querybuff,0,&bufsz)==FALSE)
			{
				if(ERROR_INSUFFICIENT_BUFFER==GetLastError())
				{
					querybuff=(QUERY_SERVICE_CONFIG*)malloc(bufsz);
					if(querybuff)
					{
						if(QueryServiceConfig(newService,querybuff,bufsz,&bufsz))
						{
							wchar_t* firstQuotes=nullptr,*secondQuotes=nullptr;
							firstQuotes=wcschr(querybuff->lpBinaryPathName,'"');
							if(firstQuotes)
							{
								secondQuotes=wcschr(firstQuotes+1,'"');
								if(secondQuotes)
								{
									wchar_t tempfilename[MAX_PATH];
									wcsncpy_s(tempfilename,firstQuotes+1,secondQuotes-firstQuotes-1);
									if(_wcsicmp(tempfilename,filename)!=0)
									{
										if(StopService(newService))
										{
											if(CopyFile(filename,tempfilename,FALSE))
											{
												wcscpy_s(startcmd,querybuff->lpBinaryPathName);
											}
										}
									}
								}
							}
						}
						free(querybuff);
					}
				}
			}
			if(!ChangeServiceConfigW(newService,
				SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS,
				SERVICE_AUTO_START,
				SERVICE_ERROR_NORMAL,
				startcmd,
				0,0,dependens,0,0,0))
				__leave;
		}
		else
		{
			newService = CreateServiceW(
				scm, ServiceTable[0].lpServiceName,
				displayname?displayname:ServiceTable[0].lpServiceName,
				SERVICE_ALL_ACCESS,
				SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS,
				SERVICE_AUTO_START,
				SERVICE_ERROR_NORMAL,
				startcmd,
				0, 0, dependens, 0, 0);
		}
		if (newService)
		{
			SERVICE_FAILURE_ACTIONS sfa;
			ZeroMemory(&sfa,sizeof(sfa));
			sfa.dwResetPeriod=INFINITE;
			sfa.cActions=3;
			SC_ACTION sact[3];
			ZeroMemory(sact,sizeof(sact));
			sfa.lpsaActions=sact;
			sact[0].Delay=500;
			sact[0].Type=SC_ACTION_RESTART;
			sact[1].Delay=500;
			sact[1].Type=SC_ACTION_RESTART;
			sact[2].Delay=500;
			sact[2].Type=SC_ACTION_RESTART;
			ChangeServiceConfig2(newService,SERVICE_CONFIG_FAILURE_ACTIONS,&sfa);

			if(QueryServiceStatus(newService,&status))
			{
				if(status.dwCurrentState==SERVICE_STOPPED)
				{
					StartService(newService,0,0);
				}
			}
		}
	}
	__finally
	{
		if(newService)CloseServiceHandle(newService);
		if(scm)CloseServiceHandle(scm);
	}
}
Пример #8
0
static void Test_LockUnlockServiceDatabaseWithServiceStart(void)
{
    BOOL bError = FALSE;

    SC_HANDLE hScm  = NULL;
    SC_HANDLE hSvc  = NULL;
    SC_LOCK   hLock = NULL;

    LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
    DWORD dwRequiredSize = 0;
    SERVICE_STATUS status;
    BOOL bWasRunning = FALSE;
    DWORD dwOldStartType = 0;

    /* Open the services database */
    SetLastError(0xdeadbeef);
    hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_LOCK);
    ok(hScm != NULL, "Failed to open service manager, error=0x%08lx\n", GetLastError());
    if (!hScm)
    {
        skip("No service control manager; cannot proceed with LockUnlockServiceDatabaseWithServiceStart test\n");
        goto cleanup;
    }
    ok_err(ERROR_SUCCESS);

    /* Grab a handle to the testing service */
    SetLastError(0xdeadbeef);
    hSvc = OpenServiceW(hScm, TESTING_SERVICE, SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS);
    ok(hSvc != NULL, "hSvc = 0x%p, expected non-null, error=0x%08lx\n", hSvc, GetLastError());
    if (!hSvc)
    {
        skip("Cannot open a handle to service %S; cannot proceed with LockUnlockServiceDatabaseWithServiceStart test\n", TESTING_SERVICE);
        goto cleanup;
    }
    ok_err(ERROR_SUCCESS);

    /* Lock the services database */
    SetLastError(0xdeadbeef);
    hLock = LockServiceDatabase(hScm);
    ok(hLock != NULL, "hLock = 0x%p, expected non-zero, error=0x%08lx\n", hLock, GetLastError());
    if (!hLock)
    {
        skip("Cannot lock the services database; cannot proceed with LockUnlockServiceDatabaseWithServiceStart test\n");
        goto cleanup;
    }
    ok_err(ERROR_SUCCESS);

    /* To proceed further, firstly attempt to stop the testing service */
    QueryServiceConfigW(hSvc, NULL, 0, &dwRequiredSize);
    lpConfig = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize);
    QueryServiceConfigW(hSvc, lpConfig, dwRequiredSize, &dwRequiredSize);
    dwOldStartType = lpConfig->dwStartType;
    HeapFree(GetProcessHeap(), 0, lpConfig);
    if (dwOldStartType == SERVICE_DISABLED)
    {
        ChangeServiceConfigW(hSvc,
                             SERVICE_NO_CHANGE,
                             SERVICE_DEMAND_START,
                             SERVICE_NO_CHANGE,
                             NULL,
                             NULL,
                             NULL,
                             NULL,
                             NULL,
                             NULL,
                             NULL);
    }
    QueryServiceStatus(hSvc, &status);
    bWasRunning = (status.dwCurrentState != SERVICE_STOPPED);
    if (bWasRunning)
    {
        ControlService(hSvc, SERVICE_CONTROL_STOP, &status);
        Sleep(1000); /* Wait 1 second for the service to stop */
    }

    /* Now try to start it (this test won't work under Windows Vista / 7 / 8) */
    SetLastError(0xdeadbeef);
    bError = StartServiceW(hSvc, 0, NULL);
    ok(bError == FALSE, "bError = %u, expected FALSE\n", bError);
    ok_err(ERROR_SERVICE_DATABASE_LOCKED);
    Sleep(1000); /* Wait 1 second for the service to start */

    /* Stop the testing service */
    ControlService(hSvc, SERVICE_CONTROL_STOP, &status);
    Sleep(1000); /* Wait 1 second for the service to stop */

    /* Now unlock the services database */
    SetLastError(0xdeadbeef);
    bError = UnlockServiceDatabase(hLock);
    ok(bError == TRUE, "bError = %u, expected TRUE\n", bError);
    ok_err(ERROR_SUCCESS);

    /* Try to start again the service, this time the database unlocked */
    SetLastError(0xdeadbeef);
    bError = StartServiceW(hSvc, 0, NULL);
    ok(bError == TRUE, "bError = %u, expected TRUE\n", bError);
    ok_err(ERROR_SUCCESS);
    Sleep(1000); /* Wait 1 second for the service to start */

    /* Stop the testing service */
    ControlService(hSvc, SERVICE_CONTROL_STOP, &status);
    Sleep(1000); /* Wait 1 second for the service to stop */

    /* Restore its original state */
    if (bWasRunning)
    {
        StartServiceW(hSvc, 0, NULL);
    }

    if (dwOldStartType == SERVICE_DISABLED)
    {
        ChangeServiceConfigW(hSvc,
                             SERVICE_NO_CHANGE,
                             SERVICE_DISABLED,
                             SERVICE_NO_CHANGE,
                             NULL,
                             NULL,
                             NULL,
                             NULL,
                             NULL,
                             NULL,
                             NULL);
    }


cleanup:
    if (hSvc)
        CloseServiceHandle(hSvc);

    if (hScm)
        CloseServiceHandle(hScm);

    return;
}
Пример #9
0
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);
            Update_Btn_States(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 bAreThereModifs = FALSE;

                    int index = -1; // From the beginning.
                    while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1)
                    {
                        bAreThereModifs = ValidateItem(index, TRUE, FALSE) || bAreThereModifs; // The order is verrrrrry important !!!!
                    }

                    if (bAreThereModifs)
                    {
                        Update_Btn_States(hDlg);
                        PropSheet_Changed(GetParent(hServicesPage), hServicesPage);
                    }

                    return TRUE;
                }

                case IDC_BTN_SERVICES_DEACTIVATE:
                {
                    BOOL bAreThereModifs = FALSE;

                    int index = -1; // From the beginning.
                    while ((index = ListView_GetNextItem(hServicesListCtrl, index, LVNI_ALL)) != -1)
                    {
                        bAreThereModifs = ValidateItem(index, FALSE, FALSE) || bAreThereModifs; // The order is verrrrrry important !!!!
                    }

                    if (bAreThereModifs)
                    {
                        Update_Btn_States(hDlg);
                        PropSheet_Changed(GetParent(hServicesPage), hServicesPage);
                    }

                    return TRUE;
                }

                case IDC_CBX_SERVICES_MASK_PROPRIETARY_SVCS:
                {
                    bMaskProprietarySvcs = !bMaskProprietarySvcs;
                    GetServices(bMaskProprietarySvcs);
                    Update_Btn_States(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()))
            {
                Update_Btn_States(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- Retrive 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);
                        Update_Btn_States(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;
}