mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 15:50:51 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			232 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2005 MySQL AB
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation; version 2 of the License.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 | |
| 
 | |
| #include "my_global.h"
 | |
| #include <windows.h>
 | |
| #include "WindowsService.h"
 | |
| 
 | |
| static WindowsService *gService;
 | |
| 
 | |
| WindowsService::WindowsService(const char *p_serviceName,
 | |
|                                const char *p_displayName) :
 | |
|   statusCheckpoint(0),
 | |
|   serviceName(p_serviceName),
 | |
|   displayName(p_displayName),
 | |
|   inited(FALSE),
 | |
|   dwAcceptedControls(SERVICE_ACCEPT_STOP),
 | |
|   debugging(FALSE)
 | |
| {
 | |
|   DBUG_ASSERT(serviceName != NULL);
 | |
| 
 | |
|   /* TODO: shouldn't we check displayName too (can it really be NULL)? */
 | |
| 
 | |
|   /* WindowsService is assumed to be singleton. Let's assure this. */
 | |
|   DBUG_ASSERT(gService == NULL);
 | |
| 
 | |
|   gService= this;
 | |
| 
 | |
|   status.dwServiceType= SERVICE_WIN32_OWN_PROCESS;
 | |
|   status.dwServiceSpecificExitCode= 0;
 | |
| }
 | |
| 
 | |
| WindowsService::~WindowsService(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| BOOL WindowsService::Install(const char *username, const char *password)
 | |
| {
 | |
|   bool ret_val= FALSE;
 | |
|   SC_HANDLE newService;
 | |
|   SC_HANDLE scm;
 | |
| 
 | |
|   if (IsInstalled())
 | |
|     return TRUE;
 | |
| 
 | |
|   // determine the name of the currently executing file
 | |
|   char szFilePath[_MAX_PATH];
 | |
|   GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
 | |
| 
 | |
|   // open a connection to the SCM
 | |
|   if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
 | |
|     return FALSE;
 | |
| 
 | |
|   newService= CreateService(scm, serviceName, displayName,
 | |
|                             SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
 | |
|                             SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
 | |
|                             szFilePath, NULL, NULL, NULL, username,
 | |
|                             password);
 | |
| 
 | |
|   if (newService)
 | |
|   {
 | |
|     CloseServiceHandle(newService);
 | |
|     ret_val= TRUE;
 | |
|   }
 | |
| 
 | |
|   CloseServiceHandle(scm);
 | |
|   return ret_val;
 | |
| }
 | |
| 
 | |
| BOOL WindowsService::Init()
 | |
| {
 | |
|   DBUG_ASSERT(serviceName != NULL);
 | |
| 
 | |
|   if (inited)
 | |
|     return TRUE;
 | |
| 
 | |
|   SERVICE_TABLE_ENTRY stb[] =
 | |
|   {
 | |
|     { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
 | |
|     { NULL, NULL }
 | |
|   };
 | |
|   inited= TRUE;
 | |
|   return StartServiceCtrlDispatcher(stb); //register with the Service Manager
 | |
| }
 | |
| 
 | |
| BOOL WindowsService::Remove()
 | |
| {
 | |
|   bool ret_val= FALSE;
 | |
| 
 | |
|   if (!IsInstalled())
 | |
|     return TRUE;
 | |
| 
 | |
|   // open a connection to the SCM
 | |
|   SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
 | |
|   if (!scm)
 | |
|     return FALSE;
 | |
| 
 | |
|   SC_HANDLE service= OpenService(scm, serviceName, DELETE);
 | |
|   if (service)
 | |
|   {
 | |
|     if (DeleteService(service))
 | |
|       ret_val= TRUE;
 | |
|     DWORD dw= ::GetLastError();
 | |
|     CloseServiceHandle(service);
 | |
|   }
 | |
| 
 | |
|   CloseServiceHandle(scm);
 | |
|   return ret_val;
 | |
| }
 | |
| 
 | |
| BOOL WindowsService::IsInstalled()
 | |
| {
 | |
|   BOOL ret_val= FALSE;
 | |
| 
 | |
|   SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
 | |
|   SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS);
 | |
| 
 | |
|   ret_val= serv_handle != NULL;
 | |
| 
 | |
|   ::CloseServiceHandle(serv_handle);
 | |
|   ::CloseServiceHandle(scm);
 | |
| 
 | |
|   return ret_val;
 | |
| }
 | |
| 
 | |
| void WindowsService::SetAcceptedControls(DWORD acceptedControls)
 | |
| {
 | |
|   dwAcceptedControls= acceptedControls;
 | |
| }
 | |
| 
 | |
| 
 | |
| BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint,
 | |
|                                   DWORD dwError)
 | |
