Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "service.h"
Toshihiro Shimizu 890ddd
#include "tlog.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tfilepath.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
#pragma warning(disable : 4996)
Toshihiro Shimizu 890ddd
#include <windows.h></windows.h>
Toshihiro Shimizu 890ddd
#include <stdio.h></stdio.h>
Toshihiro Shimizu 890ddd
#include <stdlib.h></stdlib.h>
Toshihiro Shimizu 890ddd
#include <process.h></process.h>
Toshihiro Shimizu 890ddd
#include <tchar.h></tchar.h>
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#include <string.h></string.h>
Toshihiro Shimizu 890ddd
#include <errno.h></errno.h>
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define SZDEPENDENCIES ""
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	DWORD dwRet;
Toshihiro Shimizu 890ddd
	LPTSTR lpszTemp = NULL;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	dwRet = FormatMessage(
Toshihiro Shimizu 890ddd
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
Toshihiro Shimizu 890ddd
		NULL,
Toshihiro Shimizu 890ddd
		GetLastError(),
Toshihiro Shimizu 890ddd
		LANG_NEUTRAL,
Toshihiro Shimizu 890ddd
		(LPTSTR)&lpszTemp,
Toshihiro Shimizu 890ddd
		0,
Toshihiro Shimizu 890ddd
		NULL);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// supplied buffer is not long enough
Toshihiro Shimizu 890ddd
	if (!dwRet || ((long)dwSize < (long)dwRet + 14))
Toshihiro Shimizu 890ddd
		lpszBuf[0] = TEXT('\0');
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		lpszTemp[lstrlen(lpszTemp) - 2] = TEXT('\0'); //remove cr and newline character
Toshihiro Shimizu 890ddd
		_stprintf(lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (lpszTemp)
Toshihiro Shimizu 890ddd
		LocalFree((HLOCAL)lpszTemp);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return lpszBuf;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#endif // _WIN32
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
std::string getLastErrorText()
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 2148c8
	std::string errText;
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	char errBuff[256];
Toshihiro Shimizu 890ddd
	errText = GetLastErrorText(errBuff, sizeof(errBuff));
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	errText = strerror(errno);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return errText;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TService::Imp
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	Imp() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	static void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv);
Toshihiro Shimizu 890ddd
	static void WINAPI serviceCtrl(DWORD dwCtrlCode);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static BOOL WINAPI controlHandler(DWORD dwCtrlType);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static bool reportStatusToSCMgr(long currentState, long win32ExitCode, long waitHint);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
	std::string m_name;
Shinya Kitaoka 2148c8
	std::string m_displayName;
Toshihiro Shimizu 890ddd
	static bool m_console;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	static SERVICE_STATUS_HANDLE m_hService;
Toshihiro Shimizu 890ddd
	static SERVICE_STATUS m_ssStatus; // current status of the service
Toshihiro Shimizu 890ddd
	static DWORD m_dwErr;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
SERVICE_STATUS_HANDLE TService::Imp::m_hService = 0;
Toshihiro Shimizu 890ddd
SERVICE_STATUS TService::Imp::m_ssStatus;
Toshihiro Shimizu 890ddd
DWORD TService::Imp::m_dwErr = 0;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool TService::Imp::m_console = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
TService::TService(const std::string &name, const std::string &displayName)
Toshihiro Shimizu 890ddd
	: m_imp(new Imp)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_imp->m_name = name;
Toshihiro Shimizu 890ddd
	m_imp->m_displayName = displayName;
Toshihiro Shimizu 890ddd
	m_instance = this;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TService::~TService()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TService *TService::instance()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TService *TService::m_instance = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TService::setStatus(Status status, long exitCode, long waitHint)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	if (!isRunningAsConsoleApp())
