/******************************************************************************/
/*
/*    NT Service Class
/*
/*    copyright 2003  , Stefan Voitel - Berlin / Germany
/*
/*    stefan.voitel@winways.de
/******************************************************************************/

#include <stdlib.h>

#include "cService.h"

namespace ModuleTService {
   TService* Service; //
   };

// -----------------------------------------------------------------------------

void WINAPI TService::ServiceMain (DWORD argc, char* argv[]) {
using namespace ModuleTService;

Service->m_StatusHandle = RegisterServiceCtrlHandler(Service->GetName(),
                                                                ServiceHandler);
if (Service->succeeded (Service->m_StatusHandle != NULL)) {
   Service->SetStatus (SERVICE_START_PENDING);

   if (Service->Init()) {
      Service->SetStatus (SERVICE_RUNNING);
      Service->ServiceProc();
      Service->SetStatus (SERVICE_STOP_PENDING);
      Service->Cleanup();
      Service->SetStatus (SERVICE_STOPPED);
      }
   else Service->SetStatus (SERVICE_STOPPED);
   }
else Service->SetStatus (SERVICE_STOPPED);
}
#pragma warning (default : 100)

//                   ----------------------------

void WINAPI TService::ServiceHandler (DWORD control) {
using namespace ModuleTService;

switch (control) {
   case SERVICE_CONTROL_INTERROGATE:
      Service->SetStatus (Service->m_StatusCode);
      break;

   case SERVICE_CONTROL_STOP:
   case SERVICE_CONTROL_SHUTDOWN:
      Service->SetStatus (SERVICE_STOP_PENDING);
      Service->m_Terminated = true;
      break;
   }
}

//                   ----------------------------

BOOL WINAPI TService::ConsoleHandler (DWORD dwCtrlType) {
using namespace ModuleTService;

if (dwCtrlType == CTRL_LOGOFF_EVENT)
   Service->LogoffEvent ();
else Service->ShutdownEvent ();
return TRUE;
}

// -----------------------------------------------------------------------------

TService::TService() :
      m_StatusHandle(NULL),m_StatusCode(SERVICE_STOPPED),m_Terminated(false) {

ModuleTService::Service = this;

ZeroMemory (m_ErrorString,sizeof(m_ErrorString));
succeeded(SetConsoleCtrlHandler (ConsoleHandler,TRUE));
}

// ----------------------------

TService::~TService() {
if (m_EventLog)
   DeregisterEventSource (m_EventLog);
}

// ----------------------------

bool TService::shopen (tSvcHandle &hService) {
bool 			success = false;
tSvcHandle	hSCM;

if ((hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS)) != NULL)	{
   hService = OpenService(hSCM,GetName(),SERVICE_ALL_ACCESS);
   success = succeeded (hService != NULL);
   CloseServiceHandle (hSCM);
   }
else succeeded (false);
return success;
}

// ----------------------------

void TService::shclose (tSvcHandle hService) {
CloseServiceHandle (hService);
}

// ----------------------------
void 	TService::SetStatus (DWORD status) {
m_StatusCode  = status;

SERVICE_STATUS ss;
ss.dwServiceType              = SERVICE_WIN32_OWN_PROCESS;
ss.dwCurrentState             = m_StatusCode;
ss.dwControlsAccepted	      = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
ss.dwWin32ExitCode            = NOERROR;
ss.dwServiceSpecificExitCode  = NOERROR;
ss.dwCheckPoint               = 0;
ss.dwWaitHint                 = 3000;

if (! succeeded (SetServiceStatus (m_StatusHandle,&ss)))
   LogEvent (m_ErrorString,evWarning);
}

// ----------------------------

bool TService::succeeded (BOOL success) {
DWORD SysError = success ? ERROR_SUCCESS : GetLastError();

FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,NULL,SysError,
									MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
                                    m_ErrorString,sizeof(m_ErrorString),NULL);
return SysError == ERROR_SUCCESS;
}

// -----------------------------------------------------------------------------

bool TService::Execute () {
m_EventLog = RegisterEventSource (NULL,GetName());

SERVICE_TABLE_ENTRY entries[2];
entries[0].lpServiceName = (char*) GetName();
entries[0].lpServiceProc = ServiceMain;
entries[1].lpServiceName = NULL;
entries[1].lpServiceProc = NULL;

bool  success = succeeded (StartServiceCtrlDispatcher(entries));
if (! success)
   LogEvent (m_ErrorString,evError);

//system("start cgid");

return success;
}

// ----------------------------

bool TService::ConsoleMode (void) {
m_EventLog = RegisterEventSource(NULL,GetName());

bool success = false;
if (Init())	{
   ServiceProc();
   Cleanup ();
   success = true;
   }
return success;
}

// -----------------------------------------------------------------------------

bool TService::Start() {
bool         success = false;
tSvcHandle   hService;

if (shopen (hService)) {
   success = succeeded (StartService (hService,0,NULL));
   shclose (hService);
   }
return success;
}

// ----------------------------

extern size_t ExecuteProcess(CString FullPathToExe, CString Parameters, size_t SecondsToWait);

