zoukankan      html  css  js  c++  java
  • 创建Windows服务(C++)

    这次我们来创建一个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__ << "
      "; 		                
              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__ << "
      ";
              exit(-1);
          }
      
          setServiceStatus(SERVICE_START_PENDING);
          setServiceStatus(SERVICE_RUNNING);
      }
      

    完整代码

    生成的exe需要以管理员权限启动,完整代码见此处

  • 相关阅读:
    【bzoj2079】[Poi2010]Guilds 构造结论题
    【bzoj1899】[Zjoi2004]Lunch 午餐 dp
    【bzoj1345】[Baltic2007]序列问题Sequence 单调栈
    【bzoj1047】[HAOI2007]理想的正方形 二维RMQ
    【bzoj1044】[HAOI2008]木棍分割 二分+dp
    【bzoj5037】[Jsoi2014]电信网络 最大权闭合图
    【bzoj5018】[Snoi2017]英雄联盟 背包dp
    【bzoj5020】[THUWC 2017]在美妙的数学王国中畅游 泰勒展开+LCT
    【bzoj2213】[Poi2011]Difference dp
    【bzoj2161】布娃娃 权值线段树
  • 原文地址:https://www.cnblogs.com/lgxZJ/p/7440116.html
Copyright © 2011-2022 走看看