/****************************** Module Header ******************************\ * Module Name: ServiceInstaller.cpp * Project: CppWindowsService * Copyright (c) Microsoft Corporation. * * The file implements functions that install and uninstall the service. * * This source is subject to the Microsoft Public License. * See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL. * All other rights reserved. * * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. \***************************************************************************/ #pragma region "Includes" #include "ServiceBase.h" #include "ServiceInstaller.h" #pragma endregion static bool LogError(const char* funcname) { fprintf(stderr, "%s failed with error 0x%08lx\n", funcname, GetLastError()); return false; } class SCManager { SC_HANDLE _handle; public: bool IsOk() const { return _handle != NULL; } operator SC_HANDLE() const { return _handle; } bool Start(LPCTSTR pszServiceName); bool Stop(LPCTSTR pszServiceName); bool Delete(LPCTSTR pszServiceName); SCManager(DWORD mode) { _handle = ::OpenSCManager(NULL, NULL, mode); if (_handle == NULL) LogError("OpenSCManager"); } ~SCManager() { if (_handle != NULL) CloseServiceHandle(_handle); } }; bool SCManager::Stop(LPCTSTR pszServiceName) { bool bDone = false; if (IsOk()) { // Open the service with delete, stop, and query status permissions SC_HANDLE schService = ::OpenService(_handle, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS); if (schService == NULL) { LogError("OpenService"); return false; } // Try to stop the service SERVICE_STATUS ssSvcStatus = {}; if (::ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus)) { wprintf(L"Stopping %s.", pszServiceName); while (::QueryServiceStatus(schService, &ssSvcStatus)) { if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING) { wprintf(L"."); Sleep(1000); } else break; } bDone = ssSvcStatus.dwCurrentState == SERVICE_STOPPED; wprintf(L"\n"); } ::CloseServiceHandle(schService); if (bDone) wprintf(L"\n%s is stopped.\n", pszServiceName); else wprintf(L"\n%s failed to stop.\n", pszServiceName); } return bDone; } bool SCManager::Start(LPCTSTR pszServiceName) { bool bDone = false; if (IsOk()) { SC_HANDLE schService = OpenService(_handle, pszServiceName, SERVICE_START); if (schService) { bDone = ::StartService(schService, 0, NULL) != 0; if (bDone) wprintf(L"%s started.\n", pszServiceName); else LogError("StartService"); } else LogError("OpenService"); } return bDone; } bool SCManager::Delete(LPCTSTR pszServiceName) { bool bDone = false; if (IsOk()) { // Open the service with delete, stop, and query status permissions SC_HANDLE schService = ::OpenService(_handle, pszServiceName, DELETE); if (schService) { // Now remove the service by calling DeleteService. bDone = ::DeleteService(schService) != 0; if (bDone) wprintf(L"%s has been removed.\n", pszServiceName); else LogError("DeleteService"); // Centralized cleanup for all allocated resources. if (schService) { CloseServiceHandle(schService); schService = NULL; } } else LogError("OpenService"); } return bDone; } // // FUNCTION: InstallService // // PURPOSE: Install the current application as a service to the local // service control manager database. // // PARAMETERS: // * pszServiceName - the name of the service to be installed // * pszDisplayName - the display name of the service // * dwStartType - the service start option. This parameter can be one of // the following values: SERVICE_AUTO_START, SERVICE_BOOT_START, // SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START. // * pszDependencies - a pointer to a double null-terminated array of null- // separated names of services or load ordering groups that the system // must start before this service. // * pszAccount - the name of the account under which the service runs. // * pszPassword - the password to the account name. // // NOTE: If the function fails to install the service, it prints the error // in the standard output stream for users to diagnose the problem. // void InstallService(LPCTSTR pszServiceName, LPCTSTR pszDisplayName, DWORD dwStartType, LPCTSTR pszDependencies, LPCTSTR pszAccount, LPCTSTR pszPassword) { TCHAR szPath[MAX_PATH]; if (::GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0) { LogError("GetModuleFileName"); return; } // Open the local default service control manager database SCManager schSCManager(SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); if (schSCManager.IsOk()) { // Install the service into SCM by calling CreateService SC_HANDLE schService = ::CreateService( schSCManager, // SCManager database pszServiceName, // Name of service pszDisplayName, // Name to display SERVICE_QUERY_STATUS, // Desired access SERVICE_WIN32_OWN_PROCESS, // Service type dwStartType, // Service start type SERVICE_ERROR_NORMAL, // Error control type szPath, // Service's binary NULL, // No load ordering group NULL, // No tag identifier pszDependencies, // Dependencies pszAccount, // Service running account pszPassword // Password of the account ); if (schService != NULL) { wprintf(L"%s has been installed.\n", pszServiceName); CloseServiceHandle(schService); } else LogError("CreateService"); } } // // FUNCTION: UninstallService // // PURPOSE: Stop and remove the service from the local service control // manager database. // // PARAMETERS: // * pszServiceName - the name of the service to be removed. // // NOTE: If the function fails to uninstall the service, it prints the // error in the standard output stream for users to diagnose the problem. // void UninstallService(PWSTR pszServiceName) { // Open the local default service control manager database SCManager schSCManager(SC_MANAGER_CONNECT); if (schSCManager.IsOk()) { schSCManager.Stop(pszServiceName); schSCManager.Delete(pszServiceName); } } void StartService(PWSTR pszServiceName) { SCManager schSCManager(SC_MANAGER_CONNECT); if (schSCManager.IsOk()) schSCManager.Start(pszServiceName); } void StopService(PWSTR pszServiceName) { SCManager schSCManager(SC_MANAGER_CONNECT); if (schSCManager.IsOk()) schSCManager.Stop(pszServiceName); }