当前位置: 首页 > news >正文

Windows下服务封装

支持功能

1、服务器安装/卸载
2、服务启动/停止
3、服务停止操作启用/禁用
4、服务恢复操作启用/禁用
5、程序启动模式(普通、服务)

代码封装

ServiceHandle.h

#pragma once
#include <string>#define SERVICE_CTRL_INST    ServiceHandle::Instance()
class ServiceHandle
{const std::string kServiceName = "TestService";
public:static ServiceHandle& Instance() {static ServiceHandle g_inst;return g_inst;}bool CheckSystemSession();bool InstallService();bool CusStartService();bool CusStopService();bool UninstallService();std::wstring GetServiceName();bool CheckSupportStop() { return m_bSupportStop; }bool CheckSupportRecoveryConfig() { return m_bEnableRecoveryConfig; }int Run();private:bool install_service(const std::string& strServiceName);bool start_service(const std::string& strServiceName);bool stop_service(const std::string& strServiceName);bool uninstall_service(const std::string& strServiceName);private:bool m_bSupportStop = false;bool m_bEnableRecoveryConfig = false;};

ServiceHandle.cpp

#include "ServiceHandle.h"
#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <aclapi.h>
#include <sddl.h>
#include "Conversion.h"bool SetServiceRecoveryActions(SC_HANDLE schService)
{SERVICE_FAILURE_ACTIONS failureActions;SC_ACTION actions[3];// 3 Minint nRestartMSSeconds = 3 * 60 * 1000;// first failure:restartactions[0].Type = SC_ACTION_RESTART;actions[0].Delay = nRestartMSSeconds;// second failure:restartactions[1].Type = SC_ACTION_RESTART;actions[1].Delay = nRestartMSSeconds;// and then:actions[2].Type = SC_ACTION_RUN_COMMAND;actions[2].Delay = 0;// 0: ignore it// reset recovery info in(24 hours)failureActions.dwResetPeriod = 86400;failureActions.lpRebootMsg = NULL;failureActions.lpCommand = NULL;
#if 0failureActions.lpCommand = (wchar_t*)L"cmd.exe /c echo Service failed at %date% %time% >> C:\\ServiceFailureLog.txt";
#endiffailureActions.cActions = 3;failureActions.lpsaActions = actions;bool bSucc = false;if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &failureActions)){std::cout << "Failed to set service recovery actions: " << GetLastError() << std::endl;}else{std::cout << "Service recovery actions set successfully." << std::endl;bSucc = true;}return bSucc;
}bool RestrictServiceConfigurationAccess(SC_HANDLE schService)
{// check support recovery config enable, if on, user can modify it via UI configif (SERVICE_CTRL_INST.CheckSupportRecoveryConfig()) return true;PSECURITY_DESCRIPTOR pSecDesc = NULL;DWORD dwBytesNeeded = 0;if (!QueryServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, pSecDesc, 0, &dwBytesNeeded)){if (GetLastError() != ERROR_INSUFFICIENT_BUFFER){std::cout << "QueryServiceObjectSecurity failed: " << GetLastError() << std::endl;return false;}}pSecDesc = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwBytesNeeded);if (pSecDesc == NULL){std::cout << "LocalAlloc failed: " << GetLastError() << std::endl;return false;}if (!QueryServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, pSecDesc, dwBytesNeeded, &dwBytesNeeded)){std::cout << "QueryServiceObjectSecurity failed: " << GetLastError() << std::endl;LocalFree(pSecDesc);return false;}PACL pDacl = NULL;BOOL bDaclPresent = FALSE;BOOL bDaclDefaulted = FALSE;if (!GetSecurityDescriptorDacl(pSecDesc, &bDaclPresent, &pDacl, &bDaclDefaulted)){std::cout << "GetSecurityDescriptorDacl failed: " << GetLastError() << std::endl;LocalFree(pSecDesc);return false;}// create EXPLICIT_ACCESS with 3 itemsEXPLICIT_ACCESS ea[3];ZeroMemory(ea, sizeof(EXPLICIT_ACCESS) * 3);// administratorea[0].grfAccessPermissions = SERVICE_ALL_ACCESS;ea[0].grfAccessMode = SET_ACCESS;ea[0].grfInheritance = NO_INHERITANCE;ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;ea[0].Trustee.ptstrName = (LPTSTR)L"Administrators";// systemea[1].grfAccessPermissions = SERVICE_ALL_ACCESS;ea[1].grfAccessMode = SET_ACCESS;ea[1].grfInheritance = NO_INHERITANCE;ea[1].Trustee.TrusteeForm = TRUSTEE_IS_NAME;ea[1].Trustee.TrusteeType = TRUSTEE_IS_USER;ea[1].Trustee.ptstrName = (LPTSTR)L"SYSTEM";// refuse other userea[2].grfAccessPermissions = SERVICE_CHANGE_CONFIG;ea[2].grfAccessMode = DENY_ACCESS;ea[2].grfInheritance = NO_INHERITANCE;ea[2].Trustee.TrusteeForm = TRUSTEE_IS_NAME;ea[2].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;ea[2].Trustee.ptstrName = (LPTSTR)L"Everyone";PACL pNewDacl = NULL;DWORD dwError = SetEntriesInAcl(3, ea, pDacl, &pNewDacl);if (dwError != ERROR_SUCCESS){std::cout << "SetEntriesInAcl failed: " << dwError << std::endl;LocalFree(pSecDesc);return false;}// create new sdSECURITY_DESCRIPTOR sd;if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)){std::cout << "InitializeSecurityDescriptor failed: " << GetLastError() << std::endl;LocalFree(pNewDacl);LocalFree(pSecDesc);return false;}if (!SetSecurityDescriptorDacl(&sd, TRUE, pNewDacl, FALSE)){std::cout << "SetSecurityDescriptorDacl failed: " << GetLastError() << std::endl;LocalFree(pNewDacl);LocalFree(pSecDesc);return false;}// config security infoif (!SetServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, &sd)){std::cout << "SetServiceObjectSecurity failed: " << GetLastError() << std::endl;LocalFree(pNewDacl);LocalFree(pSecDesc);return false;}std::cout << "Service configuration access restricted successfully." << std::endl;std::cout << "Only Administrators and SYSTEM can modify service configuration." << std::endl;// freeLocalFree(pNewDacl);LocalFree(pSecDesc);return true;
}bool ServiceHandle::CheckSystemSession()
{DWORD nSessionId = -1;if (!ProcessIdToSessionId(GetCurrentProcessId(), &nSessionId)) {std::cout << "Get session id failed: " << GetLastError() << "\n";return false;}return (0 == nSessionId) ? true : false;
}bool ServiceHandle::InstallService()
{if (install_service(kServiceName)) {return start_service(kServiceName);}return false;
}bool ServiceHandle::CusStartService()
{return start_service(kServiceName);
}bool ServiceHandle::CusStopService()
{return stop_service(kServiceName);
}bool ServiceHandle::UninstallService()
{if (stop_service(kServiceName)) {// note: it needs wait for process exit while delete servicereturn uninstall_service(kServiceName);}return false;
}std::wstring ServiceHandle::GetServiceName()
{std::wstring wstrServiceName(L"CustTestService");{std::wstring wstrTmp = Utils::Utf8ToUtf16(kServiceName);if (!wstrTmp.empty())wstrServiceName = wstrTmp;}return wstrServiceName;
}/**********************************************************************************
*                               service config                                    *
***********************************************************************************/
// global info
SERVICE_STATUS g_statusService = { 0 };
SERVICE_STATUS_HANDLE g_hServiceStatus = NULL;
std::wstring g_wstrLogPath = L"C:\\SampleServiceLog.txt";
HANDLE g_hEvent = NULL;
void LogMessage(const std::wstring& message)
{std::wofstream logFile;logFile.open(g_wstrLogPath, std::ios_base::app);if (logFile.is_open()){SYSTEMTIME st;GetLocalTime(&st);logFile << L"[" << st.wYear << L"-" << st.wMonth << L"-" << st.wDay<< L" " << st.wHour << L":" << st.wMinute << L":" << st.wSecond<< L"] " << message << std::endl;logFile.close();}
}void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{static DWORD dwCheckPoint = 1;g_statusService.dwCurrentState = dwCurrentState;g_statusService.dwWin32ExitCode = dwWin32ExitCode;g_statusService.dwWaitHint = dwWaitHint;if ((dwCurrentState == SERVICE_RUNNING) ||(dwCurrentState == SERVICE_STOPPED))g_statusService.dwCheckPoint = 0;else {g_statusService.dwCheckPoint = dwCheckPoint++;// don't accept stop, if 0: ignore all actionif(SERVICE_CTRL_INST.CheckSupportStop())g_statusService.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;elseg_statusService.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;}SetServiceStatus(g_hServiceStatus, &g_statusService);
}VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{switch (CtrlCode){case SERVICE_CONTROL_STOP:LogMessage(L"Service stop triggered");ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);SetEvent(g_hEvent);break;case SERVICE_CONTROL_INTERROGATE:ReportServiceStatus(g_statusService.dwCurrentState, NO_ERROR, 0);break;default:break;}
}DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{LogMessage(L"Service started successfully.");while (WaitForSingleObject(g_hEvent, 5000) != WAIT_OBJECT_0){SYSTEMTIME st;GetLocalTime(&st);std::wstring timeStr = std::to_wstring(st.wHour) + L":" +std::to_wstring(st.wMinute) + L":" +std::to_wstring(st.wSecond);LogMessage(L"Service is running at " + timeStr);}LogMessage(L"Service is stopping...");return ERROR_SUCCESS;
}std::wstring g_wstrEvtName(L"Global\\EvtTestServer");
void create_event()
{if (SERVICE_CTRL_INST.CheckSupportStop()) {g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);return;}if (NULL == g_hEvent) {SECURITY_ATTRIBUTES sa;sa.nLength = sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor = NULL;sa.bInheritHandle = TRUE;// common user supportPSECURITY_DESCRIPTOR pSD = NULL;if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(A;;GA;;;AU)",1,//SDDL_REVISION_1,&pSD,NULL)) {}sa.lpSecurityDescriptor = pSD;g_hEvent = CreateEvent(&sa, FALSE, FALSE, g_wstrEvtName.c_str());}
}void init_service()
{// register service handlestd::wstring wstrServiceName = SERVICE_CTRL_INST.GetServiceName();g_hServiceStatus = RegisterServiceCtrlHandler(wstrServiceName.c_str(), ServiceCtrlHandler);if (g_hServiceStatus == NULL){return;}// init service stateg_statusService.dwServiceType = SERVICE_WIN32_OWN_PROCESS;g_statusService.dwServiceSpecificExitCode = 0;ReportServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000);// create eventcreate_event();if (g_hEvent == NULL){ReportServiceStatus(SERVICE_STOPPED, GetLastError(), 0);return;}ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 0);
}VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{init_service();HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);WaitForSingleObject(hThread, INFINITE);CloseHandle(g_hEvent);ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
}int ServiceHandle::Run()
{std::wstring wstrServiceName = SERVICE_CTRL_INST.GetServiceName();SERVICE_TABLE_ENTRY ServiceTable[] ={{ (LPWSTR)wstrServiceName.c_str(), (LPSERVICE_MAIN_FUNCTION)ServiceMain },{ NULL, NULL }};if (StartServiceCtrlDispatcher(ServiceTable) == FALSE){LogMessage(L"Service control dispatcher failed: " + std::to_wstring(GetLastError()));return GetLastError();}return 0;
}/**********************************************************************************
*                               private function                                  *
***********************************************************************************/
bool ServiceHandle::install_service(const std::string& strServiceName)
{bool bSucc = false;std::wstring wstrServiceName = Utils::Utf8ToUtf16(strServiceName);if (wstrServiceName.empty()) {std::cout << "Convert error for service name: " << strServiceName << "\n";return bSucc;}SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (schSCManager == NULL){std::cout << "OpenSCManager failed: " << GetLastError() << std::endl;return bSucc;}wchar_t path[MAX_PATH];GetModuleFileName(NULL, path, MAX_PATH);SC_HANDLE schService = CreateService(schSCManager,wstrServiceName.c_str(),wstrServiceName.c_str(),SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,  // auto startSERVICE_ERROR_NORMAL,path,NULL,NULL,NULL,NULL,NULL);if (schService == NULL){DWORD error = GetLastError();if (error == ERROR_SERVICE_EXISTS){bSucc = true;std::cout << "Service already exists. Reconfiguring..." << std::endl;schService = OpenService(schSCManager, wstrServiceName.c_str(), SERVICE_ALL_ACCESS | WRITE_DAC);if (schService){SetServiceRecoveryActions(schService);RestrictServiceConfigurationAccess(schService);CloseServiceHandle(schService);}}else{std::cout << "CreateService failed: " << error << std::endl;}}else{bSucc = true;std::cout << "Service installed successfully." << std::endl;SetServiceRecoveryActions(schService);RestrictServiceConfigurationAccess(schService);CloseServiceHandle(schService);}CloseServiceHandle(schSCManager);return bSucc;
}bool ServiceHandle::start_service(const std::string& strServiceName)
{bool bSucc = false;SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (schSCManager == NULL){std::cout << "OpenSCManager failed: " << GetLastError() << std::endl;return bSucc;}SC_HANDLE schService = OpenServiceA(schSCManager, strServiceName.c_str(), SERVICE_START | SERVICE_QUERY_STATUS);if (schService == NULL){std::cout << "OpenService failed: " << GetLastError() << std::endl;CloseServiceHandle(schSCManager);return false;}BOOL bOK = ::StartService(schService, 0, NULL);if (!bOK){DWORD error = GetLastError();if (error == ERROR_SERVICE_ALREADY_RUNNING){std::cout << "Service is already running." << std::endl;CloseServiceHandle(schService);CloseServiceHandle(schSCManager);return true;}else{std::cout << "StartService failed: " << error << std::endl;CloseServiceHandle(schService);CloseServiceHandle(schSCManager);return false;}}std::cout << "Service start request sent successfully." << std::endl;SERVICE_STATUS status;int waitCount = 0;while (waitCount < 10){// query status needs SERVICE_QUERY_STATUSif (!QueryServiceStatus(schService, &status)){std::cout << "QueryServiceStatus failed: " << GetLastError() << std::endl;break;}if (status.dwCurrentState == SERVICE_RUNNING){std::cout << "Service is running." << std::endl;break;}Sleep(1000);waitCount++;}if (waitCount >= 10){std::cout << "Service did not start within the expected time." << std::endl;}CloseServiceHandle(schService);CloseServiceHandle(schSCManager);return bOK;
}bool ServiceHandle::stop_service(const std::string& strServiceName)
{bool bSucc = false;SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (schSCManager == NULL){std::cout << "OpenSCManager failed: " << GetLastError() << std::endl;return bSucc;}SC_HANDLE schService = OpenServiceA(schSCManager, strServiceName.c_str(), SERVICE_STOP | DELETE | WRITE_DAC | SERVICE_QUERY_STATUS);if (schService == NULL){std::cout << "OpenService failed: " << GetLastError() << std::endl;CloseServiceHandle(schSCManager);return bSucc;}SERVICE_STATUS status;if (CheckSupportStop()) {std::cout << "Stop service via control\n";ControlService(schService, SERVICE_CONTROL_STOP, &status);}else {HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, g_wstrEvtName.c_str());if (NULL != hEvent) {std::cout << "Stop service via event\n";SetEvent(hEvent);CloseHandle(hEvent);}}int nWait = 0;while (nWait < 10){// query status needs SERVICE_QUERY_STATUSif (!QueryServiceStatus(schService, &status)) {std::cout << "Query status failed: " << GetLastError() << "\n";break;}if (status.dwCurrentState == SERVICE_STOPPED) {bSucc = true;break;}Sleep(1000);++nWait;}CloseServiceHandle(schService);CloseServiceHandle(schSCManager);std::cout << "Stop service return: " << bSucc << "\n";return bSucc;
}bool ServiceHandle::uninstall_service(const std::string& strServiceName)
{bool bSucc = false;SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (schSCManager == NULL){std::cout << "OpenSCManager failed: " << GetLastError() << std::endl;return bSucc;}SC_HANDLE schService = OpenServiceA(schSCManager, strServiceName.c_str(), SERVICE_STOP | DELETE | WRITE_DAC);if (schService == NULL){std::cout << "OpenService failed: " << GetLastError() << std::endl;CloseServiceHandle(schSCManager);return bSucc;}if (::DeleteService(schService)){std::cout << "Service uninstalled successfully." << std::endl;bSucc = true;}else{DWORD error = GetLastError();if (error == ERROR_SERVICE_MARKED_FOR_DELETE){std::cout << "Service is already marked for deletion." << std::endl;}else{std::cout << "DeleteService failed: " << error << std::endl;}}CloseServiceHandle(schService);CloseServiceHandle(schSCManager);std::cout << "Uninst service return: " << bSucc << "\n";return bSucc;
}

main.cpp

#include <iostream>
#include <map>
#include "ServiceHandle.h"enum ServiceCommand
{kServiceCommandUnknown = -1,kServiceCommandUsage,kServiceCommandInstall,kServiceCommandStart,kServiceCommandStop,kServiceCommandUninstall,kServiceCommandCommon
};
std::map<ServiceCommand, std::wstring> g_listCommand
{{ kServiceCommandUsage, L"usage" },{ kServiceCommandInstall, L"install" },{ kServiceCommandStart, L"start" },{ kServiceCommandStop, L"stop" },{ kServiceCommandUninstall, L"uninstall" },{ kServiceCommandCommon, L"common" },
};
ServiceCommand GetCommandType(const std::wstring& wstrInput)
{ServiceCommand nType = kServiceCommandUnknown;for (const auto& item : g_listCommand) {if (0 == _wcsicmp(wstrInput.c_str(), item.second.c_str())) {nType = item.first;break;}}return nType;
}
void Usage()
{std::cout << "Usage: TestWindownService [command]\n";std::cout << "command and options:\n";std::cout << "\tinstall:                    install service\n";std::cout << "\tstart:                      start service\n";std::cout << "\tstop:                       stop service\n";std::cout << "\tuninstall:                  uninstall service\n";std::cout << "\tcommon:                     start process in common mode\n";std::cout << "\thelp:                       show usage\n";
}
int wmain(int argc, wchar_t* argv[])
{
#ifdef _DEBUG// todo: common running, not server, just do business(debug mode)return 0;
#endif // _DEBUGif (1 == argc){if (!SERVICE_CTRL_INST.CheckSystemSession()) {std::cout << "Process only runs in service mode\n";return -1;}SERVICE_CTRL_INST.Run();return 0;}switch (GetCommandType(argv[1])) {case kServiceCommandInstall: {SERVICE_CTRL_INST.InstallService();break;}case kServiceCommandStart: {SERVICE_CTRL_INST.CusStartService();break;}case kServiceCommandStop: {SERVICE_CTRL_INST.CusStopService();break;}case kServiceCommandUninstall: {SERVICE_CTRL_INST.UninstallService();break;}case kServiceCommandCommon: {// todo: common running, not server, just do business(debug mode)break;}default:Usage();break;}return 0;
}
http://www.dtcms.com/a/343307.html

相关文章:

  • mac电脑使用(windows转Mac用户)
  • Java多线程编程——基础篇
  • STM32输入捕获相位差测量技术详解(基于TIM1复位模式)
  • Nacos 深度指南:从入门到高可用集群部署
  • ES6 面试题及详细答案 80题 (01-05)-- 基础语法与变量声明
  • C++宏的高级用法与元编程技巧
  • 数据结构青铜到王者第一话---数据结构基本常识(2)
  • 指数续创新高,期权的几种应对之策
  • 在线《相关性分析》
  • rs-fMRI_一篇文章中分析方法的梳理(翻译)
  • 职星学院企业培训系统:私有化部署赋能企业知识安全
  • 【鸿蒙开发】ArkTS 装饰器全解析:从 @Entry 到 @Observed 的全面指南
  • 资源对象深度解析:Pod生命周期与容器探针、Deployment滚动更新与回滚、StatefulSet有状态应用管理
  • 《MLB美职棒》美国国球是橄榄球还是棒球·棒球5号位
  • DAY44打卡
  • LCR 018. 验证回文串
  • VUE实现多个弹窗优先级变化实现思路
  • 技术框架搭建:支撑竞拍全流程
  • Spring Cloud系列—SkyWalking链路追踪
  • IPSec 安全基础
  • Matplotlib数据可视化实战:Matplotlib高级使用技巧与性能优化
  • GitHub Push 认证失败 fatal Authentication failed
  • 数据治理——解读56页 数据治理整体规划汇报【附全文阅读】
  • java-ArrayList的使用
  • 短波红外科研相机:开启科研新视野的利器​
  • LCR 019. 验证回文串 II
  • SpringCloudConfig配置文件本地化部署
  • 第5.1节:awk内置变量
  • MySQL诊断系列(5/6):表结构与元数据查询——快速掌握数据库“DNA”
  • 在pycharmIDE中如何快速掌握一个新模块的使用方法