| {
 | |
|   if (debugging)
 | |
|     return TRUE;
 | |
| 
 | |
|   if(currentState == SERVICE_START_PENDING)
 | |
|     status.dwControlsAccepted= 0;
 | |
|   else
 | |
|     status.dwControlsAccepted= dwAcceptedControls;
 | |
| 
 | |
|   status.dwCurrentState= currentState;
 | |
|   status.dwWin32ExitCode= dwError != 0 ?
 | |
|     ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR;
 | |
|   status.dwWaitHint= waitHint;
 | |
|   status.dwServiceSpecificExitCode= dwError;
 | |
| 
 | |
|   if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED)
 | |
|   {
 | |
|     status.dwCheckPoint= 0;
 | |
|     statusCheckpoint= 0;
 | |
|   }
 | |
|   else
 | |
|     status.dwCheckPoint= ++statusCheckpoint;
 | |
| 
 | |
|   // Report the status of the service to the service control manager.
 | |
|   BOOL result= SetServiceStatus(statusHandle, &status);
 | |
|   if (!result)
 | |
|     Log("ReportStatus failed");
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv)
 | |
| {
 | |
|   statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler);
 | |
|   if (statusHandle && ReportStatus(SERVICE_START_PENDING))
 | |
|     Run(argc, argv);
 | |
|   ReportStatus(SERVICE_STOPPED);
 | |
| }
 | |
| 
 | |
| void WindowsService::HandleControlCode(DWORD opcode)
 | |
| {
 | |
|   // Handle the requested control code.
 | |
|   switch(opcode) {
 | |
|   case SERVICE_CONTROL_STOP:
 | |
|     // Stop the service.
 | |
|     status.dwCurrentState= SERVICE_STOP_PENDING;
 | |
|     Stop();
 | |
|     break;
 | |
| 
 | |
|   case SERVICE_CONTROL_PAUSE:
 | |
|     status.dwCurrentState= SERVICE_PAUSE_PENDING;
 | |
|     Pause();
 | |
|     break;
 | |
| 
 | |
|   case SERVICE_CONTROL_CONTINUE:
 | |
|     status.dwCurrentState= SERVICE_CONTINUE_PENDING;
 | |
|     Continue();
 | |
|     break;
 | |
| 
 | |
|   case SERVICE_CONTROL_SHUTDOWN:
 | |
|     Shutdown();
 | |
|     break;
 | |
| 
 | |
|   case SERVICE_CONTROL_INTERROGATE:
 | |
|     ReportStatus(status.dwCurrentState);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     // invalid control code
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv)
 | |
| {
 | |
|   DBUG_ASSERT(gService != NULL);
 | |
| 
 | |
|   // register our service control handler:
 | |
|   gService->RegisterAndRun(argc, argv);
 | |
| }
 | |
| 
 | |
| void WINAPI WindowsService::ControlHandler(DWORD opcode)
 | |
| {
 | |
|   DBUG_ASSERT(gService != NULL);
 | |
| 
 | |
|   return gService->HandleControlCode(opcode);
 | |
| }
 |