/* *(C) 2006 Roku LLC * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License Version 2 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * without any warranty; without even the implied warranty of * merchantability or fitness for a particular purpose. See the GNU General * Public License for more details. * * Please read README.txt in the same directory as this source file for * further license information. */ #ifndef SERVICECONTROL_H #define SERVICECONTROL_H class Service { SC_HANDLE m_sc_manager; SC_HANDLE m_sc_service; bool m_can_control; public: class Status : public SERVICE_STATUS { bool WaitPending(); public: Status() { SERVICE_STATUS *clearable_this = this; ZeroMemory(clearable_this, sizeof(SERVICE_STATUS)); } bool operator==(const Status &r) const { const SERVICE_STATUS *lhs = this; const SERVICE_STATUS *rhs = &r; return memcmp(lhs, rhs, sizeof(SERVICE_STATUS)) == 0; } bool operator!=(const Status &r) const { const SERVICE_STATUS *lhs = this; const SERVICE_STATUS *rhs = &r; return memcmp(lhs, rhs, sizeof(SERVICE_STATUS)) != 0; } void AssertValid() const { // If we've been written then this shouldn't be zero. ATLASSERT(dwCurrentState != 0); } bool IsValid() const { return dwCurrentState != 0; } bool IsRunning() const { AssertValid(); return dwCurrentState == SERVICE_RUNNING; } bool IsStopped() const { AssertValid(); return dwCurrentState == SERVICE_STOPPED; } bool IsPaused() const { AssertValid(); return dwCurrentState == SERVICE_PAUSED; } bool IsPending() const { AssertValid(); switch (dwCurrentState) { case SERVICE_CONTINUE_PENDING: case SERVICE_PAUSE_PENDING: case SERVICE_START_PENDING: case SERVICE_STOP_PENDING: return true; default: return false; } } }; Service() : m_sc_manager(NULL), m_sc_service(NULL), m_can_control(false) {} ~Service() { Close(); } bool IsOpen() const { return m_sc_service != NULL; } bool Open(const TCHAR *name); void Close(); bool GetStatus(Status *status) const; bool Start(); bool StartAndWait(); bool Stop(); bool StopAndWait(); bool WaitPending(Status *status, DWORD existing_state); bool PollPending(Status *status, DWORD existing_state); bool CanControl() const { // For the time being - need to deal with running as a user that can't control. return IsOpen() && m_can_control; } CString GetBinaryPath() const; /// Pass SERVICE_AUTO_START, SERVICE_BOOT_START, SERVICE_DEMAND_START, /// SERVICE_DISABLED or SERVICE_SYSTEM_START. bool ConfigureStartup(DWORD dwStartup); DWORD GetStartup() const; }; class ServiceStatusObserver { public: virtual void OnServiceStatus(Service::Status old_status, Service::Status new_status) = 0; }; class ServiceStatusMonitor { Service::Status m_service_status; std::vector m_service_observers; void FireServiceStatus(Service::Status old_status, Service::Status new_status) { std::vector::iterator i = m_service_observers.begin(); while (i != m_service_observers.end()) { (*i)->OnServiceStatus(old_status, new_status); ++i; } } public: void Poll(Service *service); void Subscribe(ServiceStatusObserver *obs) { m_service_observers.push_back(obs); } void Unsubscribe(ServiceStatusObserver *obs) { std::vector::iterator i = std::find(m_service_observers.begin(), m_service_observers.end(), obs); ATLASSERT(i != m_service_observers.end()); if (i != m_service_observers.end()) { m_service_observers.erase(i); } } }; #endif // SERVICECONTROL_H