void Service::install() { // Open service manager SC_HANDLE pSCM = OpenSCManagerW( nullptr, nullptr, SC_MANAGER_CREATE_SERVICE ); if ( !pSCM ) EXCEPT_WINAPI( L"Couldn't open service manager" ); // Fetch & escape path, add argument WCHAR wszPath[MAX_PATH]; if ( !GetModuleFileNameW( nullptr, wszPath, MAX_PATH ) ) EXCEPT_WINAPI( L"Couldn't get module file name" ); PathQuoteSpacesW( wszPath ); wcscat_s( wszPath, MAX_PATH, L" -s" ); // Create service SC_HANDLE hService = CreateServiceW( pSCM, mName.c_str(), mDisplayName.c_str(), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, wszPath, nullptr, nullptr, nullptr, L"NT AUTHORITY\\NetworkService", nullptr ); if ( !hService ) EXCEPT_WINAPI( L"Couldn't create service" ); // Set description SERVICE_DESCRIPTIONW descriptor; descriptor.lpDescription = new WCHAR[mDescription.length()]; wcscpy_s( descriptor.lpDescription, mDescription.length(), mDescription.c_str() ); ChangeServiceConfig2W( hService, SERVICE_CONFIG_DESCRIPTION, &descriptor ); delete[] descriptor.lpDescription; // Done CloseServiceHandle( hService ); CloseServiceHandle( pSCM ); }
static BOOL set_service_comment(wchar_t *comment) { SC_HANDLE scm; SC_HANDLE service; SERVICE_DESCRIPTIONW sd; BOOL ret = TRUE; sd.lpDescription = comment; if (!open_service_config(&scm,&service)) { return FALSE; } if (!ChangeServiceConfig2W(service,SERVICE_CONFIG_DESCRIPTION,&sd)) { last_error = GetLastError(); ret = FALSE; } CloseServiceHandle(service); CloseServiceHandle(scm); return ret; }
BOOL SetServiceDescription(LPWSTR lpServiceName, LPWSTR lpDescription) { SC_HANDLE hSCManager; SC_HANDLE hSc; SC_LOCK scLock; SERVICE_DESCRIPTION ServiceDescription; 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) { ServiceDescription.lpDescription = lpDescription; if (ChangeServiceConfig2W(hSc, SERVICE_CONFIG_DESCRIPTION, &ServiceDescription)) { bRet = TRUE; } CloseServiceHandle(hSc); } UnlockServiceDatabase(scLock); } CloseServiceHandle(hSCManager); } if (!bRet) GetError(); return bRet; }
/* 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; }
/****************************************************************** CaExecServiceConfig - entry point for ServiceConfig Custom Action called as Type 1025 CustomAction (deferred binary DLL) NOTE: deferred CustomAction since it modifies the machine NOTE: CustomActionData == wzServiceName\twzFirstFailureActionType\twzSecondFailureActionType\twzThirdFailureActionType\tdwResetPeriodInDays\tdwRestartServiceDelayInSeconds\twzProgramCommandLine\twzRebootMessage\twzServiceName\t... *******************************************************************/ extern "C" UINT __stdcall ExecServiceConfig( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug ExecServiceConfig"); HRESULT hr = S_OK; UINT uiResult = ERROR_SUCCESS; DWORD dwError = 0; LPVOID lpMsgBuf = NULL; LPWSTR pwzData = NULL; LPWSTR pwz = NULL; LPWSTR pwzServiceName = NULL; LPWSTR pwzFirstFailureActionType = NULL; LPWSTR pwzSecondFailureActionType = NULL; LPWSTR pwzThirdFailureActionType = NULL; LPWSTR pwzProgramCommandLine = NULL; LPWSTR pwzRebootMessage = NULL; DWORD dwResetPeriodInDays = 0; DWORD dwRestartServiceDelayInSeconds = 0; SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; DWORD dwOpenServiceAccess = SERVICE_CHANGE_CONFIG; // SERVICE_CHANGE_CONFIG is needed for ChangeServiceConfig2() SERVICE_FAILURE_ACTIONSW sfa; SC_ACTION actions[3]; BOOL fResult = FALSE; // initialize hr = WcaInitialize(hInstall, "ExecServiceConfig"); ExitOnFailure(hr, "failed to initialize"); hr = WcaGetProperty( L"CustomActionData", &pwzData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %S", pwzData); pwz = pwzData; // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzServiceName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzFirstFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzSecondFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzThirdFailureActionType); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwResetPeriodInDays)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwRestartServiceDelayInSeconds)); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzProgramCommandLine); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzRebootMessage); ExitOnFailure(hr, "failed to process CustomActionData"); WcaLog(LOGMSG_VERBOSE, "Configuring Service: %S", pwzServiceName); // build up SC_ACTION array // TODO: why is delay only respected when SC_ACTION_RESTART is requested? actions[0].Type = GetSCActionType(pwzFirstFailureActionType); actions[0].Delay = 0; if (SC_ACTION_RESTART == actions[0].Type) { actions[0].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds dwOpenServiceAccess |= SERVICE_START; // must have SERVICE_START access in order to handle SC_ACTION_RESTART action; } actions[1].Type = GetSCActionType(pwzSecondFailureActionType); actions[1].Delay = 0; if (SC_ACTION_RESTART == actions[1].Type) { actions[1].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds dwOpenServiceAccess |= SERVICE_START; // must have SERVICE_START access in order to handle SC_ACTION_RESTART action; } actions[2].Type = GetSCActionType(pwzThirdFailureActionType); actions[2].Delay = 0; if (SC_ACTION_RESTART == actions[2].Type) { actions[2].Delay = dwRestartServiceDelayInSeconds * 1000; // seconds to milliseconds dwOpenServiceAccess |= SERVICE_START; // must have SERVICE_START access in order to handle SC_ACTION_RESTART action; } // build up the SERVICE_FAILURE_ACTIONSW struct sfa.dwResetPeriod = dwResetPeriodInDays * 24 * 60 * 60; // days to seconds sfa.lpRebootMsg = pwzRebootMessage; sfa.lpCommand = pwzProgramCommandLine; sfa.cActions = 3; // the UI always shows 3 actions, so we'll always do 3 sfa.lpsaActions = actions; // Get a handle to the service control manager (if we don't already have) if (NULL == hSCM) { hSCM = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (hSCM == NULL) { dwError = ::GetLastError(); ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); ExitOnFailure1(hr = HRESULT_FROM_WIN32(dwError), "failed to get handle to SCM. Error: %S", (LPWSTR)lpMsgBuf); } } hService = ::OpenServiceW(hSCM, pwzServiceName, dwOpenServiceAccess); if (hService == NULL) { dwError = ::GetLastError(); hr = HRESULT_FROM_WIN32(dwError); if (dwError == ERROR_SERVICE_DOES_NOT_EXIST) { ExitOnFailure1(hr, "Service \"%S\" does not exist on this system.", pwzServiceName); } else { ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); ExitOnFailure2(hr, "Failed to get handle to the service \"%S\". Error: %S", pwzServiceName, (LPWSTR)lpMsgBuf); } } // Call ChangeServiceConfig2 to actually set up the failure actions fResult = ChangeServiceConfig2W(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPVOID)&sfa); if (fResult == FALSE) { dwError = ::GetLastError(); hr = HRESULT_FROM_WIN32(dwError); ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL); // check if this is a service that can't be modified if(dwError == ERROR_CANNOT_DETECT_PROCESS_ABORT) { WcaLog(LOGMSG_STANDARD, "WARNING: Service \"%S\" is not configurable on this server and will not be set.", pwzServiceName); } ExitOnFailure1(hr, "Cannot change service configuration. Error: %S", (LPWSTR)lpMsgBuf); } // Per-service cleanup dwResetPeriodInDays = 0; dwRestartServiceDelayInSeconds = 0; hr = WcaProgressMessage(COST_SERVICECONFIG, FALSE); ExitOnFailure(hr, "failed to send progress message"); } LExit: // Clean up handles ReleaseStr(pwzServiceName); ReleaseStr(pwzFirstFailureActionType); ReleaseStr(pwzSecondFailureActionType); ReleaseStr(pwzThirdFailureActionType); ReleaseStr(pwzProgramCommandLine); ReleaseStr(pwzRebootMessage); ReleaseStr(pwzData); if (lpMsgBuf) // Allocated with FormatString ::LocalFree(lpMsgBuf); if (hService) ::CloseServiceHandle(hService); if (hSCM) ::CloseServiceHandle(hSCM); if (FAILED(hr)) uiResult = ERROR_INSTALL_FAILURE; return WcaFinalize(uiResult); }
/** * Updates the service description with what is stored in updater.ini * at the same path as the currently executing module binary. * * @param serviceHandle A handle to an opened service with * SERVICE_CHANGE_CONFIG access right * @param TRUE on succcess. */ BOOL UpdateServiceDescription(SC_HANDLE serviceHandle) { WCHAR updaterINIPath[MAX_PATH + 1]; if (!GetModuleFileNameW(NULL, updaterINIPath, sizeof(updaterINIPath) / sizeof(updaterINIPath[0]))) { LOG(("Could not obtain module filename when attempting to " "modify service description. (%d)\n", GetLastError())); return FALSE; } if (!PathRemoveFileSpecW(updaterINIPath)) { LOG(("Could not remove file spec when attempting to " "modify service description. (%d)\n", GetLastError())); return FALSE; } if (!PathAppendSafe(updaterINIPath, L"updater.ini")) { LOG(("Could not append updater.ini filename when attempting to " "modify service description. (%d)\n", GetLastError())); return FALSE; } if (GetFileAttributesW(updaterINIPath) == INVALID_FILE_ATTRIBUTES) { LOG(("updater.ini file does not exist, will not modify " "service description. (%d)\n", GetLastError())); return FALSE; } MaintenanceServiceStringTable serviceStrings; int rv = ReadMaintenanceServiceStrings(updaterINIPath, &serviceStrings); if (rv != OK || !strlen(serviceStrings.serviceDescription)) { LOG(("updater.ini file does not contain a maintenance " "service description.\n")); return FALSE; } WCHAR serviceDescription[MAX_TEXT_LEN]; if (!MultiByteToWideChar(CP_UTF8, 0, serviceStrings.serviceDescription, -1, serviceDescription, sizeof(serviceDescription) / sizeof(serviceDescription[0]))) { LOG(("Could not convert description to wide string format (%d)\n", GetLastError())); return FALSE; } SERVICE_DESCRIPTIONW descriptionConfig; descriptionConfig.lpDescription = serviceDescription; if (!ChangeServiceConfig2W(serviceHandle, SERVICE_CONFIG_DESCRIPTION, &descriptionConfig)) { LOG(("Could not change service config (%d)\n", GetLastError())); return FALSE; } LOG(("The service description was updated successfully.\n")); return TRUE; }