www.pudn.com > insoructions-nitm.zip > 1ServiceApp.cpp, change:2004-04-14,size:13820b


// ServiceApp.cpp: implementation of the CServiceApp class. 
// 
/******************************************************************** 
	created:	2004/12/03 
	author:		Robin Liu 
	email:		robinliu@tsinghua.org.cn 
	purpose:	Create a NT service framework. 
*********************************************************************/ 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include <stdlib.h> 
#include <stdio.h> 
#include "tchar.h" 
#include "SrvAppFactory.h" 
#include "ServiceApp.h" 
#include "resource.h" 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
 
// User-defined control code. Range 128 to 255. 
const SERVICE_CTRL_CODE SERVICE_CONTROL_DEALT		= 0x00000080; 
const SERVICE_CTRL_CODE SERVICE_CONTROL_INSTALL		= 0x00000081; 
const SERVICE_CTRL_CODE SERVICE_CONTROL_UNINSTALL	= 0x00000082; 
const SERVICE_CTRL_CODE SERVICE_CONTROL_START		= 0x00000083; 
const SERVICE_CTRL_CODE SERVICE_CONTROL_HELP		= 0x00000084; 
 
const DWORD WAIT_TIME_FOR_SERVICE = 3000; 
 
IMPLEMENT_SERVICE(CServiceApp) 
 
HINSTANCE CServiceApp::m_hInstance = NULL; 
HINSTANCE CServiceApp::m_hPrevInstance = NULL; 
LPSTR CServiceApp::m_lpCmdLine = NULL; 
int CServiceApp::m_nCmdShow = NULL; 
 
CServiceApp::CServiceApp() 
{ 
 
} 
 
CServiceApp::~CServiceApp() 
{ 
	delete m_lpCmdLine; 
	m_lpCmdLine = NULL; 
} 
 
int CServiceApp::Main(HINSTANCE hInstance, LPSTR lpCmdLine) 
{ 
	SERVICE_CTRL_CODE svrCtrlCode; 
	 
	Instance()->Init(); 
	svrCtrlCode = Instance()->ProcessArguments(); 
	 
	switch(svrCtrlCode) { 
	case SERVICE_CONTROL_INSTALL: 
		Instance()->Install(); 
		break; 
	case SERVICE_CONTROL_UNINSTALL: 
		Instance()->Uninstall(); 
		break; 
	case SERVICE_CONTROL_START: 
		Instance()->Start(); 
		break; 
	case SERVICE_CONTROL_CONTINUE: 
		Instance()->Continue(); 
		break; 
	case SERVICE_CONTROL_PAUSE: 
		Instance()->Pause(); 
		break; 
	case SERVICE_CONTROL_SHUTDOWN: 
		Instance()->Shutdown(); 
		break; 
	case SERVICE_CONTROL_STOP: 
		Instance()->Stop(); 
		break; 
	case SERVICE_CONTROL_HELP: 
	default: 
		Instance()->Help(); 
	} 
	return 0; 
	/* 
	case SERVICE_CONTROL_INTERROGATE: 
		break; 
	case SERVICE_CONTROL_NETBINDADD: 
		break; 
	case SERVICE_CONTROL_NETBINDDISABLE: 
		break; 
	case SERVICE_CONTROL_NETBINDENABLE: 
		break; 
	case SERVICE_CONTROL_NETBINDREMOVE: 
		break; 
	case SERVICE_CONTROL_PARAMCHANGE: 
		break; 
	*/ 
} 
 
void CServiceApp::PreInitialise(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
			LPSTR lpCmdLine, int nCmdShow) 
{ 
	int nLength = lstrlen(lpCmdLine); 
	m_lpCmdLine = new TCHAR[nLength + 1]; 
	 
	m_hInstance = hInstance, m_hPrevInstance = hPrevInstance, 
	lstrcpy(m_lpCmdLine, lpCmdLine), m_nCmdShow = nCmdShow; 
} 
 
SERVICE_CTRL_CODE CServiceApp::ProcessArguments() 
{ 
	return CServiceApp::DefProcessArguments(m_lpCmdLine); 
} 
 
