Пример #1
0
LPQUERY_SERVICE_CONFIG
GetServiceConfig(LPWSTR lpServiceName)
{
    LPQUERY_SERVICE_CONFIGW lpServiceConfig = NULL;
    SC_HANDLE hSCManager;
    SC_HANDLE hService;
    DWORD dwBytesNeeded;

    hSCManager = OpenSCManagerW(NULL,
                                NULL,
                                SC_MANAGER_ALL_ACCESS);
    if (hSCManager)
    {
        hService = OpenServiceW(hSCManager,
                                lpServiceName,
                                SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_QUERY_CONFIG);
        if (hService)
        {
            if (!QueryServiceConfigW(hService,
                                     NULL,
                                     0,
                                     &dwBytesNeeded))
            {
                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                {
                    lpServiceConfig = (LPQUERY_SERVICE_CONFIG)HeapAlloc(GetProcessHeap(),
                                                                        0,
                                                                        dwBytesNeeded);
                    if (lpServiceConfig)
                    {
                        if (!QueryServiceConfigW(hService,
                                                lpServiceConfig,
                                                dwBytesNeeded,
                                                &dwBytesNeeded))
                        {
                            HeapFree(GetProcessHeap(),
                                     0,
                                     lpServiceConfig);
                            lpServiceConfig = NULL;
                        }
                    }
                }
            }

            CloseServiceHandle(hService);
        }

        CloseServiceHandle(hSCManager);
    }

    return lpServiceConfig;
}
POCO_LPQUERY_SERVICE_CONFIG WinService::config() const
{
    open();
    int size = 4096;
    DWORD bytesNeeded;
    POCO_LPQUERY_SERVICE_CONFIG pSvcConfig = (POCO_LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, size);
    if (!pSvcConfig) throw OutOfMemoryException("cannot allocate service config buffer");
    try
    {
#if defined(POCO_WIN32_UTF8)
        while (!QueryServiceConfigW(_svcHandle, pSvcConfig, size, &bytesNeeded))
#else
        while (!QueryServiceConfigA(_svcHandle, pSvcConfig, size, &bytesNeeded))
#endif
        {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
                LocalFree(pSvcConfig);
                size = bytesNeeded;
                pSvcConfig = (POCO_LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, size);
            }
            else throw SystemException("cannot query service configuration", _name);
        }
    }
    catch (...)
    {
        LocalFree(pSvcConfig);
        throw;
    }
    return pSvcConfig;
}
Пример #3
0
/* dupe ifdef needed for mkindex
** COMMAND: winsrv*
** Usage: fossil winsrv METHOD ?SERVICE-NAME? ?OPTIONS?
**
** Where METHOD is one of: create delete show start stop.
**
** The winsrv command manages Fossil as a Windows service.  This allows
** (for example) Fossil to be running in the background when no user
** is logged in.
**
** In the following description of the methods, "Fossil-DSCM" will be
** used as the default SERVICE-NAME:
**
**    fossil winsrv create ?SERVICE-NAME? ?OPTIONS?
**
**         Creates a service. Available options include:
**
**         -D|--display DISPLAY-NAME
**
**              Sets the display name of the service. This name is shown
**              by graphical interface programs. By default, the display name
**              equals to the service name.
**
**         -S|--start TYPE
**
**              Sets the start type of the service. TYPE can be "manual",
**              which means you need to start the service yourself with the
**              'fossil winsrv start' command or with the "net start" command
**              from the operating system. If TYPE is set to "auto", the service
**              will be started automatically by the system during startup.
**
**         -U|--username USERNAME
**
**              Specifies the user account which will be used to run the
**              service. The account needs the "Logon as a service" right
**              enabled in its profile. Specify local accounts as follows:
**              ".\\USERNAME". By default, the "LocalSystem" account will be
**              used.
**
**         -W|--password PASSWORD
**
**              Password for the user account.
**
**         The following options are more or less the same as for the "server"
**         command and influence the behaviour of the http server:
**
**         -P|--port TCPPORT
**
**              Specifies the TCP port (default port is 8080) on which the
**              server should listen.
**
**         -R|--repository REPOSITORY
**
**              Specifies the name of the repository to be served.
**              The repository option may be omitted if the working directory
**              is within an open checkout.
**              The REPOSITORY can be a directory (aka folder) that contains
**              one or more repositories with names ending in ".fossil".
**              In that case, the first element of the URL is used to select
**              among the various repositories.
**
**         --notfound URL
**
**              If REPOSITORY is a directory that contains one or more
**              repositories with names of the form "*.fossil" then the
**              first element of the URL  pathname selects among the various
**              repositories. If the pathname does not select a valid
**              repository and the --notfound option is available,
**              then the server redirects (HTTP code 302) to the URL of
**              --notfound.
**
**         --localauth
**
**              Enables automatic login if the --localauth option is present
**              and the "localauth" setting is off and the connection is from
**              localhost.
**
**
**    fossil winsrv delete ?SERVICE-NAME?
**
**         Deletes a service. If the service is currently running, it will be
**         stopped first and then deleted.
**
**
**    fossil winsrv show ?SERVICE-NAME?
**
**         Shows how the service is configured and its current state.
**
**
**    fossil winsrv start ?SERVICE-NAME?
**
**         Start the service.
**
**
**    fossil winsrv stop ?SERVICE-NAME?
**
**         Stop the service.
**
**
** NOTE: This command is available on Windows operating systems only and
**       requires administrative rights on the machine executed.
**
*/
void cmd_win32_service(void){
  int n;
  const char *zMethod;
  const char *zSvcName = "Fossil-DSCM";    /* Default service name */

  if( g.argc<3 ){
    usage("create|delete|show|start|stop ...");
  }
  zMethod = g.argv[2];
  n = strlen(zMethod);

  if( strncmp(zMethod, "create", n)==0 ){
    SC_HANDLE hScm;
    SC_HANDLE hSvc;
    SERVICE_DESCRIPTIONW
      svcDescr = {L"Fossil - Distributed Software Configuration Management"};
    char *zErrFmt = "unable to create service '%s': %s";
    DWORD dwStartType = SERVICE_DEMAND_START;
    const char *zDisplay    = find_option("display", "D", 1);
    const char *zStart      = find_option("start", "S", 1);
    const char *zUsername   = find_option("username", "U", 1);
    const char *zPassword   = find_option("password", "W", 1);
    const char *zPort       = find_option("port", "P", 1);
    const char *zNotFound   = find_option("notfound", 0, 1);
    const char *zLocalAuth  = find_option("localauth", 0, 0);
    const char *zRepository = find_option("repository", "R", 1);
    Blob binPath;

    verify_all_options();
    if( g.argc==4 ){
      zSvcName = g.argv[3];
    }else if( g.argc>4 ){
      fossil_fatal("to much arguments for create method.");
    }
    /* Process service creation specific options. */
    if( !zDisplay ){
      zDisplay = zSvcName;
    }
    if( zStart ){
      if( strncmp(zStart, "auto", strlen(zStart))==0 ){
        dwStartType = SERVICE_AUTO_START;
      }else if( strncmp(zStart, "manual", strlen(zStart))==0 ){
        dwStartType = SERVICE_DEMAND_START;
      }else{
        fossil_fatal(zErrFmt, zSvcName,
                     "specify 'auto' or 'manual' for the '-S|--start' option");
      }
    }
    /* Process options for Fossil running as server. */
    if( zPort && (atoi(zPort)<=0) ){
      fossil_fatal(zErrFmt, zSvcName,
                   "port number must be in the range 1 - 65535.");
    }
    if( !zRepository ){
      db_must_be_within_tree();
    }else if( file_isdir(zRepository)==1 ){
      g.zRepositoryName = mprintf("%s", zRepository);
      file_simplify_name(g.zRepositoryName, -1, 0);
    }else{
      db_open_repository(zRepository);
    }
    db_close(0);
    /* Build the fully-qualified path to the service binary file. */
    blob_zero(&binPath);
    blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
    if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
    if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
    if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
    blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
    /* Create the service. */
    hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    hSvc = CreateServiceW(
             hScm,                                    /* Handle to the SCM */
             fossil_utf8_to_unicode(zSvcName),           /* Name of the service */
             fossil_utf8_to_unicode(zDisplay),           /* Display name */
             SERVICE_ALL_ACCESS,                      /* Desired access */
             SERVICE_WIN32_OWN_PROCESS,               /* Service type */
             dwStartType,                             /* Start type */
             SERVICE_ERROR_NORMAL,                    /* Error control */
             fossil_utf8_to_unicode(blob_str(&binPath)), /* Binary path */
             NULL,                                    /* Load ordering group */
             NULL,                                    /* Tag value */
             NULL,                                    /* Service dependencies */
             fossil_utf8_to_unicode(zUsername),          /* Service account */
             fossil_utf8_to_unicode(zPassword)           /* Account password */
           );
    if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    /* Set the service description. */
    ChangeServiceConfig2W(hSvc, SERVICE_CONFIG_DESCRIPTION, &svcDescr);
    fossil_print("Service '%s' successfully created.\n", zSvcName);
    CloseServiceHandle(hSvc);
    CloseServiceHandle(hScm);
  }else
  if( strncmp(zMethod, "delete", n)==0 ){
    SC_HANDLE hScm;
    SC_HANDLE hSvc;
    SERVICE_STATUS sstat;
    char *zErrFmt = "unable to delete service '%s': %s";

    verify_all_options();
    if( g.argc==4 ){
      zSvcName = g.argv[3];
    }else if( g.argc>4 ){
      fossil_fatal("to much arguments for delete method.");
    }
    hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS);
    if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    QueryServiceStatus(hSvc, &sstat);
    if( sstat.dwCurrentState!=SERVICE_STOPPED ){
      fossil_print("Stopping service '%s'", zSvcName);
      if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){
        if( !ControlService(hSvc, SERVICE_CONTROL_STOP, &sstat) ){
          fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
        }
      }
      while( sstat.dwCurrentState!=SERVICE_STOPPED ){
        Sleep(100);
        fossil_print(".");
        QueryServiceStatus(hSvc, &sstat);
      }
      fossil_print("\nService '%s' stopped.\n", zSvcName);
    }
    if( !DeleteService(hSvc) ){
      if( GetLastError()==ERROR_SERVICE_MARKED_FOR_DELETE ){
        fossil_warning("Service '%s' already marked for delete.\n", zSvcName);
      }else{
        fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
      }
    }else{
      fossil_print("Service '%s' successfully deleted.\n", zSvcName);
    }
    CloseServiceHandle(hSvc);
    CloseServiceHandle(hScm);
  }else
  if( strncmp(zMethod, "show", n)==0 ){
    SC_HANDLE hScm;
    SC_HANDLE hSvc;
    SERVICE_STATUS sstat;
    LPQUERY_SERVICE_CONFIGW pSvcConfig;
    LPSERVICE_DESCRIPTIONW pSvcDescr;
    BOOL bStatus;
    DWORD nRequired;
    const char *zErrFmt = "unable to show service '%s': %s";
    static const char *const zSvcTypes[] = {
      "Driver service",
      "File system driver service",
      "Service runs in its own process",
      "Service shares a process with other services",
      "Service can interact with the desktop"
    };
    const char *zSvcType = "";
    static const char *const zSvcStartTypes[] = {
      "Started by the system loader",
      "Started by the IoInitSystem function",
      "Started automatically by the service control manager",
      "Started manually",
      "Service cannot be started"
    };
    const char *zSvcStartType = "";
    static const char *const zSvcStates[] = {
      "Stopped", "Starting", "Stopping", "Running",
      "Continue pending", "Pause pending", "Paused"
    };
    const char *zSvcState = "";

    verify_all_options();
    if( g.argc==4 ){
      zSvcName = g.argv[3];
    }else if( g.argc>4 ){
      fossil_fatal("to much arguments for show method.");
    }
    hScm = OpenSCManagerW(NULL, NULL, GENERIC_READ);
    if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), GENERIC_READ);
    if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    /* Get the service configuration */
    bStatus = QueryServiceConfigW(hSvc, NULL, 0, &nRequired);
    if( !bStatus && GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){
      fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    }
    pSvcConfig = fossil_malloc(nRequired);
    bStatus = QueryServiceConfigW(hSvc, pSvcConfig, nRequired, &nRequired);
    if( !bStatus ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    /* Translate the service type */
    switch( pSvcConfig->dwServiceType ){
      case SERVICE_KERNEL_DRIVER:       zSvcType = zSvcTypes[0]; break;
      case SERVICE_FILE_SYSTEM_DRIVER:  zSvcType = zSvcTypes[1]; break;
      case SERVICE_WIN32_OWN_PROCESS:   zSvcType = zSvcTypes[2]; break;
      case SERVICE_WIN32_SHARE_PROCESS: zSvcType = zSvcTypes[3]; break;
      case SERVICE_INTERACTIVE_PROCESS: zSvcType = zSvcTypes[4]; break;
    }
    /* Translate the service start type */
    switch( pSvcConfig->dwStartType ){
      case SERVICE_BOOT_START:    zSvcStartType = zSvcStartTypes[0]; break;
      case SERVICE_SYSTEM_START:  zSvcStartType = zSvcStartTypes[1]; break;
      case SERVICE_AUTO_START:    zSvcStartType = zSvcStartTypes[2]; break;
      case SERVICE_DEMAND_START:  zSvcStartType = zSvcStartTypes[3]; break;
      case SERVICE_DISABLED:      zSvcStartType = zSvcStartTypes[4]; break;
    }
    /* Get the service description. */
    bStatus = QueryServiceConfig2W(hSvc, SERVICE_CONFIG_DESCRIPTION,
                                  NULL, 0, &nRequired);
    if( !bStatus && GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){
      fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    }
    pSvcDescr = fossil_malloc(nRequired);
    bStatus = QueryServiceConfig2W(hSvc, SERVICE_CONFIG_DESCRIPTION,
                                  (LPBYTE)pSvcDescr, nRequired, &nRequired);
    if( !bStatus ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    /* Retrieves the current status of the specified service. */
    bStatus = QueryServiceStatus(hSvc, &sstat);
    if( !bStatus ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    /* Translate the current state. */
    switch( sstat.dwCurrentState ){
      case SERVICE_STOPPED:          zSvcState = zSvcStates[0]; break;
      case SERVICE_START_PENDING:    zSvcState = zSvcStates[1]; break;
      case SERVICE_STOP_PENDING:     zSvcState = zSvcStates[2]; break;
      case SERVICE_RUNNING:          zSvcState = zSvcStates[3]; break;
      case SERVICE_CONTINUE_PENDING: zSvcState = zSvcStates[4]; break;
      case SERVICE_PAUSE_PENDING:    zSvcState = zSvcStates[5]; break;
      case SERVICE_PAUSED:           zSvcState = zSvcStates[6]; break;
    }
    /* Print service information to terminal */
    fossil_print("Service name .......: %s\n", zSvcName);
    fossil_print("Display name .......: %s\n",
                 fossil_unicode_to_utf8(pSvcConfig->lpDisplayName));
    fossil_print("Service description : %s\n",
                 fossil_unicode_to_utf8(pSvcDescr->lpDescription));
    fossil_print("Service type .......: %s.\n", zSvcType);
    fossil_print("Service start type .: %s.\n", zSvcStartType);
    fossil_print("Binary path name ...: %s\n",
                 fossil_unicode_to_utf8(pSvcConfig->lpBinaryPathName));
    fossil_print("Service username ...: %s\n",
                 fossil_unicode_to_utf8(pSvcConfig->lpServiceStartName));
    fossil_print("Current state ......: %s.\n", zSvcState);
    /* Cleanup */
    fossil_free(pSvcConfig);
    fossil_free(pSvcDescr);
    CloseServiceHandle(hSvc);
    CloseServiceHandle(hScm);
  }else
  if( strncmp(zMethod, "start", n)==0 ){
    SC_HANDLE hScm;
    SC_HANDLE hSvc;
    SERVICE_STATUS sstat;
    char *zErrFmt = "unable to start service '%s': %s";

    verify_all_options();
    if( g.argc==4 ){
      zSvcName = g.argv[3];
    }else if( g.argc>4 ){
      fossil_fatal("to much arguments for start method.");
    }
    hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS);
    if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    QueryServiceStatus(hSvc, &sstat);
    if( sstat.dwCurrentState!=SERVICE_RUNNING ){
      fossil_print("Starting service '%s'", zSvcName);
      if( sstat.dwCurrentState!=SERVICE_START_PENDING ){
        if( !StartServiceW(hSvc, 0, NULL) ){
          fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
        }
      }
      while( sstat.dwCurrentState!=SERVICE_RUNNING ){
        Sleep(100);
        fossil_print(".");
        QueryServiceStatus(hSvc, &sstat);
      }
      fossil_print("\nService '%s' started.\n", zSvcName);
    }else{
      fossil_print("Service '%s' is already started.\n", zSvcName);
    }
    CloseServiceHandle(hSvc);
    CloseServiceHandle(hScm);
  }else
  if( strncmp(zMethod, "stop", n)==0 ){
    SC_HANDLE hScm;
    SC_HANDLE hSvc;
    SERVICE_STATUS sstat;
    char *zErrFmt = "unable to stop service '%s': %s";

    verify_all_options();
    if( g.argc==4 ){
      zSvcName = g.argv[3];
    }else if( g.argc>4 ){
      fossil_fatal("to much arguments for stop method.");
    }
    hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    hSvc = OpenServiceW(hScm, fossil_utf8_to_unicode(zSvcName), SERVICE_ALL_ACCESS);
    if( !hSvc ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
    QueryServiceStatus(hSvc, &sstat);
    if( sstat.dwCurrentState!=SERVICE_STOPPED ){
      fossil_print("Stopping service '%s'", zSvcName);
      if( sstat.dwCurrentState!=SERVICE_STOP_PENDING ){
        if( !ControlService(hSvc, SERVICE_CONTROL_STOP, &sstat) ){
          fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
        }
      }
      while( sstat.dwCurrentState!=SERVICE_STOPPED ){
        Sleep(100);
        fossil_print(".");
        QueryServiceStatus(hSvc, &sstat);
      }
      fossil_print("\nService '%s' stopped.\n", zSvcName);
    }else{
      fossil_print("Service '%s' is already stopped.\n", zSvcName);
    }
    CloseServiceHandle(hSvc);
    CloseServiceHandle(hScm);
  }else
  {
    fossil_fatal("METHOD should be one of:"
                 " create delete show start stop");
  }
  return;
}
Пример #4
0
LPWSTR
TV1_GetDependants(PSERVICEPROPSHEET pDlgInfo,
                  SC_HANDLE hService)
{
    LPQUERY_SERVICE_CONFIG lpServiceConfig;
    LPWSTR lpStr = NULL;
    DWORD bytesNeeded;
    DWORD bytes;

    /* Get the info for this service */
    if (!QueryServiceConfigW(hService,
                             NULL,
                             0,
                             &bytesNeeded) &&
        GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        lpServiceConfig = HeapAlloc(ProcessHeap,
                                    0,
                                    bytesNeeded);
        if (lpServiceConfig)
        {
            if (QueryServiceConfigW(hService,
                                    lpServiceConfig,
                                    bytesNeeded,
                                    &bytesNeeded))
            {
                /* Does this service have any dependencies? */
                if (lpServiceConfig->lpDependencies &&
                    *lpServiceConfig->lpDependencies != '\0')
                {
                    lpStr = lpServiceConfig->lpDependencies;
                    bytes = 0;

                    /* Work out how many bytes we need to hold the list */
                    for (;;)
                    {
                        bytes++;

                        if (!*lpStr && !*(lpStr + 1))
                        {
                            bytes++;
                            break;
                        }

                        lpStr++;
                    }

                    /* Allocate and copy the list */
                    bytes *= sizeof(WCHAR);
                    lpStr = HeapAlloc(ProcessHeap,
                                      0,
                                      bytes);
                    if (lpStr)
                    {
                        CopyMemory(lpStr,
                                   lpServiceConfig->lpDependencies,
                                   bytes);
                    }
                }
            }

            HeapFree(GetProcessHeap(),
                     0,
                     lpServiceConfig);
        }
    }

    return lpStr;
}
Пример #5
0
/**
 * Starts the upgrade process for update of the service if it is
 * already installed.
 *
 * @param  installDir the installation directory where
 *         maintenanceservice_installer.exe is located.
 * @return TRUE if successful
 */
BOOL
StartServiceUpdate(LPCWSTR installDir)
{
  // Get a handle to the local computer SCM database
  SC_HANDLE manager = OpenSCManager(nullptr, nullptr,
                                    SC_MANAGER_ALL_ACCESS);
  if (!manager) {
    return FALSE;
  }

  // Open the service
  SC_HANDLE svc = OpenServiceW(manager, SVC_NAME,
                               SERVICE_ALL_ACCESS);
  if (!svc) {
    CloseServiceHandle(manager);
    return FALSE;
  }

  // If we reach here, then the service is installed, so
  // proceed with upgrading it.

  CloseServiceHandle(manager);

  // The service exists and we opened it, get the config bytes needed
  DWORD bytesNeeded;
  if (!QueryServiceConfigW(svc, nullptr, 0, &bytesNeeded) &&
      GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
    CloseServiceHandle(svc);
    return FALSE;
  }

  // Get the service config information, in particular we want the binary
  // path of the service.
  mozilla::ScopedDeleteArray<char> serviceConfigBuffer(new char[bytesNeeded]);
  if (!QueryServiceConfigW(svc,
      reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get()),
      bytesNeeded, &bytesNeeded)) {
    CloseServiceHandle(svc);
    return FALSE;
  }

  CloseServiceHandle(svc);

  QUERY_SERVICE_CONFIGW &serviceConfig =
    *reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get());

  PathUnquoteSpacesW(serviceConfig.lpBinaryPathName);

  // Obtain the temp path of the maintenance service binary
  WCHAR tmpService[MAX_PATH + 1] = { L'\0' };
  if (!PathGetSiblingFilePath(tmpService, serviceConfig.lpBinaryPathName,
                              L"maintenanceservice_tmp.exe")) {
    return FALSE;
  }

  // Get the new maintenance service path from the install dir
  WCHAR newMaintServicePath[MAX_PATH + 1] = { L'\0' };
  wcsncpy(newMaintServicePath, installDir, MAX_PATH);
  PathAppendSafe(newMaintServicePath,
                 L"maintenanceservice.exe");

  // Copy the temp file in alongside the maintenace service.
  // This is a requirement for maintenance service upgrades.
  if (!CopyFileW(newMaintServicePath, tmpService, FALSE)) {
    return FALSE;
  }

  // Start the upgrade comparison process
  STARTUPINFOW si = {0};
  si.cb = sizeof(STARTUPINFOW);
  // No particular desktop because no UI
  si.lpDesktop = L"";
  PROCESS_INFORMATION pi = {0};
  WCHAR cmdLine[64] = { '\0' };
  wcsncpy(cmdLine, L"dummyparam.exe upgrade",
          sizeof(cmdLine) / sizeof(cmdLine[0]) - 1);
  BOOL svcUpdateProcessStarted = CreateProcessW(tmpService,
                                                cmdLine,
                                                nullptr, nullptr, FALSE,
                                                0,
                                                nullptr, installDir, &si, &pi);
  if (svcUpdateProcessStarted) {
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
  }
  return svcUpdateProcessStarted;
}
Пример #6
0
/**
 * Installs or upgrades the SVC_NAME service.
 * If an existing service is already installed, we replace it with the
 * currently running process.
 *
 * @param  action The action to perform.
 * @return TRUE if the service was installed/upgraded
 */
