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