inline SERVICE_CTRL_CODE CServiceApp::DefProcessArguments(LPSTR lpCmdLine) 
{ 
	if (lstrcmpi(lpCmdLine, _T("install"))==0) 
		return SERVICE_CONTROL_INSTALL; 
 
	if (lstrcmpi(lpCmdLine, _T("uninstall"))==0) 
		return SERVICE_CONTROL_UNINSTALL; 
 
	if (lstrcmpi(lpCmdLine, _T("start"))==0) 
		return SERVICE_CONTROL_START; 
 
	if (lstrcmpi(lpCmdLine, _T("stop"))==0) 
		return SERVICE_CONTROL_STOP; 
 
	if (lstrcmpi(lpCmdLine, _T("pause"))==0) 
		return SERVICE_CONTROL_PAUSE; 
 
	if (lstrcmpi(lpCmdLine, _T("continue"))==0) 
		return SERVICE_CONTROL_CONTINUE; 
 
	return SERVICE_CONTROL_HELP; 
} 
 
inline void CServiceApp::Init() 
{     
	/* In this method, should deal with the Service On Windows 95.*/ 
	LoadString(m_hInstance, IDS_SERVICENAME, m_szServiceName,  
			sizeof(m_szServiceName) / sizeof(TCHAR)); 
 
    // set up the initial service status  
    m_hServiceStatus = NULL; 
    m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
    m_status.dwCurrentState = SERVICE_STOPPED; 
    m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 
    m_status.dwWin32ExitCode = 0; 
    m_status.dwServiceSpecificExitCode = 0; 
    m_status.dwCheckPoint = 0; 
    m_status.dwWaitHint = 0; 
} 
 
BOOL CServiceApp::IsInstalled() 
{ 
	BOOL bResult = FALSE; 
	 
	SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 
	if (hSCM != NULL) 
	{ 
		SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG); 
		if (hService != NULL) 
		{ 
			bResult = TRUE; 
			::CloseServiceHandle(hService); 
		} 
		::CloseServiceHandle(hSCM); 
	} 
	return bResult; 
} 
 
BOOL CServiceApp::Install() 
{ 
	if (IsInstalled()) 
        return TRUE; 
 
	SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 
    if (hSCM == NULL) 
    { 
        MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK); 
        return FALSE; 
    } 
 
    TCHAR szFilePath[_MAX_PATH]; 
	::GetModuleFileName(NULL, szFilePath, _MAX_PATH); 
 
	SC_HANDLE hService = ::CreateService( 
			hSCM,  
			m_szServiceName,  
			m_szServiceName, 
			SERVICE_ALL_ACCESS, 
			SERVICE_WIN32_OWN_PROCESS, 
			SERVICE_AUTO_START, 
			SERVICE_ERROR_NORMAL, 
			szFilePath, 
			NULL, 
			NULL, 
			NULL, 
			NULL, 
			NULL); 
 
	if (hService == NULL) 
	{ 
		::CloseServiceHandle(hSCM); 
		MessageBox(NULL, _T("Couldn't create service"), m_szServiceName, MB_OK); 
		return FALSE; 
	} 
 
    ::CloseServiceHandle(hService); 
    ::CloseServiceHandle(hSCM); 
    return TRUE; 
} 
 
BOOL CServiceApp::Uninstall() 
{ 
	if (!IsInstalled()) 
        return TRUE; 
 
    SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 
 
    if (hSCM == NULL) 
    { 
        MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK); 
        return FALSE; 
    } 
 
    SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_STOP | DELETE); 
 
    if (hService == NULL) 
    { 
        ::CloseServiceHandle(hSCM); 
        MessageBox(NULL, _T("Couldn't open service"), m_szServiceName, MB_OK); 
        return FALSE; 
    } 
     
	SERVICE_STATUS status; 
    ::ControlService(hService, SERVICE_CONTROL_STOP, &status); 
 
    BOOL bDelete = ::DeleteService(hService); 
    ::CloseServiceHandle(hService); 
    ::CloseServiceHandle(hSCM); 
 
    if (bDelete) 
        return TRUE; 
 
    MessageBox(NULL, _T("Service could not be deleted"), m_szServiceName, MB_OK); 
    return FALSE; 
} 
 
void CServiceApp::Start() 
{ 
	SERVICE_TABLE_ENTRY DispatchTable[] =  
    { 
        { m_szServiceName,	_ServiceMain}, 
        { NULL,             NULL} 
    }; 
 
	StartServiceCtrlDispatcher(DispatchTable); 
} 
 
void WINAPI CServiceApp::_ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) 
{ 
	Instance()->ServiceMain(dwArgc, lpszArgv); 
} 
 
