mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			401 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			401 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* ------------------------------------------------------------------------
 | 
						|
   Windows NT Service class library
 | 
						|
   Copyright Abandoned 1998 Irena Pancirov - Irnet Snc
 | 
						|
   This file is public domain and comes with NO WARRANTY of any kind
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
#include <windows.h>
 | 
						|
#include <process.h>
 | 
						|
#include "nt_servc.h"
 | 
						|
 | 
						|
 | 
						|
static NTService *pService;
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
NTService::NTService()
 | 
						|
{
 | 
						|
 | 
						|
    bOsNT	     = FALSE;
 | 
						|
    //service variables
 | 
						|
    ServiceName      = NULL;
 | 
						|
    hExitEvent	     = 0;
 | 
						|
    bPause	     = FALSE;
 | 
						|
    bRunning	     = FALSE;
 | 
						|
    hThreadHandle    = 0;
 | 
						|
    fpServiceThread  = NULL;
 | 
						|
 | 
						|
    //time-out variables
 | 
						|
    nStartTimeOut    = 15000;
 | 
						|
    nStopTimeOut     = 15000;
 | 
						|
    nPauseTimeOut    = 5000;
 | 
						|
    nResumeTimeOut   = 5000;
 | 
						|
 | 
						|
    //install variables
 | 
						|
    dwDesiredAccess  = SERVICE_ALL_ACCESS;
 | 
						|
    dwServiceType    = SERVICE_WIN32_OWN_PROCESS;
 | 
						|
    dwStartType      = SERVICE_AUTO_START;
 | 
						|
    dwErrorControl   = SERVICE_ERROR_NORMAL;
 | 
						|
    szLoadOrderGroup = NULL;
 | 
						|
    lpdwTagID	     = NULL;
 | 
						|
    szDependencies   = NULL;
 | 
						|
 | 
						|
    my_argc	     = 0;
 | 
						|
    my_argv	     = NULL;
 | 
						|
    hShutdownEvent   = 0;
 | 
						|
    nError	     = 0;
 | 
						|
    dwState	     = 0;
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
NTService::~NTService()
 | 
						|
{
 | 
						|
  if(ServiceName != NULL) delete[] ServiceName;
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
BOOL NTService::GetOS()
 | 
						|
{
 | 
						|
  bOsNT = FALSE;
 | 
						|
  memset(&osVer, 0, sizeof(OSVERSIONINFO));
 | 
						|
  osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 | 
						|
  if (GetVersionEx(&osVer))
 | 
						|
  {
 | 
						|
    if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
 | 
						|
      bOsNT = TRUE;
 | 
						|
  }
 | 
						|
  return bOsNT;
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 Init()  Registers the main service thread with the service manager
 | 
						|
 | 
						|
    ServiceThread - pointer to the main programs entry function
 | 
						|
		    when the service is started
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
long NTService::Init(LPCSTR szInternName,void *ServiceThread)
 | 
						|
{
 | 
						|
 | 
						|
  pService = this;
 | 
						|
 | 
						|
  fpServiceThread = (THREAD_FC)ServiceThread;
 | 
						|
  ServiceName = new char[lstrlen(szInternName)+1];
 | 
						|
  lstrcpy(ServiceName,szInternName);
 | 
						|
 | 
						|
  SERVICE_TABLE_ENTRY stb[] =
 | 
						|
  {
 | 
						|
    { (char *)szInternName,(LPSERVICE_MAIN_FUNCTION) ServiceMain} ,
 | 
						|
    { NULL, NULL }
 | 
						|
  };
 | 
						|
 | 
						|
  return StartServiceCtrlDispatcher(stb); //register with the Service Manager
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
  Install() - Installs the service with Service manager
 | 
						|
  nError values:
 | 
						|
	0  success
 | 
						|
	1  Can't open the Service manager
 | 
						|
	2  Failed to create service
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
BOOL NTService::Install(LPCSTR szInternName,LPCSTR szDisplayName,
 | 
						|
		       LPCSTR szFullPath, LPCSTR szAccountName,LPCSTR szPassword)
 | 
						|
{
 | 
						|
  SC_HANDLE newService, scm;
 | 
						|
 | 
						|
  nError=0;
 | 
						|
 | 
						|
  // open a connection to the SCM
 | 
						|
  scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
 | 
						|
  if(scm)  // Install the new service
 | 
						|
  {  newService = CreateService(
 | 
						|
	scm,
 | 
						|
	szInternName,
 | 
						|
	szDisplayName,
 | 
						|
	dwDesiredAccess,	//default: SERVICE_ALL_ACCESS
 | 
						|
	dwServiceType,		//default: SERVICE_WIN32_OWN_PROCESS
 | 
						|
	dwStartType,		//default: SERVICE_AUTOSTART
 | 
						|
	dwErrorControl,		//default: SERVICE_ERROR_NORMAL
 | 
						|
	szFullPath,		//exec full path
 | 
						|
	szLoadOrderGroup,	//default: NULL
 | 
						|
	lpdwTagID,		//default: NULL
 | 
						|
	szDependencies,		//default: NULL
 | 
						|
	szAccountName,		//default: NULL
 | 
						|
	szPassword);		//default: NULL
 | 
						|
 | 
						|
     if (newService) CloseServiceHandle(newService);  // clean up
 | 
						|
     else	     nError=2;
 | 
						|
 | 
						|
     // clean up
 | 
						|
     CloseServiceHandle(scm);
 | 
						|
  }
 | 
						|
  else nError=1;
 | 
						|
 | 
						|
  return (!nError);
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
  Remove() - Removes  the service
 | 
						|
  nError values:
 | 
						|
	0  success
 | 
						|
	1  Can't open the Service manager
 | 
						|
	2  Failed to locate service
 | 
						|
	3  Failed to delete service
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
BOOL NTService::Remove(LPCSTR szInternName)
 | 
						|
{
 | 
						|
 | 
						|
  SC_HANDLE service, scm;
 | 
						|
 | 
						|
  nError=0;
 | 
						|
 | 
						|
  // open a connection to the SCM
 | 
						|
  scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
 | 
						|
 | 
						|
  if (scm)
 | 
						|
  {
 | 
						|
    //open the service
 | 
						|
    service = OpenService(scm,szInternName, DELETE );
 | 
						|
    if(service)
 | 
						|
    {
 | 
						|
      if(!DeleteService(service)) nError=3;
 | 
						|
      CloseServiceHandle(service);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
     //MessageBox(NULL,"Can't find the service","Remove Error",MB_OK|MB_ICONHAND);
 | 
						|
       nError=2;
 | 
						|
    }
 | 
						|
    CloseServiceHandle(scm);
 | 
						|
  }
 | 
						|
  else nError=1;
 | 
						|
 | 
						|
  return (!nError);
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
   Stop() - this function should be called before the app. exits to stop
 | 
						|
	    the service
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::Stop(void)
 | 
						|
{
 | 
						|
  SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 60000);
 | 
						|
  StopService();
 | 
						|
  SetStatus(SERVICE_STOPPED, NO_ERROR, 0, 1, 1000);
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
  ServiceMain() - This is the function that is called from the
 | 
						|
		  service manager to start the service
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
 | 
						|
{
 | 
						|
 | 
						|
  // registration function
 | 
						|
  pService->hServiceStatusHandle =
 | 
						|
	   RegisterServiceCtrlHandler(pService->ServiceName,
 | 
						|
		       (LPHANDLER_FUNCTION )NTService::ServiceCtrlHandler);
 | 
						|
 | 
						|
  if(!pService->hServiceStatusHandle)
 | 
						|
  {
 | 
						|
      pService->Exit(GetLastError());
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  // notify SCM of progress
 | 
						|
  if(!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 1, 8000))
 | 
						|
  {
 | 
						|
      pService->Exit(GetLastError());
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  // create the exit event
 | 
						|
  pService->hExitEvent = CreateEvent (0, TRUE, FALSE,0);
 | 
						|
  if(!pService->hExitEvent)
 | 
						|
  {
 | 
						|
      pService->Exit(GetLastError());
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  if(!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 3, pService->nStartTimeOut))
 | 
						|
  {
 | 
						|
      pService->Exit(GetLastError());
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  // save start arguments
 | 
						|
  pService->my_argc=argc;
 | 
						|
  pService->my_argv=argv;
 | 
						|
 | 
						|
  // start the service
 | 
						|
  if(!pService->StartService())
 | 
						|
  {
 | 
						|
      pService->Exit(GetLastError());
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  // the service is now running.
 | 
						|
  if(!pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0))
 | 
						|
  {
 | 
						|
      pService->Exit(GetLastError());
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  // wait for exit event
 | 
						|
  WaitForSingleObject (pService->hExitEvent, INFINITE);
 | 
						|
 | 
						|
  // wait for thread to exit
 | 
						|
  WaitForSingleObject (pService->hThreadHandle, 30000);
 | 
						|
 | 
						|
  pService->Exit(0);
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
   StartService() - starts the appliaction thread
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
BOOL NTService::StartService()
 | 
						|
{
 | 
						|
 | 
						|
  // Start the real service's thread (application)
 | 
						|
  hThreadHandle = (HANDLE) _beginthread((THREAD_FC)fpServiceThread,0,(void *)this);
 | 
						|
 | 
						|
  if (hThreadHandle==0) return FALSE;
 | 
						|
 | 
						|
  bRunning = TRUE;
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::StopService()
 | 
						|
{
 | 
						|
  bRunning=FALSE;
 | 
						|
 | 
						|
  // Set the event for application
 | 
						|
  if(hShutdownEvent)
 | 
						|
     SetEvent(hShutdownEvent);
 | 
						|
 | 
						|
  // Set the event for ServiceMain
 | 
						|
  SetEvent(hExitEvent);
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::PauseService()
 | 
						|
{
 | 
						|
    bPause = TRUE;
 | 
						|
    SuspendThread(hThreadHandle);
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::ResumeService()
 | 
						|
{
 | 
						|
    bPause=FALSE;
 | 
						|
    ResumeThread(hThreadHandle);
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
BOOL NTService::SetStatus (DWORD dwCurrentState,DWORD dwWin32ExitCode,
 | 
						|
	    DWORD dwServiceSpecificExitCode,DWORD dwCheckPoint,DWORD dwWaitHint)
 | 
						|
{
 | 
						|
  BOOL bRet;
 | 
						|
  SERVICE_STATUS serviceStatus;
 | 
						|
 | 
						|
   dwState=dwCurrentState;
 | 
						|
 | 
						|
   serviceStatus.dwServiceType	= SERVICE_WIN32_OWN_PROCESS;
 | 
						|
   serviceStatus.dwCurrentState = dwCurrentState;
 | 
						|
 | 
						|
   if (dwCurrentState == SERVICE_START_PENDING)
 | 
						|
	serviceStatus.dwControlsAccepted = 0;	//don't accept conrol events
 | 
						|
   else
 | 
						|
	serviceStatus.dwControlsAccepted =    SERVICE_ACCEPT_STOP |
 | 
						|
	    SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
 | 
						|
 | 
						|
   // if a specific exit code is defined,set up the win32 exit code properly
 | 
						|
   if (dwServiceSpecificExitCode == 0)
 | 
						|
       serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
 | 
						|
   else
 | 
						|
       serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
 | 
						|
 | 
						|
   serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
 | 
						|
 | 
						|
   serviceStatus.dwCheckPoint = dwCheckPoint;
 | 
						|
   serviceStatus.dwWaitHint   = dwWaitHint;
 | 
						|
 | 
						|
   // Pass the status to the Service Manager
 | 
						|
   bRet=SetServiceStatus (hServiceStatusHandle, &serviceStatus);
 | 
						|
 | 
						|
   if(!bRet) StopService();
 | 
						|
 | 
						|
   return bRet;
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::ServiceCtrlHandler(DWORD ctrlCode)
 | 
						|
{
 | 
						|
 | 
						|
  DWORD  dwState = 0;
 | 
						|
 | 
						|
  if(!pService) return;
 | 
						|
 | 
						|
  dwState=pService->dwState;  // get current state
 | 
						|
 | 
						|
  switch(ctrlCode)
 | 
						|
  {
 | 
						|
 | 
						|
   /*********** do we need this ? *******************************
 | 
						|
    case SERVICE_CONTROL_PAUSE:
 | 
						|
	 if (pService->bRunning && ! pService->bPause)
 | 
						|
	 {
 | 
						|
	     dwState = SERVICE_PAUSED;
 | 
						|
	     pService->SetStatus(SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1, pService->nPauseTimeOut);
 | 
						|
	     pService->PauseService();
 | 
						|
	 }
 | 
						|
	 break;
 | 
						|
 | 
						|
   case SERVICE_CONTROL_CONTINUE:
 | 
						|
	if (pService->bRunning && pService->bPause)
 | 
						|
	{
 | 
						|
	    dwState = SERVICE_RUNNING;
 | 
						|
	    pService->SetStatus(SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1, pService->nResumeTimeOut);
 | 
						|
	    pService->ResumeService();
 | 
						|
	}
 | 
						|
	break;
 | 
						|
   ****************************************************************/
 | 
						|
 | 
						|
    case SERVICE_CONTROL_SHUTDOWN:
 | 
						|
    case SERVICE_CONTROL_STOP:
 | 
						|
	 dwState = SERVICE_STOP_PENDING;
 | 
						|
	 pService->SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, pService->nStopTimeOut);
 | 
						|
	 pService->StopService();
 | 
						|
	 break;
 | 
						|
 | 
						|
   default:
 | 
						|
	pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  //pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
 | 
						|
}
 | 
						|
/* ------------------------------------------------------------------------
 | 
						|
 | 
						|
 -------------------------------------------------------------------------- */
 | 
						|
void NTService::Exit(DWORD error)
 | 
						|
{
 | 
						|
  if (hExitEvent) CloseHandle(hExitEvent);
 | 
						|
 | 
						|
  // Send a message to the scm to tell that we stop
 | 
						|
  if (hServiceStatusHandle)
 | 
						|
      SetStatus(SERVICE_STOPPED, error,0, 0, 0);
 | 
						|
 | 
						|
  // If the thread has started kill it ???
 | 
						|
  // if (hThreadHandle) CloseHandle(hThreadHandle);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------- the end -------------------------------------- */
 |