从C ++发送命令到服务

时间:2009-10-20 07:07:10

标签: c++ windows-services servicecontroller

如何从C ++向Windows服务发送命令?等效的.NET代码是:

ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);

3 个答案:

答案 0 :(得分:3)

您使用ControlService,请参阅Service Control Requests

答案 1 :(得分:3)

从本机C ++开始,您需要:

  1. 打开服务控制管理器的句柄
  2. 使用服务控制管理器获取您要控制的服务的服务句柄
  3. 向服务发送控制代码或
  4. 关闭步骤1和2中打开的手柄。
  5. 例如,此代码重新启动时间同步服务。首先,我为服务句柄创建一个包装类,在离开块时自动关闭它们。

    class CSC_HANDLE
    {
    public:
     CSC_HANDLE(SC_HANDLE h) : m_h(h) { }
     ~CSC_HANDLE() { ::CloseServiceHandle(m_h); }
     operator SC_HANDLE () { return m_h; }
    private:
     SC_HANDLE m_h;
    };
    

    然后,我打开服务控制管理器(使用OpenSCManager())和我想要控制的服务。请注意,OpenService()的dwDesiredAccess参数必须包含我要发送的每个控件的权限,否则相关的控制功能将失败。

    BOOL RestartTimeService()
    {
        CSC_HANDLE hSCM(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ));
        if (NULL == hSCM) return FALSE;
    
        CSC_HANDLE hW32Time(::OpenService(hSCM, L"W32Time", SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS));
        if (NULL == hW32Time) return FALSE;
    

    要停止服务,我使用ControlService()发送SERVICE_CONTROL_STOP代码,然后检查返回值以确保命令成功。如果报告了ERROR_SERVICE_NOT_ACTIVE以外的任何错误,我认为启动服务不会成功。

        SERVICE_STATUS ss = { 0 };
        ::SetLastError(0);
        BOOL success = ::ControlService(hW32Time, SERVICE_CONTROL_STOP, &ss);
        if (!success)
        {
            DWORD le = ::GetLastError();
            switch (le)
            {
            case ERROR_ACCESS_DENIED:
            case ERROR_DEPENDENT_SERVICES_RUNNING:
            case ERROR_INVALID_HANDLE:
            case ERROR_INVALID_PARAMETER:
            case ERROR_INVALID_SERVICE_CONTROL:
            case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
            case ERROR_SERVICE_REQUEST_TIMEOUT:
            case ERROR_SHUTDOWN_IN_PROGRESS:
                return FALSE;
    
            case ERROR_SERVICE_NOT_ACTIVE:
            default:
                break;
            }
        }
    

    在指示服务停止后,我等待服务管理器报告该服务实际上已停止。此代码有两个潜在的错误,您可能希望更正生产代码:

    1. Sleep(1000)将暂停此线程上的消息循环,因此如果此函数将在UI线程上运行,则应使用另一种方法来延迟执行。您可以使用MsgWaitForMultipleObjectsEx()构建一个合适的sleep-with-message-loop。
    2. GetTickCount()返回的DWORD最终会回归到零;如果它在等待这个功能时包裹,等待可能会比我预期的更早放弃。

      DWORD waitstart(::GetTickCount());
      while (true)
      {
          ZeroMemory(&ss, sizeof(ss));
          ::QueryServiceStatus(hW32Time, &ss);
          if (SERVICE_STOPPED == ss.dwCurrentState) break;
          ::Sleep(1000);
          DWORD tick(::GetTickCount());
          if ((tick < waitstart) || (tick > (waitstart + 30000))) return FALSE;
      }
      
    3. 最后,知道服务处于停止状态,我打电话给StartService()再次运行它。

          success = ::StartService(hW32Time, 0, NULL);
          if (!success) return FALSE;
      
          return TRUE;
      }
      

答案 2 :(得分:0)

这是一个小程序,它将连接到名为“MYSERVICE”的服务,然后发送命令141(由服务定义)

x = tf.split( x, 10, axis = -1 )