diff options
Diffstat (limited to 'server-tools/instance-manager/WindowsService.cpp')
-rw-r--r-- | server-tools/instance-manager/WindowsService.cpp | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp new file mode 100644 index 00000000000..192045b7a4c --- /dev/null +++ b/server-tools/instance-manager/WindowsService.cpp @@ -0,0 +1,203 @@ +#include <windows.h> +#include <assert.h> +#include ".\windowsservice.h" + +static WindowsService *gService; + +WindowsService::WindowsService(void) : + statusCheckpoint(0), + serviceName(NULL), + inited(false), + dwAcceptedControls(SERVICE_ACCEPT_STOP), + debugging(false) +{ + gService= this; + status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; + status.dwServiceSpecificExitCode= 0; +} + +WindowsService::~WindowsService(void) +{ +} + +BOOL WindowsService::Install() +{ + bool ret_val= false; + SC_HANDLE newService; + SC_HANDLE scm; + + if (IsInstalled()) return true; + + // determine the name of the currently executing file + char szFilePath[_MAX_PATH]; + GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); + + // open a connection to the SCM + if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE))) + return false; + + newService= CreateService(scm, serviceName, displayName, + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, + szFilePath, NULL, NULL, NULL, username, + password); + + if (newService) + { + CloseServiceHandle(newService); + ret_val= true; + } + + CloseServiceHandle(scm); + return ret_val; +} + +BOOL WindowsService::Init() +{ + assert(serviceName != NULL); + + if (inited) return true; + + SERVICE_TABLE_ENTRY stb[] = + { + { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, + { NULL, NULL } + }; + inited= true; + return StartServiceCtrlDispatcher(stb); //register with the Service Manager +} + +BOOL WindowsService::Remove() +{ + bool ret_val= false; + + if (! IsInstalled()) + return true; + + // open a connection to the SCM + SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE); + if (! scm) + return false; + + SC_HANDLE service= OpenService(scm, serviceName, DELETE); + if (service) + { + if (DeleteService(service)) + ret_val= true; + DWORD dw= ::GetLastError(); + CloseServiceHandle(service); + } + + CloseServiceHandle(scm); + return ret_val; +} + +BOOL WindowsService::IsInstalled() +{ + BOOL ret_val= FALSE; + + SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS); + + ret_val= serv_handle != NULL; + + ::CloseServiceHandle(serv_handle); + ::CloseServiceHandle(scm); + + return ret_val; +} + +void WindowsService::SetAcceptedControls(DWORD acceptedControls) +{ + dwAcceptedControls= acceptedControls; +} + + +BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint, + DWORD dwError) +{ + if(debugging) return TRUE; + + if(currentState == SERVICE_START_PENDING) + status.dwControlsAccepted= 0; + else + status.dwControlsAccepted= dwAcceptedControls; + + status.dwCurrentState= currentState; + status.dwWin32ExitCode= dwError != 0 ? + ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR; + status.dwWaitHint= waitHint; + status.dwServiceSpecificExitCode= dwError; + + if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) + { + status.dwCheckPoint= 0; + statusCheckpoint= 0; + } + else + status.dwCheckPoint= ++statusCheckpoint; + + // Report the status of the service to the service control manager. + BOOL result= SetServiceStatus(statusHandle, &status); + if (!result) + Log("ReportStatus failed"); + + return result; +} + +void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) +{ + statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); + if (statusHandle && ReportStatus(SERVICE_START_PENDING)) + Run(argc, argv); + ReportStatus(SERVICE_STOPPED); +} + +void WindowsService::HandleControlCode(DWORD opcode) +{ + // Handle the requested control code. + switch(opcode) { + case SERVICE_CONTROL_STOP: + // Stop the service. + status.dwCurrentState= SERVICE_STOP_PENDING; + Stop(); + break; + + case SERVICE_CONTROL_PAUSE: + status.dwCurrentState= SERVICE_PAUSE_PENDING; + Pause(); + break; + + case SERVICE_CONTROL_CONTINUE: + status.dwCurrentState= SERVICE_CONTINUE_PENDING; + Continue(); + break; + + case SERVICE_CONTROL_SHUTDOWN: + Shutdown(); + break; + + case SERVICE_CONTROL_INTERROGATE: + ReportStatus(status.dwCurrentState); + break; + + default: + // invalid control code + break; + } +} + +void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv) +{ + assert(gService != NULL); + + // register our service control handler: + gService->RegisterAndRun(argc, argv); +} + +void WINAPI WindowsService::ControlHandler(DWORD opcode) +{ + assert(gService != NULL); + + return gService->HandleControlCode(opcode); +} |