首页 技术 正文
技术 2022年11月19日
0 收藏 643 点赞 4,337 浏览 4445 个字

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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,104
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,580
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,428
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,835
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,918