创建Windows服务(C++)

来源:互联网 发布:数据库监控自动化方案 编辑:程序博客网 时间:2024/06/07 15:33

这次我们来创建一个windows本地服务,需要有以下功能:

  • 安装服务。
  • 卸载服务。
  • 手动启动服务。
  • 开机自动启动服务。
  • 控制服务(停止、暂停、恢复、启动)。

服务概念及介绍

看下图,一切尽在不言中了(-_-):
pic

安装服务并开机启动

  • 代码逻辑: 打开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需要以管理员权限启动,完整代码见此处。

原创粉丝点击