inline void CServiceApp::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */) 
{ 
	if (!OnStart()) 
	{ 
		return; 
	} 
 
	m_status.dwCurrentState = SERVICE_START_PENDING; 
    m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler); 
    if (m_hServiceStatus == NULL) 
    { 
        LogEvent(_T("Handler not installed")); 
        return; 
    } 
    SetServiceStatus(SERVICE_START_PENDING); 
 
    m_status.dwWin32ExitCode = S_OK; 
    m_status.dwCheckPoint = 0; 
    m_status.dwWaitHint = 0; 
 
    Run(); 
 
    SetServiceStatus(SERVICE_STOPPED); 
    LogEvent(_T("Service stopped")); 
} 
 
void WINAPI CServiceApp::_Handler(DWORD dwOpcode) 
{ 
    Instance()->Handler(dwOpcode); 
} 
 
inline void CServiceApp::Handler(DWORD dwOpcode) 
{ 
	switch (dwOpcode) 
    { 
    case SERVICE_CONTROL_STOP: 
		OnStop(); 
        break; 
    case SERVICE_CONTROL_PAUSE: 
		OnPause(); 
        break; 
    case SERVICE_CONTROL_CONTINUE: 
		OnContinue(); 
        break; 
    case SERVICE_CONTROL_INTERROGATE: 
        break; 
    case SERVICE_CONTROL_SHUTDOWN: 
		OnShutdown(); 
        break; 
    default: 
        LogEvent(_T("Bad service request")); 
    } 
} 
 
void CServiceApp::LogEvent(LPCTSTR pFormat, ...) 
{ 
    TCHAR   chMsg[256]; 
    HANDLE  hEventSource; 
    LPTSTR  lpszStrings[1]; 
    va_list pArg; 
 
    va_start(pArg, pFormat); 
    _vstprintf(chMsg, pFormat, pArg); 
    va_end(pArg); 
 
    lpszStrings[0] = chMsg; 
 
    hEventSource = RegisterEventSource(NULL, m_szServiceName); 
    if (hEventSource != NULL) 
    { 
        ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 
				0, 0, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL); 
        DeregisterEventSource(hEventSource); 
    } 
} 
 
void CServiceApp::SetServiceStatus(DWORD dwState) 
{ 
    m_status.dwCurrentState = dwState; 
    ::SetServiceStatus(m_hServiceStatus, &m_status); 
} 
 
void CServiceApp::Run() 
{ 
	OnRunning(); 
    Instance()->dwThreadID = GetCurrentThreadId(); 
 
    LogEvent(_T("Service started")); 
    SetServiceStatus(SERVICE_RUNNING); 
 
    MSG msg; 
    while (GetMessage(&msg, 0, 0, 0)) 
        DispatchMessage(&msg); 
} 
 
BOOL CServiceApp::OnStart() 
{ 
	return TRUE; 
} 
 
BOOL CServiceApp::OnRunning() 
{ 
	return TRUE; 
} 
 
inline void CServiceApp::Continue() 
{ 
	BOOL bReturn=TRUE; 
	 
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); 
	if(!hSCM) 
	{ 
		return; 
	} 
 
	SC_HANDLE hService=OpenService(hSCM, m_szServiceName, SERVICE_ALL_ACCESS); 
	if(!hService) 
	{ 
		CloseServiceHandle(hSCM); 
		return; 
	} 
 
	SERVICE_STATUS serviceStatus; 
 
	ControlService(hService, SERVICE_CONTROL_CONTINUE, &serviceStatus); 
 
	WaitForServiceState(hService, SERVICE_RUNNING, &serviceStatus, WAIT_TIME_FOR_SERVICE); 
 
	CloseServiceHandle(hService); 
	CloseServiceHandle(hSCM); 
			 
	return; 
} 
 
BOOL CServiceApp::OnContinue() 
{ 
	return TRUE; 
} 
 
inline void CServiceApp::Pause() 
{ 
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); 
	if(!hSCM) 
	{ 
		return; 
	} 
 
	SC_HANDLE hService=OpenService(hSCM, m_szServiceName, SERVICE_ALL_ACCESS); 
	if(!hService) 
	{ 
		CloseServiceHandle(hSCM); 
		return; 
	} 
 
	SERVICE_STATUS serviceStatus; 
 
	ControlService(hService, SERVICE_CONTROL_PAUSE, &serviceStatus); 
 
	WaitForServiceState(hService, SERVICE_PAUSED,  
			&serviceStatus, WAIT_TIME_FOR_SERVICE); 
 
	CloseServiceHandle(hService); 
	CloseServiceHandle(hSCM); 
 
	return; 
} 
 
BOOL CServiceApp::OnPause() 
{ 
	return TRUE; 
} 
 
inline void CServiceApp::Shutdown() 
{ 
	Stop(); 
} 
 