Toshihiro Shimizu 890ddd
		TService::Imp::reportStatusToSCMgr(status, exitCode, waitHint);
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		if (status == Stopped)
Toshihiro Shimizu 890ddd
			exit(1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	if (status == Stopped)
Toshihiro Shimizu 890ddd
		exit(1);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
std::string TService::getName() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_imp->m_name;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
std::string TService::getDisplayName() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_imp->m_displayName;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void WINAPI TService::Imp::serviceCtrl(DWORD dwCtrlCode)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Handle the requested control code.
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	switch (dwCtrlCode) {
Toshihiro Shimizu 890ddd
	// Stop the service.
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	// SERVICE_STOP_PENDING should be reported before
Toshihiro Shimizu 890ddd
	// setting the Stop Event - hServerStopEvent - in
Toshihiro Shimizu 890ddd
	// ServiceStop().  This avoids a race condition
Toshihiro Shimizu 890ddd
	// which may result in a 1053 - The Service did not respond...
Toshihiro Shimizu 890ddd
	// error.
Toshihiro Shimizu 890ddd
	case SERVICE_CONTROL_STOP:
Toshihiro Shimizu 890ddd
	case SERVICE_CONTROL_SHUTDOWN: {
Toshihiro Shimizu 890ddd
		TService::Imp::reportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 3000 /*1*/ /*0*/);
Toshihiro Shimizu 890ddd
		TService::instance()->onStop();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TService::Imp::reportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 3000);
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Update the service status.
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	case SERVICE_CONTROL_INTERROGATE:
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// invalid control code
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	default:
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	reportStatusToSCMgr(m_ssStatus.dwCurrentState, NO_ERROR, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void WINAPI TService::Imp::serviceMain(DWORD dwArgc, LPTSTR *lpszArgv)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// register our service control handler:
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	m_hService = RegisterServiceCtrlHandler(
Toshihiro Shimizu 890ddd
		TService::instance()->getName().c_str(), TService::Imp::serviceCtrl);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_hService == 0)
Toshihiro Shimizu 890ddd
		goto cleanup;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// SERVICE_STATUS members that don't change in example
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	m_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
Toshihiro Shimizu 890ddd
	m_ssStatus.dwServiceSpecificExitCode = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// report the status to the service control manager.
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	if (!reportStatusToSCMgr(
Toshihiro Shimizu 890ddd
			SERVICE_START_PENDING, // service state
Toshihiro Shimizu 890ddd
			NO_ERROR,			   // exit code
Toshihiro Shimizu 890ddd
			3000))				   // wait hint
Toshihiro Shimizu 890ddd
		goto cleanup;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// AGGIUNGERE INIZIALIZZAZIONE QUI
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!reportStatusToSCMgr(
Toshihiro Shimizu 890ddd
			SERVICE_RUNNING, // service state
Toshihiro Shimizu 890ddd
			NO_ERROR,		 // exit code
Toshihiro Shimizu 890ddd
			0))				 // wait hint
Toshihiro Shimizu 890ddd
		goto cleanup;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TService::instance()->onStart(dwArgc, lpszArgv);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