bool TService::Stop() {
bool         success = false;
tSvcHandle   hService;

if (shopen (hService)) {
   SetCurrentDirectory("c:\\Development\\cgid\\cgid"); 
   ShellExecute(NULL, "open", "kill_cgid.exe", NULL, NULL, SW_SHOWNORMAL);
   //ExecuteProcess("C:\\Development\\cgid\\cgid\\kill_cgid.exe", "", INFINITE);
   SERVICE_STATUS   state;
   success = succeeded (ControlService (hService,SERVICE_CONTROL_STOP,&state));
   shclose (hService);
   }
return success;
}

// ----------------------------

bool TService::Remove() {
Stop();

bool         success = false;
tSvcHandle   hService;

if (shopen (hService)) {
   success = succeeded (DeleteService (hService));
   shclose (hService);

   HKEY hKey;
   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,REG_EVENTLOG,0,KEY_ALL_ACCESS,&hKey)
                                                           == ERROR_SUCCESS) {
      RegDeleteKey (hKey,GetName());
      RegCloseKey (hKey);
      }
   }
return success;
}

// ----------------------------

bool TService::Install() {
bool        success = false;
SC_HANDLE   hService,hSCManager;
char        imagePath[MAX_PATH];

GetModuleFileName(NULL,imagePath,MAX_PATH);
if (succeeded ((hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS))
                                                                   != NULL)) {
   if (succeeded ((hService = ::CreateService (hSCManager,
                          GetName(),GetDisplayName(),
                          SERVICE_ALL_ACCESS,
                          SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,
                          SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,
                          imagePath,NULL,NULL,NULL,NULL,NULL)) != NULL)) {
      CloseServiceHandle (hService);
      success = true;
      }
   CloseServiceHandle (hSCManager);
   }

if (success) {
   UINT f = EVENTLOG_ERROR_TYPE|EVENTLOG_WARNING_TYPE|EVENTLOG_INFORMATION_TYPE;

   char   szKey [MAX_PATH];
   wsprintf (szKey,"%s\\%s",REG_EVENTLOG,GetName());

   HKEY hKey;
   if (RegCreateKey (HKEY_LOCAL_MACHINE,szKey,&hKey) == ERROR_SUCCESS) {
      char   mod[MAX_PATH];
      DWORD  len = GetModuleFileName (NULL,mod,MAX_PATH);

      RegSetValueEx(hKey,"TypesSupported",0,REG_DWORD,(BYTE*) &f,sizeof(DWORD));
      RegSetValueEx(hKey,"EventMessageFile",0,REG_SZ,(BYTE*) mod,len+1);
      RegCloseKey (hKey);
      }
   }
return success;
}

// ----------------------------

bool TService::Help (DWORD context) {
char file [MAX_PATH +6],*p;

GetModuleFileName (NULL,file,MAX_PATH);
if ((p = strrchr (file,'.')) != NULL)
   strcpy (p,".hlp");
return WinHelp (NULL,file,context ? HELP_CONTEXT : HELP_CONTENTS,context) != 0;
}

// -----------------------------------------------------------------------------

void TService::PrintLastError (const char *cap) {
DWORD n;

if (cap != NULL && *cap) {
   WriteConsole (GetStdHandle(STD_ERROR_HANDLE),"\r\n",2,&n,NULL);
   WriteConsole (GetStdHandle(STD_ERROR_HANDLE),cap,(DWORD)strlen(cap),&n,NULL);
   }

char oem[sizeof(m_ErrorString)];
ZeroMemory (oem,sizeof(oem));

CharToOemBuff (m_ErrorString,oem,(DWORD) strlen(m_ErrorString));
WriteConsole (GetStdHandle(STD_ERROR_HANDLE),"\r\n",2,&n,NULL);
WriteConsole (GetStdHandle(STD_ERROR_HANDLE),oem,(DWORD) strlen(oem),&n,NULL);
}

// ----------------------------

void TService::LogEvent (char* str,evLogType type,WORD Category) {
if (m_EventLog != NULL) {
   const char* msgs[1];
   msgs[0] = str;
   ReportEvent (m_EventLog,(WORD) type,Category,0,NULL,1,0,msgs,NULL);
   }
}

// -----------------------------------------------------------------------------

bool TService::SetConfigValue (char* key,BYTE *b,DWORD n,cfValType t) {
char	RegPath[255];
HKEY 	hk;
DWORD disp;
bool 	success = false;

wsprintf (RegPath,REG_CONFIG,GetName());
if (succeeded (RegCreateKeyEx (HKEY_LOCAL_MACHINE,RegPath,0,NULL,
                     REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hk,&disp)
                                                           == ERROR_SUCCESS)) {
   ZeroMemory (b,n);
   success = succeeded (RegSetValueEx (hk,key,0,(DWORD)t,b,n) == ERROR_SUCCESS);
   RegCloseKey (hk);
   }
return success;
}

// ----------------------------

bool TService::GetConfigValue (char* key,BYTE *b,DWORD *n,cfValType *t) {
char	RegPath[255];
HKEY 	hk;
DWORD disp;
bool 	success = false;

wsprintf (RegPath,REG_CONFIG,GetName());
if (succeeded (RegCreateKeyEx (HKEY_LOCAL_MACHINE,RegPath,0,NULL,
                     REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hk,&disp)
                                                           == ERROR_SUCCESS)) {
   ZeroMemory (b,*n);
   success = succeeded (RegQueryValueEx (hk,key,0,(DWORD*)t,b,n)
                                                              == ERROR_SUCCESS);
   RegCloseKey (hk);
   }
return success;
}
// -----------------------------------------------------------------------------
// EOF

