创建Windows服务(C++)
这次我们来创建一个windows本地服务,需要有以下功能:
- 安装服务。
- 卸载服务。
- 手动启动服务。
- 开机自动启动服务。
- 控制服务(停止、暂停、恢复、启动)。
服务概念及介绍
看下图,一切尽在不言中了(-_-):
安装服务并开机启动
-
代码逻辑: 打开SCM(Service Control Manager)-> 创建服务。
-
在CreateService调用中,我们传入
SERVICE_AUTO_START
里表明这个服务是开启自启动的,SCM会在开机时调用StartService来启动我们的服务;同时我们传入NULL
作为服务开始名称,这样该服务就可以开机启动为系统服务。在调用installService后,我们会调用startService来手动启动服务。 -
这里我用
SAFE_CALL
简化了错误处理逻辑。wstring getExeFullFilename() { static wchar_t buffer[1024]; SAFE_CALL(GetModuleFileNameW(NULL, buffer, 1024), 0); return wstring(buffer); } void installService() { auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE); SAFE_CALL(scmHandle, NULL); auto serviceHandle = CreateServiceW(scmHandle, L"lgxZJ::Service", L"lgxZJ::Service", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, getExeFullFilename().c_str(), NULL, NULL, L"", NULL, L""); SAFE_CALL(serviceHandle, NULL); CloseServiceHandle(scmHandle); CloseServiceHandle(serviceHandle); } void startService() { auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); SAFE_CALL(scmHandle, NULL); auto serviceHandle = OpenServiceW( scmHandle, L"lgxZJ::Service", SERVICE_ALL_ACCESS); SAFE_CALL(serviceHandle, NULL); SERVICE_STATUS serviceStatus; SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0); if (serviceStatus.dwCurrentState == SERVICE_START && serviceStatus.dwCurrentState != SERVICE_START_PENDING) return; SAFE_CALL(StartServiceW(serviceHandle, 0, NULL), FALSE); CloseServiceHandle(scmHandle); CloseServiceHandle(serviceHandle); } #define SAFE_CALL(FuncCall, ErrorCode) \ if (FuncCall == ErrorCode) { \ cout << #FuncCall " error, code:" << GetLastError() \ << " ,line:" << \__LINE__ << "\n"; \ exit(-1); \ }
卸载服务
-
代码逻辑: 打开SCM(Service Control Manager)-> 打开服务 -> 停止服务(如果正在运行) -> 删除服务。
void uninstallService() { auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); SAFE_CALL(scmHandle, NULL); auto serviceHandle = OpenServiceW( scmHandle, L"lgxZJ::Service", SERVICE_ALL_ACCESS); SAFE_CALL(serviceHandle, NULL); SERVICE_STATUS serviceStatus; SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0); if (serviceStatus.dwCurrentState == SERVICE_RUNNING) { SAFE_CALL(ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus), 0); SAFE_CALL(serviceStatus.dwCurrentState, NO_ERROR); do { SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0); Sleep(1000); } while (serviceStatus.dwCurrentState != SERVICE_STOPPED); } SAFE_CALL(DeleteService(serviceHandle), FALSE); CloseServiceHandle(scmHandle); CloseServiceHandle(serviceHandle); }
手动启动服务
-
代码逻辑: 打开SCM -> 打开服务 -> 启动服务。
void startService() { auto scmHandle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); SAFE_CALL(scmHandle, NULL); auto serviceHandle = OpenServiceW( scmHandle, L"lgxZJ::Service", SERVICE_ALL_ACCESS); SAFE_CALL(serviceHandle, NULL); SERVICE_STATUS serviceStatus; SAFE_CALL(QueryServiceStatus(serviceHandle, &serviceStatus), 0); if (serviceStatus.dwCurrentState == SERVICE_START && serviceStatus.dwCurrentState != SERVICE_START_PENDING) return; SAFE_CALL(StartServiceW(serviceHandle, 0, NULL), FALSE); CloseServiceHandle(scmHandle); CloseServiceHandle(serviceHandle); }
运行服务(服务启动时会运行服务)、服务控制处理
-
代码逻辑: 启动分发器(连接到SCM) -> 注册服务控制处理器 -> 在控制处理器中对服务控制进行处理(通过SetServiceStatus反馈服务状态和设置接受的控制)。
void runService() { const SERVICE_TABLE_ENTRYW serviceTable[] = { { L"", ServiceMain }, { NULL, NULL } }; SAFE_CALL(StartServiceCtrlDispatcherW(&serviceTable[0]), 0); } SERVICE_STATUS_HANDLE g_serviceStatusHandle = NULL; void setServiceStatus(DWORD status) { SERVICE_STATUS serviceStatus; serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwWin32ExitCode = NO_ERROR; serviceStatus.dwServiceSpecificExitCode = 0; serviceStatus.dwWaitHint = 2000; serviceStatus.dwCheckPoint = 0; serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; serviceStatus.dwCurrentState = status; SAFE_CALL(SetServiceStatus(g_serviceStatusHandle, &serviceStatus), 0); } VOID WINAPI ServiceHandler(DWORD controlCode) { switch (controlCode) { case SERVICE_CONTROL_CONTINUE: setServiceStatus(SERVICE_START_PENDING); break; case SERVICE_CONTROL_INTERROGATE: break; case SERVICE_CONTROL_PAUSE: setServiceStatus(SERVICE_PAUSED); break; case SERVICE_CONTROL_SHUTDOWN: setServiceStatus(SERVICE_STOPPED); break; case SERVICE_CONTROL_STOP: setServiceStatus(SERVICE_STOPPED); break; default: break; } } VOID WINAPI ServiceMain(DWORD argc, LPWSTR *argv) { g_serviceStatusHandle = RegisterServiceCtrlHandlerW(L"lgxZJ::Service", &ServiceHandler); if (g_serviceStatusHandle == 0) { cout << "RegisterServiceCtrlHandlerW error, code:" << GetLastError() << " ,line:" << __LINE__ << "\n"; exit(-1); } setServiceStatus(SERVICE_START_PENDING); setServiceStatus(SERVICE_RUNNING); }
完整代码
生成的exe需要以管理员权限启动,完整代码见此处。