3
/* Copyright 2009 10gen Inc.
5
* Licensed under the Apache License, Version 2.0 (the "License");
6
* you may not use this file except in compliance with the License.
7
* You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
19
#include "ntservice.h"
27
SERVICE_STATUS_HANDLE ServiceController::_statusHandle = null;
28
std::wstring ServiceController::_serviceName;
29
ServiceCallback ServiceController::_serviceCallback = null;
31
ServiceController::ServiceController() {
34
bool ServiceController::installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, int argc, char* argv[] ) {
36
std::string commandLine;
38
for ( int i = 0; i < argc; i++ ) {
39
std::string arg( argv[ i ] );
41
// replace install command to indicate process is being started as a service
42
if ( arg == "--install" )
45
commandLine += arg + " ";
48
SC_HANDLE schSCManager = ::OpenSCManager( null, null, SC_MANAGER_ALL_ACCESS );
49
if ( schSCManager == null )
52
std::basic_ostringstream< TCHAR > commandLineWide;
53
commandLineWide << commandLine.c_str();
56
SC_HANDLE schService = ::CreateService( schSCManager, serviceName.c_str(), displayName.c_str(),
57
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
58
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
59
commandLineWide.str().c_str(), null, null, L"\0\0", null, null );
61
if ( schService == null ) {
62
::CloseServiceHandle( schSCManager );
66
SERVICE_DESCRIPTION serviceDescription;
67
serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str();
69
// set new service description
70
bool serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription );
72
if ( serviceInstalled ) {
73
SC_ACTION aActions[ 3 ] = { { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 } };
75
SERVICE_FAILURE_ACTIONS serviceFailure;
76
ZeroMemory( &serviceFailure, sizeof( SERVICE_FAILURE_ACTIONS ) );
77
serviceFailure.cActions = 3;
78
serviceFailure.lpsaActions = aActions;
80
// set service recovery options
81
serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailure );
84
::CloseServiceHandle( schService );
85
::CloseServiceHandle( schSCManager );
87
return serviceInstalled;
90
bool ServiceController::removeService( const std::wstring& serviceName ) {
91
SC_HANDLE schSCManager = ::OpenSCManager( null, null, SC_MANAGER_ALL_ACCESS );
92
if ( schSCManager == null )
95
SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS );
97
if ( schService == null ) {
98
::CloseServiceHandle( schSCManager );
102
SERVICE_STATUS serviceStatus;
104
// stop service if running
105
if ( ::ControlService( schService, SERVICE_CONTROL_STOP, &serviceStatus ) ) {
106
while ( ::QueryServiceStatus( schService, &serviceStatus ) ) {
107
if ( serviceStatus.dwCurrentState == SERVICE_STOP_PENDING )
112
bool serviceRemoved = ::DeleteService( schService );
114
::CloseServiceHandle( schService );
115
::CloseServiceHandle( schSCManager );
117
return serviceRemoved;
120
bool ServiceController::startService( const std::wstring& serviceName, ServiceCallback startService ) {
121
_serviceName = serviceName;
122
_serviceCallback = startService;
124
SERVICE_TABLE_ENTRY dispTable[] = {
125
{ (LPTSTR)serviceName.c_str(), (LPSERVICE_MAIN_FUNCTION)ServiceController::initService },
129
return StartServiceCtrlDispatcher( dispTable );
132
bool ServiceController::reportStatus( DWORD reportState, DWORD waitHint ) {
133
if ( _statusHandle == null )
136
static DWORD checkPoint = 1;
138
SERVICE_STATUS ssStatus;
140
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
141
ssStatus.dwServiceSpecificExitCode = 0;
142
ssStatus.dwControlsAccepted = reportState == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP;
143
ssStatus.dwCurrentState = reportState;
144
ssStatus.dwWin32ExitCode = NO_ERROR;
145
ssStatus.dwWaitHint = waitHint;
146
ssStatus.dwCheckPoint = ( reportState == SERVICE_RUNNING || reportState == SERVICE_STOPPED ) ? 0 : checkPoint++;
148
return SetServiceStatus( _statusHandle, &ssStatus );
151
void WINAPI ServiceController::initService( DWORD argc, LPTSTR *argv ) {
152
_statusHandle = RegisterServiceCtrlHandler( _serviceName.c_str(), serviceCtrl );
153
if ( !_statusHandle )
156
reportStatus( SERVICE_START_PENDING, 1000 );
160
reportStatus( SERVICE_STOPPED );
163
void WINAPI ServiceController::serviceCtrl( DWORD ctrlCode ) {
164
switch ( ctrlCode ) {
165
case SERVICE_CONTROL_STOP:
166
case SERVICE_CONTROL_SHUTDOWN:
168
reportStatus( SERVICE_STOPPED );