BOOL
SvcInstall(SvcInstallAction action)
{
  // Get a handle to the local computer SCM database with full access rights.
  nsAutoServiceHandle schSCManager(OpenSCManager(NULL, NULL, 
                                                 SC_MANAGER_ALL_ACCESS));
  if (!schSCManager) {
    LOG(("Could not open service manager.  (%d)\n", GetLastError()));
    return FALSE;
  }

  WCHAR newServiceBinaryPath[MAX_PATH + 1];
  if (!GetModuleFileNameW(NULL, newServiceBinaryPath, 
                          sizeof(newServiceBinaryPath) / 
                          sizeof(newServiceBinaryPath[0]))) {
    LOG(("Could not obtain module filename when attempting to "
         "install service. (%d)\n",
         GetLastError()));
    return FALSE;
  }

  // Check if we already have the service installed.
  nsAutoServiceHandle schService(OpenServiceW(schSCManager, 
                                              SVC_NAME, 
                                              SERVICE_ALL_ACCESS));
  DWORD lastError = GetLastError();
  if (!schService && ERROR_SERVICE_DOES_NOT_EXIST != lastError) {
    // The service exists but we couldn't open it
    LOG(("Could not open service.  (%d)\n", GetLastError()));
    return FALSE;
  }
  
  if (schService) {
    // The service exists but it may not have the correct permissions.
    // This could happen if the permissions were not set correctly originally
    // or have been changed after the installation.  This will reset the 
    // permissions back to allow limited user accounts.
    if (!SetUserAccessServiceDACL(schService)) {
      LOG(("Could not reset security ACE on service handle. It might not be "
           "possible to start the service. This error should never "
           "happen.  (%d)\n", GetLastError()));
    }

    // The service exists and we opened it
    DWORD bytesNeeded;
    if (!QueryServiceConfigW(schService, NULL, 0, &bytesNeeded) && 
        GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
      LOG(("Could not determine buffer size for query service config.  (%d)\n", 
           GetLastError()));
      return FALSE;
    }

    // Get the service config information, in particular we want the binary 
    // path of the service.
    nsAutoArrayPtr<char> serviceConfigBuffer = new char[bytesNeeded];
    if (!QueryServiceConfigW(schService, 
        reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get()), 
        bytesNeeded, &bytesNeeded)) {
      LOG(("Could open service but could not query service config.  (%d)\n", 
           GetLastError()));
      return FALSE;
    }
    QUERY_SERVICE_CONFIGW &serviceConfig = 
      *reinterpret_cast<QUERY_SERVICE_CONFIGW*>(serviceConfigBuffer.get());

    // Check if we need to fix the service path
    BOOL servicePathWasWrong;
    static BOOL alreadyCheckedFixServicePath = FALSE;
    if (!alreadyCheckedFixServicePath) {
      if (!FixServicePath(schService, serviceConfig.lpBinaryPathName,
                          servicePathWasWrong)) {
        LOG(("Could not fix service path. This should never happen. (%d)\n",
              GetLastError()));
        // True is returned because the service is pointing to
        // maintenanceservice_tmp.exe so it actually was upgraded to the
        // newest installed service.
        return TRUE;
      } else if (servicePathWasWrong) {
        // Now that the path is fixed we should re-attempt the install.
        // This current process' image path is maintenanceservice_tmp.exe.
        // The service used to point to maintenanceservice_tmp.exe.
        // The service was just fixed to point to maintenanceservice.exe.
        // Re-attempting an install from scratch will work as normal.
        alreadyCheckedFixServicePath = TRUE;
        LOG(("Restarting install action: %d\n", action));
        return SvcInstall(action);
      }
    }

    // Ensure the service path is not quoted. We own this memory and know it to
    // be large enough for the quoted path, so it is large enough for the
    // unquoted path.  This function cannot fail.
    PathUnquoteSpacesW(serviceConfig.lpBinaryPathName);

    // Obtain the existing maintenanceservice file's version number and
    // the new file's version number.  Versions are in the format of
    // A.B.C.D.
    DWORD existingA, existingB, existingC, existingD;
    DWORD newA, newB, newC, newD; 
    BOOL obtainedExistingVersionInfo = 
      GetVersionNumberFromPath(serviceConfig.lpBinaryPathName, 
                               existingA, existingB, 
                               existingC, existingD);
    if (!GetVersionNumberFromPath(newServiceBinaryPath, newA, 
                                 newB, newC, newD)) {
      LOG(("Could not obtain version number from new path\n"));
      return FALSE;
    }

    // Check if we need to replace the old binary with the new one
    // If we couldn't get the old version info then we assume we should 
    // replace it.
    if (ForceInstallSvc == action ||
        !obtainedExistingVersionInfo || 
        (existingA < newA) ||
        (existingA == newA && existingB < newB) ||
        (existingA == newA && existingB == newB && 
         existingC < newC) ||
        (existingA == newA && existingB == newB && 
         existingC == newC && existingD < newD)) {

      // We have a newer updater, so update the description from the INI file.
      UpdateServiceDescription(schService);

      schService.reset();
      if (!StopService()) {
        return FALSE;
      }

      if (!wcscmp(newServiceBinaryPath, serviceConfig.lpBinaryPathName)) {
        LOG(("File is already in the correct location, no action needed for "
             "upgrade.  The path is: \"%ls\"\n", newServiceBinaryPath));
        return TRUE;
      }

      BOOL result = TRUE;

      // Attempt to copy the new binary over top the existing binary.
      // If there is an error we try to move it out of the way and then
      // copy it in.  First try the safest / easiest way to overwrite the file.
      if (!CopyFileW(newServiceBinaryPath, 
                     serviceConfig.lpBinaryPathName, FALSE)) {
        LOG(("Could not overwrite old service binary file. "
             "This should never happen, but if it does the next upgrade will "
             "fix it, the service is not a critical component that needs to be "
             "installed for upgrades to work. (%d)\n", GetLastError()));

        // We rename the last 3 filename chars in an unsafe way.  Manually
        // verify there are more than 3 chars for safe failure in MoveFileExW.
        const size_t len = wcslen(serviceConfig.lpBinaryPathName);
        if (len > 3) {
          // Calculate the temp file path that we're moving the file to. This 
          // is the same as the proper service path but with a .old extension.
          LPWSTR oldServiceBinaryTempPath = 
            new WCHAR[len + 1];
          memset(oldServiceBinaryTempPath, 0, (len + 1) * sizeof (WCHAR));
          wcsncpy(oldServiceBinaryTempPath, serviceConfig.lpBinaryPathName, len);
          // Rename the last 3 chars to 'old'
          wcsncpy(oldServiceBinaryTempPath + len - 3, L"old", 3);

          // Move the current (old) service file to the temp path.
          if (MoveFileExW(serviceConfig.lpBinaryPathName, 
                          oldServiceBinaryTempPath, 
                          MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
            // The old binary is moved out of the way, copy in the new one.
            if (!CopyFileW(newServiceBinaryPath, 
                           serviceConfig.lpBinaryPathName, FALSE)) {
              // It is best to leave the old service binary in this condition.
              LOG(("ERROR: The new service binary could not be copied in."
                   " The service will not be upgraded.\n"));
              result = FALSE;
            } else {
              LOG(("The new service binary was copied in by first moving the"
                   " old one out of the way.\n"));
            }

            // Attempt to get rid of the old service temp path.
            if (DeleteFileW(oldServiceBinaryTempPath)) {
              LOG(("The old temp service path was deleted: %ls.\n", 
                   oldServiceBinaryTempPath));
            } else {
              // The old temp path could not be removed.  It will be removed
              // the next time the user can't copy the binary in or on uninstall.
              LOG(("WARNING: The old temp service path was not deleted.\n"));
            }
          } else {
            // It is best to leave the old service binary in this condition.
            LOG(("ERROR: Could not move old service file out of the way from:"
                 " \"%ls\" to \"%ls\". Service will not be upgraded. (%d)\n", 
                 serviceConfig.lpBinaryPathName, 
                 oldServiceBinaryTempPath, GetLastError()));
            result = FALSE;
          }
          delete[] oldServiceBinaryTempPath;
        } else {
            // It is best to leave the old service binary in this condition.
            LOG(("ERROR: Service binary path was less than 3, service will"
                 " not be updated.  This should never happen.\n"));
            result = FALSE;
        }
      } else {
        LOG(("The new service binary was copied in.\n"));
      }

      // We made a copy of ourselves to the existing location.
      // The tmp file (the process of which we are executing right now) will be
      // left over.  Attempt to delete the file on the next reboot.
      if (MoveFileExW(newServiceBinaryPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) {
        LOG(("Deleting the old file path on the next reboot: %ls.\n", 
             newServiceBinaryPath));
      } else {
        LOG(("Call to delete the old file path failed: %ls.\n", 
             newServiceBinaryPath));
      }
      
      return result;
    }

    // We don't need to copy ourselves to the existing location.
    // The tmp file (the process of which we are executing right now) will be
    // left over.  Attempt to delete the file on the next reboot.
    MoveFileExW(newServiceBinaryPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
    
    // nothing to do, we already have a newer service installed
    return TRUE; 
  }
  
  // If the service does not exist and we are upgrading, don't install it.
  if (UpgradeSvc == action) {
    // The service does not exist and we are upgrading, so don't install it
    return TRUE;
  }

  // Quote the path only if it contains spaces.
  PathQuoteSpacesW(newServiceBinaryPath);
  // The service does not already exist so create the service as on demand
  schService.own(CreateServiceW(schSCManager, SVC_NAME, SVC_DISPLAY_NAME,
                                SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
                                SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
                                newServiceBinaryPath, NULL, NULL, NULL, 
                                NULL, NULL));
  if (!schService) {
    LOG(("Could not create Windows service. "
         "This error should never happen since a service install "
         "should only be called when elevated. (%d)\n", GetLastError()));
    return FALSE;
  } 

  if (!SetUserAccessServiceDACL(schService)) {
    LOG(("Could not set security ACE on service handle, the service will not "
         "be able to be started from unelevated processes. "
         "This error should never happen.  (%d)\n", 
         GetLastError()));
  }

  UpdateServiceDescription(schService);

  return TRUE;
}
Пример #7
0
extern "C" UINT __stdcall CheckServiceUpgrades(MSIHANDLE hInstall) 
{
  HRESULT hr = S_OK;
  UINT er = ERROR_SUCCESS;
  wchar_t* service= 0;
  wchar_t* dir= 0;
  wchar_t installerVersion[MAX_VERSION_PROPERTY_SIZE];
  char installDir[MAX_PATH];
  DWORD size =MAX_VERSION_PROPERTY_SIZE;
  int installerMajorVersion, installerMinorVersion, installerPatchVersion;
  bool upgradableServiceFound=false;

  hr = WcaInitialize(hInstall, __FUNCTION__);
   WcaLog(LOGMSG_STANDARD, "Initialized.");
  if (MsiGetPropertyW(hInstall, L"ProductVersion", installerVersion, &size) 
    != ERROR_SUCCESS)
  {
    hr = HRESULT_FROM_WIN32(GetLastError());
    ExitOnFailure(hr, "MsiGetPropertyW failed");
  }
   if (swscanf(installerVersion,L"%d.%d.%d",
    &installerMajorVersion, &installerMinorVersion, &installerPatchVersion) !=3)
  {
    assert(FALSE);
  }

  size= MAX_PATH;
  if (MsiGetPropertyA(hInstall,"INSTALLDIR", installDir, &size)
    != ERROR_SUCCESS)
  {
    hr = HRESULT_FROM_WIN32(GetLastError());
    ExitOnFailure(hr, "MsiGetPropertyW failed");
  }
 

  SC_HANDLE scm = OpenSCManager(NULL, NULL, 
    SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT);  
  if (scm == NULL) 
  { 
    hr = HRESULT_FROM_WIN32(GetLastError());
    ExitOnFailure(hr,"OpenSCManager failed");
  }

  static BYTE buf[64*1024];
  static BYTE config_buffer[8*1024];

  DWORD bufsize= sizeof(buf);
  DWORD bufneed;
  DWORD num_services;
  BOOL ok= EnumServicesStatusExW(scm, SC_ENUM_PROCESS_INFO,  SERVICE_WIN32,
    SERVICE_STATE_ALL,  buf, bufsize,  &bufneed, &num_services, NULL, NULL);
  if(!ok) 
  {
    hr = HRESULT_FROM_WIN32(GetLastError());
    ExitOnFailure(hr,"EnumServicesStatusEx failed");
  }
  LPENUM_SERVICE_STATUS_PROCESSW info =
    (LPENUM_SERVICE_STATUS_PROCESSW)buf;
  int index=-1;
  for (ULONG i=0; i < num_services; i++)
  {
    SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName, 
      SERVICE_QUERY_CONFIG);
    if (!service)
      continue;
    QUERY_SERVICE_CONFIGW *config= 
      (QUERY_SERVICE_CONFIGW*)(void *)config_buffer;
    DWORD needed;
    BOOL ok= QueryServiceConfigW(service, config,sizeof(config_buffer),
      &needed);
    CloseServiceHandle(service);
    if (ok)
    {
        mysqld_service_properties props;
       if (get_mysql_service_properties(config->lpBinaryPathName, &props))
                  continue;
        /* 
          Only look for services that have mysqld.exe outside of the current
          installation directory.
        */
       if(installDir[0] == 0 || strstr(props.mysqld_exe,installDir) == 0)
        {
           WcaLog(LOGMSG_STANDARD, "found service %S, major=%d, minor=%d",
            info[i].lpServiceName, props.version_major, props.version_minor);
          if(props.version_major < installerMajorVersion
            || (props.version_major == installerMajorVersion && 
                props.version_minor <= installerMinorVersion))
          {
            upgradableServiceFound= true;
            break;
          }
       }
    }
  }

  if(!upgradableServiceFound)
  {
    /* Disable optional checkbox at the end of installation */
    MsiSetPropertyW(hInstall, L"WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT", L"");
    MsiSetPropertyW(hInstall, L"WIXUI_EXITDIALOGOPTIONALCHECKBOX",L"");
  }
  else
  {
    MsiSetPropertyW(hInstall, L"UpgradableServiceFound", L"1");
    MsiSetPropertyW(hInstall, L"WIXUI_EXITDIALOGOPTIONALCHECKBOX",L"1");
  }
LExit:
  if(scm)
    CloseServiceHandle(scm);
  return WcaFinalize(er); 
}
Пример #8
0
/*
  Checks if database directory or service are modified by user
  For example, service may point to different mysqld.exe that it was originally
  installed, or some different service might use this database directory. This 
  would normally mean user has done an upgrade of the database and in this case 
  uninstall should neither delete service nor database directory.

  If this function find that service is modified by user (mysqld.exe used by 
  service does not point to the installation bin directory), MSI public variable
  SERVICENAME is removed, if DATADIR is used by some other service, variables 
  DATADIR and CLEANUPDATA are removed.

  The effect of variable removal is that service does not get uninstalled and
  datadir is not touched by uninstallation.

  Note that this function is running without elevation and does not use anything
  that would require special privileges.

*/
extern "C" UINT CheckDBInUse(MSIHANDLE hInstall)
{
  static BYTE buf[256*1024]; /* largest possible buffer for EnumServices */
  static char config_buffer[8*1024]; /*largest buffer for QueryServiceConfig */
  HRESULT hr = S_OK;
  UINT er = ERROR_SUCCESS;
  wchar_t *servicename= NULL;
  wchar_t *datadir= NULL;
  wchar_t *bindir=NULL;

  SC_HANDLE scm    = NULL; 
  ULONG  bufsize   = sizeof(buf); 
  ULONG  bufneed   = 0x00; 
  ULONG  num_services = 0x00; 
  LPENUM_SERVICE_STATUS_PROCESS info = NULL;  

  hr = WcaInitialize(hInstall, __FUNCTION__);
  ExitOnFailure(hr, "Failed to initialize");
  WcaLog(LOGMSG_STANDARD, "Initialized.");

  WcaGetProperty(L"SERVICENAME", &servicename);
  WcaGetProperty(L"DATADIR", &datadir);
  WcaGetFormattedString(L"[INSTALLDIR]bin\\", &bindir);
  WcaLog(LOGMSG_STANDARD,"SERVICENAME=%S, DATADIR=%S, bindir=%S",
    servicename, datadir, bindir);

  scm = OpenSCManager(NULL, NULL, 
    SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT);  
  if (scm == NULL) 
  { 
    ExitOnFailure(E_FAIL, "OpenSCManager failed");
  }

  BOOL ok= EnumServicesStatusExW(  scm,
    SC_ENUM_PROCESS_INFO, 
    SERVICE_WIN32,
    SERVICE_STATE_ALL,  
    buf, 
    bufsize,  
    &bufneed,  
    &num_services,  
    NULL, 
    NULL);
  if(!ok) 
  {
    WcaLog(LOGMSG_STANDARD, "last error %d", GetLastError());
    ExitOnFailure(E_FAIL, "EnumServicesStatusExW failed");
  }
  info = (LPENUM_SERVICE_STATUS_PROCESS)buf; 
  for (ULONG i=0; i < num_services; i++)
  {
    SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName, 
      SERVICE_QUERY_CONFIG);
    if (!service)
      continue;
    WcaLog(LOGMSG_VERBOSE, "Checking Service %S", info[i].lpServiceName);
    QUERY_SERVICE_CONFIGW *config= 
      (QUERY_SERVICE_CONFIGW *)(void *)config_buffer;
    DWORD needed;
    BOOL ok= QueryServiceConfigW(service, config,sizeof(config_buffer), 
      &needed);
    CloseServiceHandle(service);
    if (ok)
    {
       CheckServiceConfig(servicename, datadir, bindir, info[i].lpServiceName, 
         config);
    }
  }

LExit:
  if(scm)
    CloseServiceHandle(scm);

  ReleaseStr(servicename);
  ReleaseStr(datadir);
  ReleaseStr(bindir);
  return WcaFinalize(er); 
}
Пример #9
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;
}
Пример #10
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;
}
Пример #11
0
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;
}