/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* 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 Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifdef _WIN32
#include "Common.h"
#include "Log.h"
#include
#include
#include
#if !defined(WINADVAPI)
#if !defined(_ADVAPI32_)
#define WINADVAPI DECLSPEC_IMPORT
#else
#define WINADVAPI
#endif
#endif
extern int main(int argc, char** argv);
extern char serviceLongName[];
extern char serviceName[];
extern char serviceDescription[];
extern int m_ServiceStatus;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
// cppcheck-suppress syntaxError
typedef WINADVAPI BOOL (WINAPI* CSD_T)(SC_HANDLE, DWORD, LPCVOID);
bool WinServiceInstall()
{
SC_HANDLE serviceControlMgr = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (serviceControlMgr)
{
char path[_MAX_PATH + 10];
if (GetModuleFileName( 0, path, sizeof(path) / sizeof(path[0])) > 0)
{
SC_HANDLE service;
std::strcat(path, " --service");
service = CreateService(serviceControlMgr,
serviceName, // name of service
serviceLongName, // service name to display
SERVICE_ALL_ACCESS, // desired access
// service type
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_AUTO_START, // start type
SERVICE_ERROR_IGNORE, // error control type
path, // service's binary
0, // no load ordering group
0, // no tag identifier
0, // no dependencies
0, // LocalSystem account
0); // no password
if (service)
{
HMODULE advapi32 = GetModuleHandle("ADVAPI32.DLL");
if (!advapi32)
{
CloseServiceHandle(service);
CloseServiceHandle(serviceControlMgr);
return false;
}
CSD_T ChangeService_Config2 = (CSD_T) GetProcAddress(advapi32, "ChangeServiceConfig2A");
if (!ChangeService_Config2)
{
CloseServiceHandle(service);
CloseServiceHandle(serviceControlMgr);
return false;
}
SERVICE_DESCRIPTION sdBuf;
sdBuf.lpDescription = serviceDescription;
ChangeService_Config2(
service, // handle to service
SERVICE_CONFIG_DESCRIPTION, // change: description
&sdBuf); // new data
SC_ACTION _action[1];
_action[0].Type = SC_ACTION_RESTART;
_action[0].Delay = 10000;
SERVICE_FAILURE_ACTIONS sfa;
ZeroMemory(&sfa, sizeof(SERVICE_FAILURE_ACTIONS));
sfa.lpsaActions = _action;
sfa.cActions = 1;
sfa.dwResetPeriod = INFINITE;
ChangeService_Config2(
service, // handle to service
SERVICE_CONFIG_FAILURE_ACTIONS, // information level
&sfa); // new data
CloseServiceHandle(service);
}
}
CloseServiceHandle(serviceControlMgr);
}
return true;
}
bool WinServiceUninstall()
{
SC_HANDLE serviceControlMgr = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
if (serviceControlMgr)
{
SC_HANDLE service = OpenService(serviceControlMgr,
serviceName, SERVICE_QUERY_STATUS | DELETE);
if (service)
{
SERVICE_STATUS serviceStatus2;
if (QueryServiceStatus(service, &serviceStatus2))
{
if (serviceStatus2.dwCurrentState == SERVICE_STOPPED)
{
DeleteService(service);
}
}
CloseServiceHandle(service);
}
CloseServiceHandle(serviceControlMgr);
}
return true;
}
void WINAPI ServiceControlHandler(DWORD controlCode)
{
switch (controlCode)
{
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
m_ServiceStatus = 0;
return;
case SERVICE_CONTROL_PAUSE:
m_ServiceStatus = 2;
serviceStatus.dwCurrentState = SERVICE_PAUSED;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
break;
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
m_ServiceStatus = 1;
break;
default:
if (controlCode >= 128 && controlCode <= 255)
// user defined control code
{
break;
}
else
// unrecognized control code
{
break;
}
}
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
void WINAPI ServiceMain(DWORD argc, char* argv[])
{
// initialise service status
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
serviceStatus.dwWin32ExitCode = NO_ERROR;
serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, ServiceControlHandler);
if (serviceStatusHandle)
{
char path[_MAX_PATH + 1];
unsigned int i, last_slash = 0;
GetModuleFileName(0, path, sizeof(path) / sizeof(path[0]));
for (i = 0; i < std::strlen(path); i++)
{
if (path[i] == '\\') { last_slash = i; }
}
path[last_slash] = 0;
// service is starting
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
// do initialisation here
SetCurrentDirectory(path);
// running
serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus( serviceStatusHandle, &serviceStatus );
////////////////////////
// service main cycle //
////////////////////////
m_ServiceStatus = 1;
argc = 1;
main(argc, argv);
// service was stopped
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
// do cleanup here
// service is now stopped
serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(serviceStatusHandle, &serviceStatus);
}
}
bool WinServiceRun()
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ serviceName, ServiceMain },
{ 0, 0 }
};
if (!StartServiceCtrlDispatcher(serviceTable))
{
LOG_ERROR("server", "StartService Failed. Error [{}]", ::GetLastError());
return false;
}
return true;
}
#endif