BOOL CServiceApp::OnShutdown() 
{ 
 
	return OnStop(); 
} 
 
inline void CServiceApp::Stop() 
{ 
	BOOL bResult = TRUE; 
	 
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); 
	if(!hSCM){ 
		return; 
	} 
 
	SC_HANDLE hService=OpenService(hSCM, m_szServiceName, SERVICE_ALL_ACCESS); 
	if(!hService){ 
		CloseServiceHandle(hSCM); 
		return; 
	}	 
 
	SERVICE_STATUS serviceStatus; 
 
	ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus); 
	 
	WaitForServiceState(hService, SERVICE_STOPPED, 
			&serviceStatus, WAIT_TIME_FOR_SERVICE); 
 
	CloseServiceHandle(hService); 
	CloseServiceHandle(hSCM); 
	 
	return; 
} 
 
BOOL CServiceApp::OnStop() 
{ 
	SetServiceStatus(SERVICE_STOP_PENDING); 
    PostThreadMessage(dwThreadID, WM_QUIT, 0, 0); 
	return TRUE; 
} 
 
void CServiceApp::Help() 
{ 
	ShowHelpMessage(); 
} 
 
inline void CServiceApp::ShowHelpMessage() 
{ 
	MessageBox(NULL, 
			_T("DYLockMessageService [ install | uninstall | start | stop | pause | continue ]\n\n") 
			_T("install\t: service install\n") 
			_T("uninstall\t: service uninstall\n") 
			_T("start\t: service start\n") 
			_T("stop\t: service stop\n") 
			_T("pause\t: service pause\n") 
			_T("continue\t: service continue\n"), 
			m_szServiceName, 
			MB_OK); 
} 
 
BOOL CServiceApp::WaitForServiceState(SC_HANDLE hService,  
		SERVICE_CTRL_CODE dwDesiredState,  
		SERVICE_STATUS* lpServiceStatus, 
		DWORD dwMilliseconds) 
{ 
 
	BOOL  fServiceOk = TRUE; 
	BOOL  fFirstTime = TRUE; // Don't compare state/checkpoint the first time 
	DWORD dwLastState = 0, dwLastCheckPoint = 0; 
	DWORD dwTimeout = GetTickCount() + dwMilliseconds; 
 
	// Loop until service reaches desired state, error occurs, or timeout 
	for (;;) { 
		// Get current state of service 
		fServiceOk = ::QueryServiceStatus(hService, lpServiceStatus); 
 
		// If we can't query the service, we're done 
		if (!fServiceOk) break; 
 
		// If the service reaches the desired state, we're done 
		if (lpServiceStatus->dwCurrentState == dwDesiredState) 
			break; 
 
		// If timeout, we're done 
		if ((dwMilliseconds != INFINITE) && (dwTimeout < GetTickCount())) 
		{ 
			fServiceOk = FALSE; 
			SetLastError(ERROR_TIMEOUT); 
			break; 
		} 
 
		// If first time, save service's state/checkpoint 
		if (fFirstTime) 
		{ 
			dwLastState      = lpServiceStatus->dwCurrentState; 
			dwLastCheckPoint = lpServiceStatus->dwCheckPoint; 
			fFirstTime       = FALSE; 
		} 
		else 
		{ 
			// If not first time and state changed, save state/checkpoint 
			if (dwLastState != lpServiceStatus->dwCurrentState) 
			{ 
				dwLastState      = lpServiceStatus->dwCurrentState; 
				dwLastCheckPoint = lpServiceStatus->dwCheckPoint; 
			} 
			else 
			{ 
				// State hasn't changed; make sure checkpoint isn't decreasing 
				if (lpServiceStatus->dwCheckPoint >= dwLastCheckPoint) 
				{ 
					// Good checkpoint; save it 
					dwLastCheckPoint = lpServiceStatus->dwCheckPoint; 
				} else 
				{ 
					// Bad checkpoint, service failed, we're done! 
					fServiceOk = FALSE;  
					break; 
				} 
			} 
		} 
 
		// We're not done; wait the specified period of time 
		// Poll 1/10 of the wait hint 
		DWORD dwWaitHint = lpServiceStatus->dwWaitHint / 10; 
		// At most once a second 
		if (dwWaitHint <  1000) dwWaitHint = 1000; 
		// At least every 10 seconds 
		if (dwWaitHint > 10000) dwWaitHint = 10000; 
		Sleep(dwWaitHint); 
	} 
 
	// Note: The last SERVICE_STATUS is returned to the caller so 
	// that the caller can check the service state and error codes 
	return(fServiceOk); 
}