cleanup:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// try to report the stopped status to the service control manager.
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	if (m_hService)
Toshihiro Shimizu 890ddd
		reportStatusToSCMgr(SERVICE_STOPPED, m_dwErr, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  TService::Imp::controlHandler( DWORD dwCtrlType )
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  PURPOSE: Handled console control events
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  PARAMETERS:
Toshihiro Shimizu 890ddd
//    dwCtrlType - type of control event
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  RETURN VALUE:
Toshihiro Shimizu 890ddd
//    True - handled
Toshihiro Shimizu 890ddd
//    False - unhandled
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  COMMENTS:
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
BOOL WINAPI TService::Imp::controlHandler(DWORD dwCtrlType)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (dwCtrlType) {
Toshihiro Shimizu 890ddd
	case CTRL_CLOSE_EVENT:
Toshihiro Shimizu 890ddd
	case CTRL_LOGOFF_EVENT:
Toshihiro Shimizu 890ddd
	case CTRL_SHUTDOWN_EVENT:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
Toshihiro Shimizu 890ddd
	case CTRL_C_EVENT:	 // SERVICE_CONTROL_STOP in debug mode
Toshihiro Shimizu 890ddd
		_tprintf(
Toshihiro Shimizu 890ddd
			TEXT("Stopping %s.\n"),
Toshihiro Shimizu 890ddd
			TService::instance()->getDisplayName().c_str());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TService::instance()->onStop();
Toshihiro Shimizu 890ddd
		return TRUE;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return FALSE;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  FUNCTION: ReportStatusToSCMgr()
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  PURPOSE: Sets the current status of the service and
Toshihiro Shimizu 890ddd
//           reports it to the Service Control Manager
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  PARAMETERS:
Toshihiro Shimizu 890ddd
//    dwCurrentState - the state of the service
Toshihiro Shimizu 890ddd
//    dwWin32ExitCode - error code to report
Toshihiro Shimizu 890ddd
//    dwWaitHint - worst case estimate to next checkpoint
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  RETURN VALUE:
Toshihiro Shimizu 890ddd
//    TRUE  - success
Toshihiro Shimizu 890ddd
//    FALSE - failure
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//  COMMENTS:
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool TService::Imp::reportStatusToSCMgr(long currentState, long win32ExitCode, long waitHint)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
	SERVICE_STATUS srvStatus;		// Declare a SERVICE_STATUS structure, and fill it in
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	srvStatus.dwServiceType  = SERVICE_WIN32_OWN_PROCESS;	// We're a service running in our own process
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Set the state of the service from the argument, and save it away
Toshihiro Shimizu 890ddd
	// for future use
Toshihiro Shimizu 890ddd
	_dwPrevState=_dwCurrState;
Toshihiro Shimizu 890ddd
	srvStatus.dwCurrentState = _dwCurrState = dwState;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Which commands will we accept from the SCM? All the common ones...
Toshihiro Shimizu 890ddd
	srvStatus.dwControlsAccepted =	SERVICE_ACCEPT_STOP | 
Toshihiro Shimizu 890ddd
													SERVICE_ACCEPT_PAUSE_CONTINUE | 
Toshihiro Shimizu 890ddd
													SERVICE_ACCEPT_SHUTDOWN;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	srvStatus.dwWin32ExitCode = dwExitCode;	// Set the Win32 exit code for the service
Toshihiro Shimizu 890ddd
	srvStatus.dwServiceSpecificExitCode = 0;	// Set the service-specific exit code
Toshihiro Shimizu 890ddd
	srvStatus.dwCheckPoint = dwProgress;	// Set the checkpoint value	
Toshihiro Shimizu 890ddd
	srvStatus.dwWaitHint = __WAIT_TIME_FOR_SERVICE;	// 3 second timeout for waits
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return SetServiceStatus( _hService, &srvStatus); // pass the structure to the SCM
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static DWORD dwCheckPoint = 1;
Toshihiro Shimizu 890ddd
	BOOL fResult = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_console) // when running as a console application we don't report to the SCM
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (currentState == SERVICE_START_PENDING)
Toshihiro Shimizu 890ddd
			m_ssStatus.dwControlsAccepted = 0;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			m_ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
Toshihiro Shimizu 890ddd
											SERVICE_ACCEPT_PAUSE_CONTINUE |
Toshihiro Shimizu 890ddd
											SERVICE_ACCEPT_SHUTDOWN;
Toshihiro Shimizu 890ddd
		;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_ssStatus.dwCurrentState = currentState;
Toshihiro Shimizu 890ddd
		m_ssStatus.dwWin32ExitCode = win32ExitCode;
Toshihiro Shimizu 890ddd
		m_ssStatus.dwWaitHint = waitHint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((currentState == SERVICE_RUNNING) ||
Toshihiro Shimizu 890ddd
			(currentState == SERVICE_STOPPED))
Toshihiro Shimizu 890ddd
			m_ssStatus.dwCheckPoint = 0;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			m_ssStatus.dwCheckPoint = dwCheckPoint++;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Report the status of the service to the service control manager.
Toshihiro Shimizu 890ddd
		//
Toshihiro Shimizu 890ddd
		if (!(fResult = SetServiceStatus(m_hService, &m_ssStatus))) {
Toshihiro Shimizu 890ddd
			TService::addToMessageLog(QString("Failed to set the service status"));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return !!fResult;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TService::run(int argc, char *argv[], bool console)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_imp->m_console = console;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
  DebugBreak();
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	if (console) {
Toshihiro Shimizu 890ddd
		_tprintf(TEXT("Starting %s.\n"), TService::instance()->getDisplayName().c_str());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		SetConsoleCtrlHandler(TService::Imp::controlHandler, TRUE);
Toshihiro Shimizu 890ddd
		TService::instance()->onStart(argc, argv);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		SERVICE_TABLE_ENTRY dispatchTable[2];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
		std::string name = TService::instance()->getName().c_str();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		dispatchTable[0].lpServiceName = (char *)name.c_str();
Toshihiro Shimizu 890ddd
		dispatchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)TService::Imp::serviceMain;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		dispatchTable[1].lpServiceName = NULL;
Toshihiro Shimizu 890ddd
		dispatchTable[1].lpServiceProc = NULL;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!StartServiceCtrlDispatcher(dispatchTable))
Toshihiro Shimizu 890ddd
			TService::addToMessageLog(QString(TEXT("Service start failed.")));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	TService::instance()->onStart(argc, argv);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
void TService::start(const std::string &name)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
void TService::stop(const std::string &name)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool TService::isRunningAsConsoleApp() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_imp->m_console;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
void TService::install(const std::string &name, const std::string &displayName, const TFilePath &appPath)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	SC_HANDLE schService;
Toshihiro Shimizu 890ddd
	SC_HANDLE schSCManager;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	schSCManager = OpenSCManager(
Toshihiro Shimizu 890ddd
		NULL,					// machine (NULL == local)
Toshihiro Shimizu 890ddd
		NULL,					// database (NULL == default)
Toshihiro Shimizu 890ddd
		SC_MANAGER_ALL_ACCESS); // access required
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (schSCManager) {
Toshihiro Shimizu 890ddd
		schService = CreateService(
Toshihiro Shimizu 890ddd
			schSCManager,							   // SCManager database
Toshihiro Shimizu 890ddd
			name.c_str(),							   // name of service
Toshihiro Shimizu 890ddd
			displayName.c_str(),					   // name to display
Toshihiro Shimizu 890ddd
			SERVICE_ALL_ACCESS,						   // desired access
Toshihiro Shimizu 890ddd
			SERVICE_WIN32_OWN_PROCESS,				   // service type
Toshihiro Shimizu 890ddd
			SERVICE_DEMAND_START,					   // start type
Toshihiro Shimizu 890ddd
			SERVICE_ERROR_NORMAL,					   // error control type
Toshihiro Shimizu 890ddd
			toString(appPath.getWideString()).c_str(), // service's binary
Toshihiro Shimizu 890ddd
			NULL,									   // no load ordering group
Toshihiro Shimizu 890ddd
			NULL,									   // no tag identifier
Toshihiro Shimizu 890ddd
			TEXT(SZDEPENDENCIES),					   // dependencies
Toshihiro Shimizu 890ddd
			NULL,									   // LocalSystem account
Toshihiro Shimizu 890ddd
			NULL);									   // no password
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (schService) {
Toshihiro Shimizu 890ddd
			_tprintf(TEXT("%s installed.\n"), displayName.c_str());
Toshihiro Shimizu 890ddd
			CloseServiceHandle(schService);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			_tprintf(TEXT("CreateService failed - %s\n"), getLastErrorText().c_str());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CloseServiceHandle(schSCManager);
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		_tprintf(TEXT("OpenSCManager failed - %s\n"), getLastErrorText().c_str());
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
void TService::remove(const std::string &name)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Shinya Kitaoka 2148c8
	std::string displayName = name;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SC_HANDLE schService;
Toshihiro Shimizu 890ddd
	SC_HANDLE schSCManager;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	schSCManager = OpenSCManager(
Toshihiro Shimizu 890ddd
		NULL,					// machine (NULL == local)
Toshihiro Shimizu 890ddd
		NULL,					// database (NULL == default)
Toshihiro Shimizu 890ddd
		SC_MANAGER_ALL_ACCESS); // access required
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (schSCManager) {
Toshihiro Shimizu 890ddd
		schService = OpenService(schSCManager, name.c_str(), SERVICE_ALL_ACCESS);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (schService) {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			SERVICE_STATUS ssStatus; // current status of the service
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// try to stop the service
Toshihiro Shimizu 890ddd
			if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) {
Toshihiro Shimizu 890ddd
				_tprintf(TEXT("Stopping %s."), displayName.c_str());
Toshihiro Shimizu 890ddd
				Sleep(1000);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				while (QueryServiceStatus(schService, &ssStatus)) {
Toshihiro Shimizu 890ddd
					if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
Toshihiro Shimizu 890ddd
						_tprintf(TEXT("."));
Toshihiro Shimizu 890ddd
						Sleep(1000);
Toshihiro Shimizu 890ddd
					} else
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (ssStatus.dwCurrentState == SERVICE_STOPPED)
Toshihiro Shimizu 890ddd
					_tprintf(TEXT("\n%s stopped.\n"), displayName.c_str());
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					_tprintf(TEXT("\n%s failed to stop.\n"), displayName.c_str());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// now remove the service
Toshihiro Shimizu 890ddd
			if (DeleteService(schService))
Toshihiro Shimizu 890ddd
				_tprintf(TEXT("%s removed.\n"), displayName.c_str());
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				_tprintf(TEXT("DeleteService failed - %s\n"), getLastErrorText().c_str());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CloseServiceHandle(schService);
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			_tprintf(TEXT("OpenService failed - %s\n"), getLastErrorText().c_str());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CloseServiceHandle(schSCManager);
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		_tprintf(TEXT("OpenSCManager failed - %s\n"), getLastErrorText().c_str());
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TService::addToMessageLog(const QString &msg)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	addToMessageLog(msg.toStdString());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
void TService::addToMessageLog(const std::string &msg)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
	TCHAR szMsg[256];
Toshihiro Shimizu 890ddd
	HANDLE hEventSource;
Toshihiro Shimizu 890ddd
	LPCTSTR lpszStrings[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!TService::Imp::m_console) {
Toshihiro Shimizu 890ddd
		TService::Imp::m_dwErr = GetLastError();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Use event logging to log the error.
Toshihiro Shimizu 890ddd
		//
Toshihiro Shimizu 890ddd
		hEventSource = RegisterEventSource(NULL, TService::instance()->getName().c_str());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		_stprintf(szMsg, TEXT("%s error: %d"), TService::instance()->getName().c_str(), TService::Imp::m_dwErr);
Toshihiro Shimizu 890ddd
		lpszStrings[0] = szMsg;
Toshihiro Shimizu 890ddd
		lpszStrings[1] = msg.c_str();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (hEventSource != NULL) {
Toshihiro Shimizu 890ddd
			ReportEvent(hEventSource,		 // handle of event source
Toshihiro Shimizu 890ddd
						EVENTLOG_ERROR_TYPE, // event type
Toshihiro Shimizu 890ddd
						0,					 // event category
Toshihiro Shimizu 890ddd
						0,					 // event ID
Toshihiro Shimizu 890ddd
						NULL,				 // current user's SID
Toshihiro Shimizu 890ddd
						2,					 // strings in lpszStrings
Toshihiro Shimizu 890ddd
						0,					 // no bytes of raw data
Toshihiro Shimizu 890ddd
						lpszStrings,		 // array of error strings
Toshihiro Shimizu 890ddd
						NULL);				 // no raw data
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			(VOID) DeregisterEventSource(hEventSource);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else {
Shinya Kitaoka 2148c8
		std::cout << msg.c_str();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	if (!TService::Imp::m_console) {
Toshihiro Shimizu 890ddd
		QString str(msg.c_str());
Toshihiro Shimizu 890ddd
		TSysLog::error(str);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		std::cout << msg.c_str();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}