|
|
/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/
/*
service.cpp Calls to start and stop services. FILE HISTORY: */ #include "stdafx.h"
#include "DynamLnk.h"
#include "cluster.h"
DynamicDLL g_NetApiDLL( _T("NETAPI32.DLL"), g_apchNetApiFunctionNames );
/*---------------------------------------------------------------------------
IsComputerNT Checks to see if the given computer is running NT Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSIsComputerNT ( LPCTSTR pszComputer, BOOL * bIsNT ) { DWORD err = 0; BYTE * pbBuffer; *bIsNT = FALSE;
if ( !g_NetApiDLL.LoadFunctionPointers() ) return err;
err = ((NETSERVERGETINFO) g_NetApiDLL[NET_API_NET_SERVER_GET_INFO]) ( (LPTSTR) pszComputer, 101, &pbBuffer );
if (err == NERR_Success) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_LEVEL
// ERROR_INVALID_PARAMETER
// ERROR_NOT_ENOUGH_MEMORY
//
SERVER_INFO_101 * pServerInfo = (SERVER_INFO_101 *) pbBuffer;
if ( (pServerInfo->sv101_type & SV_TYPE_NT) ) { *bIsNT = TRUE; }
err = ERROR_SUCCESS; //Translate the NERR code to a winerror code
}
return err; }
/*---------------------------------------------------------------------------
IsNTServer Checks to see if the given computer is running NTS Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSIsNTServer ( LPCTSTR pszComputer, BOOL * bIsNTS ) { DWORD err = 0; BYTE * pbBuffer; *bIsNTS = FALSE;
if ( !g_NetApiDLL.LoadFunctionPointers() ) return err;
err = ((NETSERVERGETINFO) g_NetApiDLL[NET_API_NET_SERVER_GET_INFO]) ( (LPTSTR) pszComputer, 101, &pbBuffer );
if (err == NERR_Success) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_LEVEL
// ERROR_INVALID_PARAMETER
// ERROR_NOT_ENOUGH_MEMORY
//
SERVER_INFO_101 * pServerInfo = (SERVER_INFO_101 *) pbBuffer;
if ( (pServerInfo->sv101_type & SV_TYPE_SERVER_NT) || (pServerInfo->sv101_type & SV_TYPE_DOMAIN_CTRL) || (pServerInfo->sv101_type & SV_TYPE_DOMAIN_BAKCTRL) ) { *bIsNTS = TRUE; }
err = ERROR_SUCCESS; //Translate the NERR code to a winerror code
}
return err; }
/*---------------------------------------------------------------------------
TFSIsServiceRunning Checks to see if the given service is running on a machine Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSIsServiceRunning ( LPCTSTR pszComputer, LPCTSTR pszServiceName, BOOL * fIsRunning ) { DWORD err = 0; DWORD dwStatus;
*fIsRunning = FALSE;
err = TFSGetServiceStatus(pszComputer, pszServiceName, &dwStatus, NULL);
if (err == 0) *fIsRunning = (BOOL)(dwStatus & SERVICE_RUNNING);
return err; }
/*!--------------------------------------------------------------------------
TFSGetServiceStatus Returns ERROR_SUCCESS on API success. Returns an error code otherwise.
pszComputer - name of the computer to attach to. pszServiceName - name of the service to check. pdwServiceStatus - returns the status of the service. pdwErrorCode - returns the error code returned from the service (this is NOT the error code from the API itself). This may be NULL. Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSGetServiceStatus ( LPCWSTR pszComputer, LPCWSTR pszServiceName, DWORD * pdwServiceStatus, OPTIONAL DWORD * pdwErrorCode ) { DWORD err = 0; SC_HANDLE hScManager;
Assert(pdwServiceStatus);
*pdwServiceStatus = 0;
if (pdwErrorCode) *pdwErrorCode = 0;
//
// Find out if the service is running on the given machine
//
hScManager = ::OpenSCManager(pszComputer, NULL, GENERIC_READ); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
return GetLastError(); } SC_HANDLE hService = ::OpenService(hScManager, pszServiceName, SERVICE_QUERY_STATUS); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError();
::CloseServiceHandle(hScManager); return err; }
SERVICE_STATUS serviceStatus; if (!::QueryServiceStatus(hService, &serviceStatus)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
//
err = GetLastError();
::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; }
*pdwServiceStatus = serviceStatus.dwCurrentState;
// Also return the error code
if (pdwErrorCode) { if (serviceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR) *pdwErrorCode = serviceStatus.dwServiceSpecificExitCode; else *pdwErrorCode = serviceStatus.dwWin32ExitCode; }
::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; }
/*---------------------------------------------------------------------------
StartService Starts the given service on a machine Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSStartService ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc ) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
DWORD err = 0; err = StartSCMService(pszComputer, pszServiceName, pszServiceDesc); return err; }
/*---------------------------------------------------------------------------
StartServiceEx Starts the given service on a machine, cluster aware Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSStartServiceEx ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszClusterResourceType, LPCTSTR pszServiceDesc ) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
DWORD err = 0; if (FIsComputerInRunningCluster(pszComputer)) { err = ControlClusterService(pszComputer, pszClusterResourceType, pszServiceDesc, TRUE); } else { err = StartSCMService(pszComputer, pszServiceName, pszServiceDesc); } return err; }
/*---------------------------------------------------------------------------
StopService Stops the given service on a machine Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSStopService ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc ) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
DWORD err = 0;
err = StopSCMService(pszComputer, pszServiceName, pszServiceDesc);
return err; }
/*---------------------------------------------------------------------------
StopServiceEx Stops the given service on a machine, cluster aware Author: EricDav ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) TFSStopServiceEx ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszClusterResourceType, LPCTSTR pszServiceDesc ) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
DWORD err = 0;
if (FIsComputerInRunningCluster(pszComputer)) { err = ControlClusterService(pszComputer, pszClusterResourceType, pszServiceDesc, FALSE); } else { err = StopSCMService(pszComputer, pszServiceName, pszServiceDesc); }
return err; }
TFSCORE_API(DWORD) TFSGetServiceStartType(LPCWSTR pszComputer, LPCWSTR pszServiceName, DWORD *pdwStartType) { DWORD err = 0; SC_HANDLE hScManager = 0; SC_HANDLE hService = 0; HRESULT hr = hrOK; BOOL fReturn = FALSE; LPQUERY_SERVICE_CONFIG pqsConfig = NULL; DWORD cbNeeded = sizeof( QUERY_SERVICE_CONFIG ); DWORD cbSize;
//
// Find out if the service is running on the given machine
//
hScManager = ::OpenSCManager(pszComputer, NULL, GENERIC_READ); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
err = GetLastError(); goto Exit; } hService = ::OpenService(hScManager, pszServiceName, SERVICE_QUERY_CONFIG); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError(); goto Exit; }
COM_PROTECT_TRY { *pdwStartType = 0; // loop, allocating the needed size
do { delete [] (PBYTE)pqsConfig; pqsConfig = (LPQUERY_SERVICE_CONFIG) new BYTE[cbNeeded]; cbSize = cbNeeded; fReturn = ::QueryServiceConfig( hService, pqsConfig, cbSize, &cbNeeded ); *pdwStartType = pqsConfig->dwStartType; delete [] (PBYTE)pqsConfig; pqsConfig = NULL; if (!fReturn && (cbNeeded == cbSize)) { // error
*pdwStartType = 0; err = GetLastError(); goto Error; } } while (!fReturn && (cbNeeded != cbSize));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH;
if (!FHrSucceeded(hr)) { // The only time we should get here (with an hr is for outofmemory)
err = ERROR_OUTOFMEMORY; } Exit: if (err != 0) { *pdwStartType = 0; } ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; }
TFSCORE_API(DWORD) TFSSetServiceStartType(LPCWSTR pszComputer, LPCWSTR pszServiceName, DWORD dwStartType) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
DWORD err = 0; SC_HANDLE hScManager;
//
// Open the SCManager so that we can try to stop the service
//
hScManager = ::OpenSCManager(pszComputer, NULL, SC_MANAGER_ALL_ACCESS); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
return GetLastError(); } SC_HANDLE hService = ::OpenService(hScManager, pszServiceName, SERVICE_STOP | SERVICE_ALL_ACCESS); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError(); ::CloseServiceHandle(hScManager); return err; }
if (!::ChangeServiceConfig( hService, SERVICE_NO_CHANGE, dwStartType, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_CIRCULAR_DEPENDENCY
// ERROR_DUP_NAME
// ERROR_INVALID_HANDLE
// ERROR_INVALID_PARAMETER
// ERROR_INVALID_SERVICE_ACCOUNT
// ERROR_SERVICE_MARKED_FOR_DELETE
//
err = ::GetLastError(); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; } ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; }
DWORD StartSCMService ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc ) { DWORD err = 0; SC_HANDLE hScManager;
//
// Open the SCManager so that we can try to start the service
//
hScManager = ::OpenSCManager(pszComputer, NULL, SC_MANAGER_CONNECT ); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
return GetLastError(); } SC_HANDLE hService = ::OpenService(hScManager, pszServiceName, SERVICE_START | SERVICE_QUERY_STATUS); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError(); ::CloseServiceHandle(hScManager); return err; }
SERVICE_STATUS serviceStatus; if (!::QueryServiceStatus(hService, &serviceStatus)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
//
err = GetLastError(); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; }
// If the service is in a start pending, do not do anything
if (serviceStatus.dwCurrentState == SERVICE_START_PENDING) { ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
err = ERROR_SERVICE_ALREADY_RUNNING;
return err; } if (!::StartService(hService, NULL, NULL)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_PATH_NOT_FOUND
// ERROR_SERVICE_ALREADY_RUNNING
// ERROR_SERVICE_DATABASE_LOCKED
// ERROR_SERVICE_DEPENDENCY_DELETED
// ERROR_SERVICE_DEPENDENCY_FAIL
// ERROR_SERVICE_DISABLED
// ERROR_SERVICE_LOGON_FAILED
// ERROR_SERVICE_MARKED_FOR_DELETE
// ERROR_SERVICE_NO_THREAD
// ERROR_SERVICE_REQUEST_TIMEOUT
//
err = GetLastError(); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; } //
// Put up the dialog with the funky spinning thing to
// let the user know that something is happening
//
CServiceCtrlDlg dlgServiceCtrl(hService, pszComputer, pszServiceDesc, TRUE);
dlgServiceCtrl.DoModal(); err = dlgServiceCtrl.m_dwErr;
//
// Everything started ok, close up and get going
//
::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; }
DWORD StopSCMService ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc ) { DWORD err = 0; SC_HANDLE hScManager; LPENUM_SERVICE_STATUS lpScStatus = NULL; DWORD dwNumService = 0, dwSize = 0, dwSizeReqd = 0, i = 0; BOOL bRet;
//
// Open the SCManager so that we can try to stop the service
//
hScManager = ::OpenSCManager(pszComputer, NULL, SC_MANAGER_CONNECT ); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
return GetLastError(); } SC_HANDLE hService = ::OpenService( hScManager, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS ); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError(); ::CloseServiceHandle(hScManager); return err; }
//
// Stop all dependent services that are currently active.
// Since the number of services is unknown (up front),
// EnumDependentServices is called atleast twice (first
// to get the size of buffer, and second to get the
// list of services). If the number of services changes
// between the calls, then EnumDependentServices is called
// one more time (as per the logic, i < 3).
//
do { //
// Enumerate all dependent services
//
bRet = ::EnumDependentServices( hService, SERVICE_ACTIVE, lpScStatus, dwSize, &dwSizeReqd, &dwNumService ); if (!bRet && (GetLastError() == ERROR_MORE_DATA)) { //
// Not enough buffer to hold the dependent service list,
// delete previous allocation (if any) and allocate new
// buffer of requiste size.
//
if (lpScStatus) { delete lpScStatus; lpScStatus = NULL; }
lpScStatus = reinterpret_cast<LPENUM_SERVICE_STATUS> (new BYTE[2 * dwSizeReqd]); if (lpScStatus == NULL) { //
// allocation failed, forget about stopping dependent
// services
//
break; }
//
// Increment attempt count. At most 3 attempts will be made
// to get the list of dependent services
//
dwSize = 2 * dwSizeReqd; dwSizeReqd = 0; i++; }
else { //
// Success or failure for other than insufficent buffer reason
//
break; } } while( i < 3 );
//
// if dependent service were successfully enumerated
// stop them all
//
if (bRet) { for (i = 0; i < dwNumService; i++) { StopSCMService( pszComputer, lpScStatus[i].lpServiceName, lpScStatus[i].lpDisplayName ); } }
if (lpScStatus) { delete lpScStatus; lpScStatus = NULL; }
//
// Stop the service, now that all dependents have been stopped
//
SERVICE_STATUS serviceStatus; if (!::ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DEPENDENT_SERVICES_RUNNING
// ERROR_INVALID_SERVICE_CONTROL
// ERROR_SERVICE_CANNOT_ACCEPT_CTRL
// ERROR_SERVICE_NOT_ACTIVE
// ERROR_SERVICE_REQUEST_TIMEOUT
//
err = GetLastError(); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; }
if ( serviceStatus.dwCurrentState != SERVICE_STOPPED ) { //
// Put up the dialog with the funky spinning thing to
// let the user know that something is happening
//
CServiceCtrlDlg dlgServiceCtrl(hService, pszComputer, pszServiceDesc, FALSE);
dlgServiceCtrl.DoModal(); err = dlgServiceCtrl.m_dwErr; }
//
// Everything stopped ok, close up and get going
//
::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; }
TFSCORE_API(DWORD) TFSPauseService(LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc) { return PauseSCMService(pszComputer, pszServiceName, pszServiceDesc); }
TFSCORE_API(DWORD) TFSResumeService(LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc) { return ResumeSCMService(pszComputer, pszServiceName, pszServiceDesc); }
DWORD PauseSCMService ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc ) { DWORD err = 0; SC_HANDLE hScManager;
//
// Open the SCManager so that we can try to stop the service
//
hScManager = ::OpenSCManager(pszComputer, NULL, SC_MANAGER_CONNECT ); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
return GetLastError(); } SC_HANDLE hService = ::OpenService(hScManager, pszServiceName, SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError(); ::CloseServiceHandle(hScManager); return err; }
SERVICE_STATUS serviceStatus; if (!::ControlService(hService, SERVICE_CONTROL_PAUSE, &serviceStatus)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DEPENDENT_SERVICES_RUNNING
// ERROR_INVALID_SERVICE_CONTROL
// ERROR_SERVICE_CANNOT_ACCEPT_CTRL
// ERROR_SERVICE_NOT_ACTIVE
// ERROR_SERVICE_REQUEST_TIMEOUT
//
err = GetLastError(); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; }
#if 0
if ( serviceStatus.dwCurrentState != SERVICE_STOPPED ) { //
// Put up the dialog with the funky spinning thing to
// let the user know that something is happening
//
CServiceCtrlDlg dlgServiceCtrl(hService, pszComputer, pszServiceDesc, FALSE);
dlgServiceCtrl.DoModal(); err = dlgServiceCtrl.m_dwErr; } #endif
//
// Everything stopped ok, close up and get going
//
::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; }
DWORD ResumeSCMService ( LPCTSTR pszComputer, LPCTSTR pszServiceName, LPCTSTR pszServiceDesc ) { DWORD err = 0; SC_HANDLE hScManager;
//
// Open the SCManager so that we can try to stop the service
//
hScManager = ::OpenSCManager(pszComputer, NULL, SC_MANAGER_CONNECT ); if (hScManager == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DATABASE_DOES_NOT_EXIST
// ERROR_INVALID_PARAMETER
//
return GetLastError(); } SC_HANDLE hService = ::OpenService(hScManager, pszServiceName, SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS); if (hService == NULL) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_INVALID_HANDLE
// ERROR_INVALID_NAME
// ERROR_SERVICE_DOES_NOT_EXIST
//
err = GetLastError(); ::CloseServiceHandle(hScManager); return err; }
SERVICE_STATUS serviceStatus; if (!::ControlService(hService, SERVICE_CONTROL_CONTINUE, &serviceStatus)) { //
// Possible Errors:
// ERROR_ACCESS_DENIED
// ERROR_DEPENDENT_SERVICES_RUNNING
// ERROR_INVALID_SERVICE_CONTROL
// ERROR_SERVICE_CANNOT_ACCEPT_CTRL
// ERROR_SERVICE_NOT_ACTIVE
// ERROR_SERVICE_REQUEST_TIMEOUT
//
err = GetLastError(); ::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager); return err; } #if 0
if ( serviceStatus.dwCurrentState != SERVICE_STOPPED ) { //
// Put up the dialog with the funky spinning thing to
// let the user know that something is happening
//
CServiceCtrlDlg dlgServiceCtrl(hService, pszComputer, pszServiceDesc, FALSE);
dlgServiceCtrl.DoModal(); err = dlgServiceCtrl.m_dwErr; } #endif
//
// Everything stopped ok, close up and get going
//
::CloseServiceHandle(hService); ::CloseServiceHandle(hScManager);
return err; }
|