这次我们来创建一个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需要以管理员权限启动,完整代码见此处。