diff --git a/win32/FireflyShell/FireflyShell.vcproj b/win32/FireflyShell/FireflyShell.vcproj index 78e35f89..cbb957ad 100644 --- a/win32/FireflyShell/FireflyShell.vcproj +++ b/win32/FireflyShell/FireflyShell.vcproj @@ -4,6 +4,7 @@ Version="8.00" Name="FireflyShell" ProjectGUID="{ED38F171-854B-4EA3-B3A0-7681648969FC}" + RootNamespace="FireflyShell" Keyword="Win32Proj" > diff --git a/win32/FireflyShell/ServiceControl.cpp b/win32/FireflyShell/ServiceControl.cpp index 3f8253d4..60960265 100644 --- a/win32/FireflyShell/ServiceControl.cpp +++ b/win32/FireflyShell/ServiceControl.cpp @@ -1,217 +1,253 @@ /* - *(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. - */ +*(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. +*/ #include "stdafx.h" #include "ServiceControl.h" +#include "DosPath.h" + +bool Service::ExecHelper(const TCHAR *szAction) { + PROCESS_INFORMATION pi; + STARTUPINFO si; + CString commandline; + CDosPath path = CDosPath::AppPath(); + CDosPath filename(_T("svcctrl.exe")); + DWORD dwResult; + LPTSTR cmd; + + filename |= path; + commandline.Format(_T("%s %s \"%s\""),filename.GetPath(),szAction,m_name); + cmd = commandline.GetBuffer(commandline.GetLength() + 1); + ZeroMemory(&si,sizeof(si)); + si.cb = sizeof(si); + + ZeroMemory(&pi,sizeof(pi)); + + + BOOL bStarted = CreateProcess(NULL,cmd,NULL,NULL, + FALSE,0,NULL,NULL,&si,&pi); + + commandline.ReleaseBuffer(); + + if(!bStarted) + return false; + + WaitForSingleObject(pi.hProcess, INFINITE); + + GetExitCodeProcess(pi.hProcess,&dwResult); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + if(dwResult) + return false; + + return true; +} bool Service::Open(const TCHAR *name) { - Close(); + Close(); - const DWORD ADMIN_ACCESS = SC_MANAGER_ALL_ACCESS; - const DWORD USER_ACCESS = SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | STANDARD_RIGHTS_READ; + const DWORD USER_ACCESS = SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | STANDARD_RIGHTS_READ; - DWORD dwDesiredAccess = ADMIN_ACCESS; + DWORD dwDesiredAccess = USER_ACCESS; - m_sc_manager = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, dwDesiredAccess); - if (!m_sc_manager) - { - dwDesiredAccess = USER_ACCESS; - m_sc_manager = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, dwDesiredAccess); - m_can_control = false; - } - else - { - m_can_control = true; - } + m_sc_manager = ::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, dwDesiredAccess); + if (!m_sc_manager) + { + m_can_control = false; + } + else + { + m_can_control = true; + } - if (m_sc_manager) - { - m_sc_service = ::OpenService(m_sc_manager, name, dwDesiredAccess); - if (m_sc_service) - return true; - } + if (m_sc_manager) + { + m_sc_service = ::OpenService(m_sc_manager, name, dwDesiredAccess); + if (m_sc_service) { + m_name = name; + return true; + } + } - Close(); - return false; + Close(); + return false; } void Service::Close() { - if (m_sc_service) - { - ::CloseServiceHandle(m_sc_service); - m_sc_service = NULL; - } - if (m_sc_manager) - { - ::CloseServiceHandle(m_sc_manager); - m_sc_manager = NULL; - } + if (m_sc_service) + { + ::CloseServiceHandle(m_sc_service); + m_sc_service = NULL; + } + if (m_sc_manager) + { + ::CloseServiceHandle(m_sc_manager); + m_sc_manager = NULL; + } } bool Service::GetStatus(Status *status) const { - if (::QueryServiceStatus(m_sc_service, status)) - return true; - else - return false; + if (::QueryServiceStatus(m_sc_service, status)) + return true; + else + return false; } bool Service::Start() { - if (::StartService(m_sc_service, 0, NULL)) - return true; - else - return false; + if (ExecHelper(_T("start"))) + return true; + else + return false; } bool Service::StartAndWait() { - if (Start()) - { - Status status; - return WaitPending(&status, SERVICE_START_PENDING); - } - else - return false; + if (Start()) + { + Status status; + return WaitPending(&status, SERVICE_START_PENDING); + } + else + return false; } bool Service::Stop() { - Status status; - if (::ControlService(m_sc_service, SERVICE_CONTROL_STOP, &status)) - return true; - else - return false; + Status status; + if (ExecHelper(_T("stop"))) + return true; + else + return false; } bool Service::StopAndWait() { - Status status; - if (::ControlService(m_sc_service, SERVICE_CONTROL_STOP, &status)) - { - return WaitPending(&status, SERVICE_STOP_PENDING); - } - else - return false; + Status status; + if (Stop()) + return WaitPending(&status, SERVICE_STOP_PENDING); + else + return false; } bool Service::WaitPending(Status *status, DWORD existing_state) { - ATLTRACE(_T("Enter Service::WaitPending\n")); - if (GetStatus(status)) - { - DWORD dwStartTickCount = GetTickCount(); - DWORD dwOldCheckPoint = status->dwCheckPoint; + ATLTRACE(_T("Enter Service::WaitPending\n")); + if (GetStatus(status)) + { + DWORD dwStartTickCount = GetTickCount(); + DWORD dwOldCheckPoint = status->dwCheckPoint; - while (status->dwCurrentState == existing_state) - { - ATLTRACE(_T("Service::WaitPending in loop\n")); - DWORD dwWaitTime = status->dwWaitHint / 10; - if (dwWaitTime < 1000) - dwWaitTime = 1000; - else if (dwWaitTime > 10000) - dwWaitTime = 10000; + while (status->dwCurrentState == existing_state) + { + ATLTRACE(_T("Service::WaitPending in loop\n")); + DWORD dwWaitTime = status->dwWaitHint / 10; + if (dwWaitTime < 1000) + dwWaitTime = 1000; + else if (dwWaitTime > 10000) + dwWaitTime = 10000; - ATLTRACE(_T("Sleeping\n")); - ::Sleep(dwWaitTime); + ATLTRACE(_T("Sleeping\n")); + ::Sleep(dwWaitTime); - if (!GetStatus(status)) - { - ATLTRACE(_T("Service::WaitPending - Failed to get status\n")); - return false; - } + if (!GetStatus(status)) + { + ATLTRACE(_T("Service::WaitPending - Failed to get status\n")); + return false; + } - // If we haven't changed state yet then check to see that the - // service is actually making progress. - if (status->dwCurrentState == existing_state) - { - if (status->dwCheckPoint != dwOldCheckPoint) - { - // The service is making progress - dwStartTickCount = GetTickCount(); - dwOldCheckPoint = status->dwCheckPoint; - } - else if (GetTickCount() - dwStartTickCount > status->dwWaitHint) - { - ATLTRACE(_T("Service::WaitPending - No progress\n")); - /// Hmm. No progress - return false; - } - } - } - } - ATLTRACE(_T("Service::WaitPending success\n")); - return true; + // If we haven't changed state yet then check to see that the + // service is actually making progress. + if (status->dwCurrentState == existing_state) + { + if (status->dwCheckPoint != dwOldCheckPoint) + { + // The service is making progress + dwStartTickCount = GetTickCount(); + dwOldCheckPoint = status->dwCheckPoint; + } + else if (GetTickCount() - dwStartTickCount > status->dwWaitHint) + { + ATLTRACE(_T("Service::WaitPending - No progress\n")); + /// Hmm. No progress + return false; + } + } + } + } + ATLTRACE(_T("Service::WaitPending success\n")); + return true; } CString Service::GetBinaryPath() const { - CString path; + CString path; - DWORD bytes_required; - ::QueryServiceConfig(m_sc_service, NULL, 0, &bytes_required); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - void *buffer = operator new(bytes_required); - LPQUERY_SERVICE_CONFIG config = reinterpret_cast(buffer); + DWORD bytes_required; + ::QueryServiceConfig(m_sc_service, NULL, 0, &bytes_required); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *buffer = operator new(bytes_required); + LPQUERY_SERVICE_CONFIG config = reinterpret_cast(buffer); - if (::QueryServiceConfig(m_sc_service, config, bytes_required, &bytes_required)) - { - path = config->lpBinaryPathName; - } + if (::QueryServiceConfig(m_sc_service, config, bytes_required, &bytes_required)) + { + path = config->lpBinaryPathName; + } - delete buffer; - } - return path; + delete buffer; + } + return path; } DWORD Service::GetStartup() const { - DWORD result = 0xffffffff; - const size_t BUFFER_SIZE = 8192; - void *buffer = operator new(BUFFER_SIZE); - LPQUERY_SERVICE_CONFIG config = reinterpret_cast(buffer); - - DWORD bytes_required; - if (::QueryServiceConfig(m_sc_service, config, BUFFER_SIZE, &bytes_required)) - result = config->dwStartType; + DWORD result = 0xffffffff; + const size_t BUFFER_SIZE = 8192; + void *buffer = operator new(BUFFER_SIZE); + LPQUERY_SERVICE_CONFIG config = reinterpret_cast(buffer); - delete buffer; - return result; + DWORD bytes_required; + if (::QueryServiceConfig(m_sc_service, config, BUFFER_SIZE, &bytes_required)) + result = config->dwStartType; + + delete buffer; + return result; } bool Service::ConfigureStartup(DWORD startup) { - if (::ChangeServiceConfig(m_sc_service, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) - return true; - else - return false; + if (::ChangeServiceConfig(m_sc_service, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) + return true; + else + return false; } void ServiceStatusMonitor::Poll(Service *service) { - Service::Status new_status; - if (service->GetStatus(&new_status)) - { - if (!m_service_status.IsValid() || (m_service_status != new_status)) - { - FireServiceStatus(m_service_status, new_status); - m_service_status = new_status; - } - } + Service::Status new_status; + if (service->GetStatus(&new_status)) + { + if (!m_service_status.IsValid() || (m_service_status != new_status)) + { + FireServiceStatus(m_service_status, new_status); + m_service_status = new_status; + } + } } diff --git a/win32/FireflyShell/ServiceControl.h b/win32/FireflyShell/ServiceControl.h index 03ef0476..82798591 100644 --- a/win32/FireflyShell/ServiceControl.h +++ b/win32/FireflyShell/ServiceControl.h @@ -1,171 +1,174 @@ /* - *(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. - */ +*(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; + SC_HANDLE m_sc_manager; + SC_HANDLE m_sc_service; + bool m_can_control; + CString m_name; public: - - class Status : public SERVICE_STATUS - { - bool WaitPending(); - public: - Status() - { - SERVICE_STATUS *clearable_this = this; - ZeroMemory(clearable_this, sizeof(SERVICE_STATUS)); - } + class Status : public SERVICE_STATUS + { + bool WaitPending(); - bool operator==(const Status &r) const - { - const SERVICE_STATUS *lhs = this; - const SERVICE_STATUS *rhs = &r; - return memcmp(lhs, rhs, sizeof(SERVICE_STATUS)) == 0; - } + 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 operator!=(const Status &r) const + { + const SERVICE_STATUS *lhs = this; + const SERVICE_STATUS *rhs = &r; + return memcmp(lhs, rhs, sizeof(SERVICE_STATUS)) != 0; + } - bool IsValid() const - { - return dwCurrentState != 0; - } + void AssertValid() const + { + // If we've been written then this shouldn't be zero. + ATLASSERT(dwCurrentState != 0); + } - bool IsRunning() const - { - AssertValid(); - return dwCurrentState == SERVICE_RUNNING; - } + bool IsValid() const + { + return dwCurrentState != 0; + } - bool IsStopped() const - { - AssertValid(); - return dwCurrentState == SERVICE_STOPPED; - } + bool IsRunning() const + { + AssertValid(); + return dwCurrentState == SERVICE_RUNNING; + } - bool IsPaused() const - { - AssertValid(); - return dwCurrentState == SERVICE_PAUSED; - } + bool IsStopped() const + { + AssertValid(); + return dwCurrentState == SERVICE_STOPPED; + } - 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; - } - } - }; + bool IsPaused() const + { + AssertValid(); + return dwCurrentState == SERVICE_PAUSED; + } - Service() : m_sc_manager(NULL), m_sc_service(NULL), m_can_control(false) {} - ~Service() { Close(); } + 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; + } + } + }; - bool IsOpen() const - { - return m_sc_service != NULL; - } - bool Open(const TCHAR *name); - void Close(); + Service() : m_sc_manager(NULL), m_sc_service(NULL), m_can_control(false) {} + ~Service() { Close(); } - bool GetStatus(Status *status) const; + bool IsOpen() const + { + return m_sc_service != NULL; + } + bool Open(const TCHAR *name); + void Close(); - bool Start(); - bool StartAndWait(); - bool Stop(); - bool StopAndWait(); - bool WaitPending(Status *status, DWORD existing_state); - bool PollPending(Status *status, DWORD existing_state); + 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; - } + 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; + CString GetBinaryPath() const; - /// Pass SERVICE_AUTO_START, SERVICE_BOOT_START, SERVICE_DEMAND_START, - /// SERVICE_DISABLED or SERVICE_SYSTEM_START. - bool ConfigureStartup(DWORD dwStartup); + /// Pass SERVICE_AUTO_START, SERVICE_BOOT_START, SERVICE_DEMAND_START, + /// SERVICE_DISABLED or SERVICE_SYSTEM_START. + bool ConfigureStartup(DWORD dwStartup); + DWORD GetStartup() const; - DWORD GetStartup() const; +private: + bool ExecHelper(const TCHAR *szAction); }; class ServiceStatusObserver { public: - virtual void OnServiceStatus(Service::Status old_status, Service::Status new_status) = 0; + virtual void OnServiceStatus(Service::Status old_status, Service::Status new_status) = 0; }; class ServiceStatusMonitor { - Service::Status m_service_status; - std::vector m_service_observers; + 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; - } - } + 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 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); - } - } + 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 diff --git a/win32/nsi/mt-daapd.nsi.templ b/win32/nsi/mt-daapd.nsi.templ index 5a76252a..a705f773 100644 --- a/win32/nsi/mt-daapd.nsi.templ +++ b/win32/nsi/mt-daapd.nsi.templ @@ -16,8 +16,8 @@ !define MTDROOT "..\.." !define MTD_SOURCE "${MTDROOT}\win32\Release" -!define DLL_SOURCE "${PROJROOT}\win32\dll" !define CONFIG_SOURCE "${MTDROOT}\win32\FireflyShell\Release" +!define DLL_SOURCE "${PROJROOT}\win32\dll" !define ADMIN_ROOT "${MTDROOT}\admin-root" !define REDIST_SOURCE "${PROJROOT}\win32\redist" @@ -171,6 +171,7 @@ NoProgramItems: File "${CONFIG_SOURCE}\FireflyShell-11.dll" File "${CONFIG_SOURCE}\FireflyShell-10.dll" File "${CONFIG_SOURCE}\..\FireflyShell.exe.manifest" + File "${CONFIG_SOURCE}\svcctrl.exe" File "${DLL_SOURCE}\gnu_regex.dll" File "${DLL_SOURCE}\pthreadVC2.dll" File "${DLL_SOURCE}\sqlite.dll" diff --git a/win32/svcctrl/svcctrl.vcproj b/win32/svcctrl/svcctrl.vcproj index df040eff..ec75a772 100644 --- a/win32/svcctrl/svcctrl.vcproj +++ b/win32/svcctrl/svcctrl.vcproj @@ -17,7 +17,7 @@