|
|
/////////////////////////////////////////////////////////////////////
//
// Progress.cpp
//
// Progress dialog to Start, Stop, Pause, Resume and Restart a service.
//
// IMPLEMENTATION
// Since an operation (ie, Start, Stop, Pause, Resume or Restart) may take
// a while, a thread is created to do the actual work while a dialog
// is displayed to the user.
// 0. Allocate CServiceControlProgress object on the heap
// 1. Create a thread in suspended mode.
// 2. Create the dialog.
// 3. Dialog creates a timer to update the progress bar.
// 4. Dialog resumes the thread.
// 5. Thread opens the service and perform the requested operation(s).
// 6. Dialog updates UI using its timer.
// 7. Thread updates dialog UI as well.
// 8. Thread waits until the dialog is dismissed. Dialog can be
// dismissed for any of the following event:
// a) Operation completed successfully.
// b) User hit cancel button.
// c) An unexpected error occured.
// d) Operation times out.
// 9 Thread deletes CServiceControlProgress object.
//
// HISTORY
// 03-Oct-95 t-danmo Creation of (sysmgmt\dsui\services\progress.cxx)
// 30-Sep-96 t-danmo Renamed and adapted to MMC.
// 14-May-97 t-danm Fully implemented the "Restart" feature.
//
#include "stdafx.h"
#include "progress.h"
/////////////////////////////////////////////////////////////////////////////
// This array represent the expected state of the service
// after carrying action, start, stop, pause or resume.
//
// To be compared SERVICE_STATUS.dwCurrentState.
//
const DWORD rgdwExpectedServiceStatus[4] = { SERVICE_RUNNING, // Service should be running after a 'start'
SERVICE_STOPPED, // Service should be stopped after a 'stop'
SERVICE_PAUSED, // Service should be paused after a 'pause'
SERVICE_RUNNING, // Service should be running after a 'resume'
};
/////////////////////////////////////////////////////////////////////////////
CServiceControlProgress::CServiceControlProgress() { // Using ZeroMemory() is safe as long as CServiceControlProgress
// is not derived from any other object and does not contains
// any objects with constructors.
::ZeroMemory(this, sizeof(*this)); }
/////////////////////////////////////////////////////////////////////////////
CServiceControlProgress::~CServiceControlProgress() { delete m_pargDependentServicesT; delete m_pargServiceStop; }
/////////////////////////////////////////////////////////////////////////////
// M_FInit()
//
// Initialize the object.
// - Copy all input parameters
// - Load the clock bitmap(s)
// Return TRUE if successful, otherwise FALSE
//
BOOL CServiceControlProgress::M_FInit( HWND hwndParent, // IN: Parent of the dialog
SC_HANDLE hScManager, // IN: Handle to service control manager database
LPCTSTR pszMachineName, // IN: Machine name to display to the user
LPCTSTR pszServiceName, // IN: Name of the service
LPCTSTR pszServiceDisplayName) // IN: Display name of the service
{ Assert(IsWindow(hwndParent)); Assert(hScManager != NULL); Assert(pszServiceName != NULL); Assert(pszServiceDisplayName != NULL);
m_hWndParent = hwndParent; m_hScManager = hScManager; lstrcpy(OUT m_szUiMachineName, (pszMachineName && pszMachineName[0]) ? pszMachineName : (LPCTSTR)g_strLocalMachine); lstrcpy(OUT m_szServiceName, pszServiceName); lstrcpy(OUT m_szServiceDisplayName, pszServiceDisplayName);
return TRUE; } // M_FInit()
/////////////////////////////////////////////////////////////////////
// M_FDlgStopDependentServices()
//
// Check if the services has dependent services that must be stopped
// before stopping the current service.
//
// If there are any dependent services, the function will display
// a dialog asking the user to confirm he/she wants also to stop
// all the dependent services.
//
// This function return FALSE ONLY IF the user click on the cancel button
// otherwise TRUE. If there are no dependent services, or an error occurs
// while reading dependent services, the function will return TRUE.
//
BOOL CServiceControlProgress::M_FDlgStopDependentServices() { Assert(m_hScManager != NULL);
SC_HANDLE hService = NULL; BOOL fSuccess = TRUE; DWORD cbBytesNeeded = 0; DWORD dwServicesReturned = 0;
m_cDependentServices = 0; // So far we have no dependent services
delete m_pargServiceStop; m_pargServiceStop = NULL;
{ AFX_MANAGE_STATE(AfxGetStaticModuleState( )); // required for CWaitCursor
CWaitCursor wait; hService = ::OpenService(m_hScManager, m_szServiceName, SERVICE_ENUMERATE_DEPENDENTS); } if (hService == NULL) { TRACE1("M_FDlgStopDependentServices() - Unable to enumerate service dependencies for service %s.\n", m_szServiceName); goto End; }
// Find out how many bytes are needed to enumerate the dependent services
fSuccess = ::EnumDependentServices( hService, SERVICE_ACTIVE, // Enumerate only the active services
NULL, 0, OUT &cbBytesNeeded, OUT &dwServicesReturned); if (cbBytesNeeded == 0) { // Service does not have any dependencies
goto End; } Assert(fSuccess == FALSE); Report(GetLastError() == ERROR_MORE_DATA); // Error should be 'more data'
Assert(dwServicesReturned == 0); cbBytesNeeded += 1000; // Add extra bytes (just in case)
delete m_pargDependentServicesT; // Free previously allocated memory (if any)
m_pargDependentServicesT = (LPENUM_SERVICE_STATUS) new BYTE[cbBytesNeeded];
// Query the database for the dependent services
fSuccess = ::EnumDependentServices( hService, SERVICE_ACTIVE, // Enumerate only the active services
OUT m_pargDependentServicesT, cbBytesNeeded, OUT IGNORED &cbBytesNeeded, OUT &dwServicesReturned); Report(fSuccess != FALSE); Report(dwServicesReturned > 0); m_cDependentServices = dwServicesReturned; if (m_cDependentServices > 0) { // Allocate an array to hold all the dependent services
m_pargServiceStop = new ENUM_SERVICE_STATUS[m_cDependentServices + 1]; memcpy(OUT m_pargServiceStop, m_pargDependentServicesT, m_cDependentServices * sizeof(ENUM_SERVICE_STATUS)); m_pargServiceStop[m_cDependentServices].lpServiceName = m_szServiceName; m_pargServiceStop[m_cDependentServices].lpDisplayName = m_szServiceDisplayName;
INT_PTR nReturn = ::DialogBoxParam( g_hInstanceSave, MAKEINTRESOURCE(IDD_SERVICE_STOP_DEPENDENCIES), m_hWndParent, (DLGPROC)&S_DlgProcDependentServices, reinterpret_cast<LPARAM>(this)); Report(nReturn != -1); if (0 == nReturn) // user chose Cancel
fSuccess = FALSE; } // if
End: if (NULL != hService) { VERIFY(::CloseServiceHandle(hService)); } return fSuccess; } // M_FDlgStopDependentServices()
/////////////////////////////////////////////////////////////////////
// M_DoExecuteServiceThread()
//
// Run a background thread while a foreground dialog is
// displayed to the user.
// This routine synchronizes the background thread with the main thread.
//
// If an error occurs, the routine will display a message box of the
// error encountered.
//
// Return the error code from GetLastError() if an error occured.
//
APIERR CServiceControlProgress::M_EDoExecuteServiceThread(void * pThreadProc) { Assert(pThreadProc != NULL); Assert(m_hService == NULL); Assert(m_hThread == NULL);
m_hEvent = ::CreateEvent( NULL, FALSE, FALSE, NULL); Report(m_hEvent != NULL);
// Create a thread in suspended mode
m_hThread = ::CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)pThreadProc, this, CREATE_SUSPENDED, NULL); Report(m_hThread != NULL);
// Display the dialog box, the dialog will resume the suspended thread
(void)::DialogBoxParam( g_hInstanceSave, MAKEINTRESOURCE(IDD), m_hWndParent, (DLGPROC)&S_DlgProcControlService, reinterpret_cast<LPARAM>(this));
// Display an error message to the user (if an error occured);
M_ProcessErrorCode(); // Make a copy of the last error code
APIERR dwLastError = m_dwLastError; // Indicate the thread is allowed to terminate and delete the 'this' pointer
VERIFY(SetEvent(m_hEvent)); // 'this' pointer cannot longer be assumed to be valid
return dwLastError; } // M_EDoExecuteServiceThread()
/////////////////////////////////////////////////////////////////////
// M_ProcessErrorCode()
//
// Query the service status one last time to get its exit code,
// examine the content of member m_dwLastError and display an
// error message if an error occured.
//
void CServiceControlProgress::M_ProcessErrorCode() { SERVICE_STATUS ss; ::ZeroMemory( &ss, sizeof(ss) );
if (m_hService != NULL) { // Query the service status again to get its Win32ExitCode
if (!::QueryServiceStatus(m_hService, OUT &ss)) { TRACE3("QueryServiceStatus(%s [hService=%p]) failed. err=%u.\n", m_szServiceName, m_hService, GetLastError()); m_dwLastError = GetLastError(); } else { if (ss.dwWin32ExitCode != ERROR_SUCCESS) m_dwLastError = ss.dwWin32ExitCode; } } // if
APIERR dwLastError = m_dwLastError; UINT uIdString = IDS_MSG_sss_UNABLE_TO_START_SERVICE; TCHAR szMessageExtra[512]; szMessageExtra[0] = _T('\0'); switch (dwLastError) { case ERROR_SUCCESS: if (ss.dwCurrentState == rgdwExpectedServiceStatus[m_iServiceAction]) { // The service status is consistent with the expected service status
uIdString = 0; } else { // We got a problem here, the service did not return an error
// but did not behave as expected
//
// JonN 12/3/99 418111 If the service stopped automatically,
// don't make such a fuss
//
if (SERVICE_RUNNING == rgdwExpectedServiceStatus[m_iServiceAction] && ( ss.dwCurrentState == SERVICE_STOPPED || ss.dwCurrentState == SERVICE_STOP_PENDING)) { uIdString = IDS_MSG_sss_SERVICE_STOPPED_AUTOMATICALLY; break; } ::LoadString(g_hInstanceSave, IDS_MSG_INTERNAL_ERROR, OUT szMessageExtra, LENGTH(szMessageExtra)); Assert(lstrlen(szMessageExtra) > 0); } break;
case errUserCancelStopDependentServices: case errUserAbort: // Do not report this 'error' to the user
uIdString = 0; break;
case ERROR_SERVICE_SPECIFIC_ERROR: dwLastError = ss.dwServiceSpecificExitCode; uIdString = IDS_MSG_ssd_SERVSPECIFIC_START_SERVICE; // 341363 JonN 6/1/99: no point in loading this string as if it were
// a Win32 error
//::LoadString(g_hInstanceSave, IDS_MSG_SPECIFIC_ERROR,
// OUT szMessageExtra, LENGTH(szMessageExtra));
// Assert(lstrlen(szMessageExtra) > 0);
break; } // switch
if (uIdString != 0) { if (uIdString == IDS_MSG_ssd_SERVSPECIFIC_START_SERVICE) { DoServicesErrMsgBox( ::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, 0, uIdString + m_iServiceAction, m_szServiceDisplayName, m_szUiMachineName, dwLastError); } else { DoServicesErrMsgBox( ::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwLastError, uIdString + m_iServiceAction, m_szServiceDisplayName, m_szUiMachineName, szMessageExtra); } } } // M_ProcessErrorCode()
/////////////////////////////////////////////////////////////////////
// M_DoThreadCleanup()
//
// Routine that synchronize the background thread with the dialog and
// perform cleanup tasks.
// This routine delete the 'this' pointer when done.
//
void CServiceControlProgress::M_DoThreadCleanup() { TRACE1("CServiceControlProgress::M_DoThreadCleanup() - Waiting for event 0x%p...\n", m_hEvent); Assert(m_hEvent != NULL); // Wait for the the dialog box to be gone
::WaitForSingleObject(m_hEvent, INFINITE); VERIFY(::CloseHandle(m_hEvent));
// Close the service handle opened by the thread
if (m_hService != NULL) { if (!::CloseServiceHandle(m_hService)) { TRACE3("CloseServiceHandle(%s [hService=%p]) failed. err=%u.\n", m_szServiceName, m_hService, GetLastError()); } } // if
VERIFY(::CloseHandle(m_hThread)); delete this; // We are done with the object
} // M_DoThreadCleanup()
/////////////////////////////////////////////////////////////////////
// M_EControlService()
//
// This function is just there to initialize variables to
// perform a stop, pause, resume or restart operation.
//
APIERR CServiceControlProgress::M_EControlService(DWORD dwControlCode) { Assert(m_fRestartService == FALSE);
APIERR err = 0; m_dwControlCode = dwControlCode; switch (dwControlCode) { default: Assert(FALSE && "CServiceControlProgress::M_EControlService() - Unknown control code."); break;
case SERVICE_CONTROL_RESTART: m_dwControlCode = SERVICE_CONTROL_STOP; m_fRestartService = TRUE; // Fall Through //
case SERVICE_CONTROL_STOP: m_dwDesiredAccess = SERVICE_STOP | SERVICE_QUERY_STATUS; m_dwQueryState = SERVICE_STOP_PENDING; m_iServiceAction = iServiceActionStop; if (!M_FDlgStopDependentServices()) { // User changed its mind by pressing the 'Cancel' button
err = errUserCancelStopDependentServices; } else { // Stop the services (including dependent services)
err = M_EDoExecuteServiceThread(S_ThreadProcStopService); } break;
case SERVICE_CONTROL_PAUSE: m_dwDesiredAccess = SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS; m_dwQueryState = SERVICE_PAUSE_PENDING; m_iServiceAction = iServiceActionPause; err = M_EDoExecuteServiceThread(S_ThreadProcPauseResumeService); break;
case SERVICE_CONTROL_CONTINUE: m_dwDesiredAccess = SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS; m_dwQueryState = SERVICE_CONTINUE_PENDING; m_iServiceAction = iServiceActionResume; err = M_EDoExecuteServiceThread(S_ThreadProcPauseResumeService); break; } // switch
return err; } // M_EControlService()
/////////////////////////////////////////////////////////////////////
// M_QueryCurrentServiceState()
//
// Simply call the API ::QueryServiceStatus() and return dwCurrentState
// of the SERVICE_STATUS structure.
//
// RETURNS
// Function return the current state of a service:
// SERVICE_STOPPED The service is not running.
// SERVICE_START_PENDING The service is starting.
// SERVICE_STOP_PENDING The service is stopping.
// SERVICE_RUNNING The service is running.
// SERVICE_CONTINUE_PENDING The service continue is pending.
// SERVICE_PAUSE_PENDING The service pause is pending.
// SERVICE_PAUSED The service is paused.
//
// If an error occurs, the function will return SERVICE_STOPPED.
//
DWORD CServiceControlProgress::M_QueryCurrentServiceState() { BOOL fRet; SERVICE_STATUS ss;
Assert(m_hService != NULL); if (m_hService == NULL) // Just in case
{ return SERVICE_STOPPED; } // Query the service status
fRet = ::QueryServiceStatus(m_hService, OUT &ss); if (!fRet) { TRACE2("CServiceControlProgress::M_QueryCurrentServiceState() - ::QueryServiceStatus(%s) failed. err=%u\n", m_szServiceName, GetLastError()); Assert(GetLastError() != ERROR_SUCCESS); m_dwLastError = GetLastError(); return SERVICE_STOPPED; } return ss.dwCurrentState; } // M_QueryCurrentServiceState()
/////////////////////////////////////////////////////////////////////
// Query the service database to get the friendly name and
// display it into the dialog.
//
void CServiceControlProgress::M_UpdateDialogUI(LPCTSTR pszDisplayName) { Assert(pszDisplayName != NULL); if (m_hctlActionMsg == NULL || m_hctlServiceNameMsg == NULL) return; Assert(IsWindow(m_hctlActionMsg) && IsWindow(m_hctlServiceNameMsg)); SetWindowTextPrintf( m_hctlActionMsg, IDS_SVC_ss_SERVICE_STARTING + m_iServiceAction, pszDisplayName, m_szUiMachineName); SetWindowText( m_hctlServiceNameMsg, pszDisplayName ); } // M_UpdateDialogUI()
/////////////////////////////////////////////////////////////////////
// Routine to iterate through the dependent services to stop.
//
// Return the the service name to stop, increment the 'pointer' to the
// next service. The routine returns FALSE if there are no remaining
// services to stop.
//
// REMARKS
// This routine is also used to restart dependent services.
//
BOOL CServiceControlProgress::M_FGetNextService( OUT LPCTSTR * ppszServiceName, OUT LPCTSTR * ppszDisplayName) { Assert(ppszServiceName != NULL); Assert(ppszDisplayName != NULL); Assert(m_iServiceAction == iServiceActionStop || m_iServiceAction == iServiceActionStart);
int iDependentService = m_iDependentServiceIter; if (m_iServiceAction == iServiceActionStop) m_iDependentServiceIter++; else m_iDependentServiceIter--; if (m_pargServiceStop != NULL && iDependentService >= 0 && iDependentService <= m_cDependentServices) { *ppszServiceName = m_pargServiceStop[iDependentService].lpServiceName; *ppszDisplayName = m_pargServiceStop[iDependentService].lpDisplayName; } else { *ppszServiceName = m_szServiceName; *ppszDisplayName = m_szServiceDisplayName; } return (m_iDependentServiceIter >= 0 && m_iDependentServiceIter <= m_cDependentServices); } // M_FGetNextService()
/////////////////////////////////////////////////////////////////////
// Thread to start one (or more) services.
DWORD CServiceControlProgress::S_ThreadProcStartService(CServiceControlProgress * pThis) { BOOL fSuccess = FALSE; SC_HANDLE hService;
Assert(pThis != NULL); Assert(pThis->m_hScManager != NULL); Assert(pThis->m_hService == NULL); Endorse(pThis->m_fPulseEvent == TRUE); // We are starting multiple services
Endorse(pThis->m_fPulseEvent == FALSE); // Wa are starting only one service
if (pThis->m_dwLastError != ERROR_SUCCESS) { // If there is already an error, it is because we attempted to previously stop a service
Assert(pThis->m_fRestartService == TRUE); goto Done; }
while (TRUE) { LPCTSTR pszServiceName; LPCTSTR pszServiceDisplayName; UINT cServicesRemaining = pThis->M_FGetNextService( OUT &pszServiceName, OUT &pszServiceDisplayName);
pThis->M_UpdateDialogUI(pszServiceDisplayName); // Sleep(5000); // Debug
// Open service to allow a 'start' operation
hService = ::OpenService( pThis->m_hScManager, pszServiceName, SERVICE_START | SERVICE_QUERY_STATUS); if (hService == NULL) { pThis->m_dwLastError = GetLastError(); TRACE2("ERR: S_ThreadProcStartService(): Unable to open service %s to start. err=%u.\n", pszServiceName, pThis->m_dwLastError); break; } fSuccess = ::StartService( hService, pThis->m_dwNumServiceArgs, pThis->m_lpServiceArgVectors); if (!fSuccess) { APIERR err = GetLastError(); if (ERROR_SERVICE_ALREADY_RUNNING != err) { pThis->m_dwLastError = err; TRACE2("ERR: S_ThreadProcStartService(): StartService(%s) returned err=%u.\n", pszServiceName, pThis->m_dwLastError); break; } } Assert(pThis->m_hService == NULL); if (cServicesRemaining == 0) { // This was our last service to start
pThis->m_fPulseEvent = FALSE; pThis->m_hService = hService; break; } Assert(pThis->m_fPulseEvent == TRUE); pThis->m_hService = hService; // Wait until the service was actually 'started'
WaitForSingleObject(pThis->m_hEvent, INFINITE); pThis->m_hService = NULL; Assert(hService != NULL); VERIFY(::CloseServiceHandle(hService)); } // while
Done: pThis->M_DoThreadCleanup(); return 0; } // S_ThreadProcStartService()
/////////////////////////////////////////////////////////////////////
// Thread to stop one (or more) services.
DWORD CServiceControlProgress::S_ThreadProcStopService(CServiceControlProgress * pThis) { BOOL fSuccess; SC_HANDLE hService;
Assert(pThis != NULL); Assert(pThis->m_hScManager != NULL); Assert(pThis->m_dwDesiredAccess & SERVICE_STOP); Assert(pThis->m_hService == NULL); Assert(pThis->m_fPulseEvent == FALSE);
//
// Stop the dependent services
//
while (TRUE) { LPCTSTR pszServiceName; LPCTSTR pszServiceDisplayName; UINT cServicesRemaining = pThis->M_FGetNextService( OUT &pszServiceName, OUT &pszServiceDisplayName);
pThis->M_UpdateDialogUI(pszServiceDisplayName); // Sleep(5000); // Debug
hService = ::OpenService( pThis->m_hScManager, pszServiceName, pThis->m_dwDesiredAccess); if (hService == NULL) { pThis->m_dwLastError = GetLastError(); TRACE2("ERR: S_ThreadProcStopService(): Unable to open dependent service %s to stop. err=%u.\n", pszServiceName, pThis->m_dwLastError); break; } SERVICE_STATUS ss; // Ignored
fSuccess = ::ControlService( hService, pThis->m_dwControlCode, OUT IGNORED &ss); if (!fSuccess) { APIERR err = GetLastError(); if (ERROR_SERVICE_NOT_ACTIVE != err) { TRACE2("ERR: S_ThreadProcStopService(): ControlService(%s) returned err=%u.\n", pszServiceName, pThis->m_dwLastError); break; } }
Assert(pThis->m_hService == NULL); if (cServicesRemaining == 0 && !pThis->m_fRestartService) { // This was our last service to stop
pThis->m_fPulseEvent = FALSE; pThis->m_hService = hService; break; // We are done
} else { pThis->m_fPulseEvent = TRUE; pThis->m_hService = hService; }
// Wait until the service was actually 'stopped'
WaitForSingleObject(pThis->m_hEvent, INFINITE); pThis->m_hService = NULL; Assert(hService != NULL); VERIFY(::CloseServiceHandle(hService));
if (cServicesRemaining == 0) { Assert(pThis->m_fRestartService == TRUE); Assert(pThis->m_fPulseEvent == TRUE); // Start the service
Assert(pThis->m_dwNumServiceArgs == 0); Assert(pThis->m_lpServiceArgVectors == NULL); pThis->m_iDependentServiceIter = pThis->m_cDependentServices; // Rewind the service iterator
pThis->m_dwQueryState = SERVICE_START_PENDING; pThis->m_iServiceAction = iServiceActionStart; (void)S_ThreadProcStartService(pThis); return 0; } } // while
pThis->M_DoThreadCleanup(); return 0; } // S_ThreadProcStopService()
/////////////////////////////////////////////////////////////////////
// Thread to pause or resume the service
DWORD CServiceControlProgress::S_ThreadProcPauseResumeService(CServiceControlProgress * pThis) { BOOL fSuccess; SC_HANDLE hService; SERVICE_STATUS ss;
Assert(pThis != NULL); Assert(pThis->m_hScManager != NULL); Assert(pThis->m_dwDesiredAccess & SERVICE_PAUSE_CONTINUE); Assert(pThis->m_hService == NULL); Assert(pThis->m_fPulseEvent == FALSE);
pThis->M_UpdateDialogUI(pThis->m_szServiceDisplayName);
// Open service to allow a 'pause' or 'resume' operation
hService = ::OpenService( pThis->m_hScManager, pThis->m_szServiceName, pThis->m_dwDesiredAccess); if (hService == NULL) { pThis->m_dwLastError = GetLastError(); TRACE2("ERR: S_ThreadProcPauseResumeService(): Unable to open service %s. err=%u.\n", pThis->m_szServiceName, pThis->m_dwLastError); goto Done; } fSuccess = ::ControlService( hService, pThis->m_dwControlCode, OUT IGNORED &ss); if (!fSuccess) { pThis->m_dwLastError = GetLastError(); TRACE2("ERR: S_ThreadProcPauseResumeService(): ControlService(%s) returned err=%u.\n", pThis->m_szServiceName, pThis->m_dwLastError); } Assert(pThis->m_hService == NULL); pThis->m_hService = hService; Done: pThis->M_DoThreadCleanup(); return 0; } // S_ThreadProcPauseResumeService()
/////////////////////////////////////////////////////////////////////
// S_DlgProcControlService()
//
// Dialog proc for the clock dialog
// - Respond to a WM_TIMER message to update the clock bitmap while
// waiting for the operation to complete.
//
BOOL CALLBACK CServiceControlProgress::S_DlgProcControlService(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CServiceControlProgress * pThis; pThis = (CServiceControlProgress*)GetWindowLongPtr(hdlg, DWLP_USER); switch (uMsg) { case WM_INITDIALOG: pThis = reinterpret_cast<CServiceControlProgress *>(lParam); Assert(pThis != NULL); pThis->M_OnInitDialog(hdlg); break;
case WM_TIMER: Assert(pThis != NULL); Assert(wParam == pThis->m_uTimerId); pThis->M_OnTimer(hdlg); break;
case WM_COMMAND: Assert(wParam == IDOK || wParam == IDCANCEL); if (wParam == IDCANCEL) { if ((HWND)lParam != NULL) { TRACE1("INFO: User cancelled dialog. dwLastError=%u.\n", pThis->m_dwLastError); pThis->m_dwLastError = errUserAbort; } EndDialog(hdlg, FALSE); } else { Assert(IsWindow(pThis->m_hctlProgress)); SendMessage(pThis->m_hctlProgress, PBM_SETPOS, dwTimerProgressDone * 2, 0); Sleep(150); EndDialog (hdlg, TRUE); } break;
case WM_DESTROY: Assert(IsWindow(pThis->m_hctlActionMsg) && IsWindow(pThis->m_hctlServiceNameMsg)); pThis->m_hctlActionMsg = NULL; pThis->m_hctlServiceNameMsg = NULL; if (pThis->m_uTimerId != 0) { VERIFY(KillTimer(hdlg, pThis->m_uTimerId)); } break;
default: return FALSE; } // switch (uMsg)
return (TRUE); } // S_DlgProcControlService()
/////////////////////////////////////////////////////////////////////
void CServiceControlProgress::M_OnInitDialog(HWND hdlg) { Assert(IsWindow(hdlg)); SetWindowLongPtr(hdlg, DWLP_USER, reinterpret_cast<LONG_PTR>(this)); m_hctlActionMsg = HGetDlgItem(hdlg, IDC_STATIC_ACTION_MSG); m_hctlServiceNameMsg = HGetDlgItem(hdlg, IDC_STATIC_SERVICENAME_MSG); m_hctlProgress = HGetDlgItem(hdlg, IDC_PROGRESS); SendMessage(m_hctlProgress, PBM_SETRANGE, 0, MAKELPARAM(0, dwTimerProgressDone * 2));
Assert(m_uTimerId == 0); Assert(m_dwTimerTicks == 0); m_uTimerId = SetTimer(hdlg, ID_TIMER, dwTimerTickIncrement, NULL); Assert(m_hThread != NULL); ::ResumeThread(m_hThread); if (m_uTimerId == 0) { Report(FALSE && "Unable to create timer. Dialog will be destroyed."); PostMessage(hdlg, WM_COMMAND, IDCANCEL, 0); } } // M_OnInitDialog()
/////////////////////////////////////////////////////////////////////
void CServiceControlProgress::M_OnTimer(HWND hdlg) { Assert(IsWindow(m_hctlActionMsg) && IsWindow(m_hctlServiceNameMsg)); m_dwTimerTicks += dwTimerTickIncrement; if (m_dwLastError != ERROR_SUCCESS) { TRACE1("CServiceControlProgress::M_OnTimer() - dwLastError=%u.\n", m_dwLastError); PostMessage(hdlg, WM_COMMAND, IDCANCEL, 0); return; } if (m_dwTimerTicks > dwTimerTimeout) { VERIFY(KillTimer(hdlg, m_uTimerId)); m_uTimerId = 0; m_dwLastError = ERROR_SERVICE_REQUEST_TIMEOUT; TRACE0("CServiceControlProgress::M_OnTimer() - Time out.\n"); PostMessage(hdlg, WM_COMMAND, IDCANCEL, 0); return; } if ((m_hService != NULL) && (m_dwTimerTicks >= 900)) { // If the current state of the service changed (ie, operation completed)
// we can dismiss the dialog
if (m_dwQueryState != M_QueryCurrentServiceState()) { if (m_fPulseEvent) { m_dwTimerTicks = 0; // Reset the time-out counter
Assert(m_hEvent != NULL); PulseEvent(m_hEvent); SendMessage(m_hctlProgress, PBM_SETPOS, dwTimerProgressDone * 2, 0); Sleep(100); } else { PostMessage(hdlg, WM_COMMAND, IDOK, 0); } } } // if
// Advance the current position of the progress bar by the increment.
Assert(IsWindow(m_hctlProgress)); DWORD dwPos = m_dwTimerTicks; if(dwPos > dwTimerProgressDone) { dwPos -= dwTimerProgressDone; dwPos = (dwPos * dwTimerProgressDone) / dwTimerTimeout; dwPos += dwTimerProgressDone; } SendMessage(m_hctlProgress, PBM_SETPOS, dwPos, 0); } // M_OnTimer()
/////////////////////////////////////////////////////////////////////
BOOL CALLBACK CServiceControlProgress::S_DlgProcDependentServices(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CServiceControlProgress * pThis; HWND hwndListbox; INT i;
switch (uMsg) { case WM_INITDIALOG: pThis = reinterpret_cast<CServiceControlProgress *>(lParam); Assert(pThis != NULL); SetWindowTextPrintf( ::GetDlgItem(hdlg, IDC_STATIC_STOP_SERVICES), (pThis->m_fRestartService) ? IDS_SVC_s_RESTART_DEPENDENT_SERVICES : IDS_SVC_s_STOP_DEPENDENT_SERVICES, pThis->m_szServiceDisplayName); if (pThis->m_fRestartService) { // Set the window caption
SetWindowTextPrintf(hdlg, IDS_SVC_RESTART_DEPENDENT_CAPTION); SetWindowTextPrintf(::GetDlgItem(hdlg, IDC_STATIC_STOP_SERVICES_QUERY), IDS_SVC_RESTART_DEPENDENT_QUERY); } // Fill in the listbox with dependent services
hwndListbox = HGetDlgItem(hdlg, IDC_LIST_SERVICES); Assert(pThis->m_pargDependentServicesT != NULL); for (i = 0; i < pThis->m_cDependentServices; i++) { SendMessage(hwndListbox, LB_ADDSTRING, 0, (LPARAM)pThis->m_pargDependentServicesT[i].lpDisplayName); } break;
case WM_COMMAND: switch (wParam) { case IDOK: EndDialog(hdlg, TRUE); break; case IDCANCEL: EndDialog(hdlg, FALSE); break; } break;
case WM_CONTEXTMENU: // right mouse click
DoContextHelp(wParam, HELP_DIALOG_TOPIC(IDD_SERVICE_STOP_DEPENDENCIES)); break;
case WM_HELP: DoHelp(lParam, HELP_DIALOG_TOPIC(IDD_SERVICE_STOP_DEPENDENCIES)); break;
default: return FALSE; } // switch (uMsg)
return TRUE;
} // S_DlgProcDependentServices()
/////////////////////////////////////////////////////////////////////
// S_EStartService()
//
// Starts the execution of a service synchronously. The function will wait
// until the service is fully started and/or failed to start.
//
// A clock dialog will appear indicating the progress of the operation.
//
// Return ERROR_SUCCESS if syccessful, otherwise return the error code
// from GetLastError().
//
APIERR CServiceControlProgress::S_EStartService( HWND hwndParent, // IN: Parent of the dialog
SC_HANDLE hScManager, // IN: Handle to service control manager database
LPCTSTR pszMachineName, // IN: Machine name to display to the user
LPCTSTR pszServiceName, // IN: Name of the service to start
LPCTSTR pszServiceDisplayName, // IN: Display name of the service to start
DWORD dwNumServiceArgs, // IN: Number of arguments
LPCTSTR * lpServiceArgVectors) // IN: Address of array of argument string pointers
{ CServiceControlProgress * pThis;
pThis = new CServiceControlProgress; Assert(pThis->m_dwLastError == ERROR_SUCCESS); // No error yet
if (!pThis->M_FInit( hwndParent, hScManager, pszMachineName, pszServiceName, pszServiceDisplayName)) { delete pThis; return errCannotInitialize; } pThis->m_dwNumServiceArgs = dwNumServiceArgs; pThis->m_lpServiceArgVectors = lpServiceArgVectors; pThis->m_dwQueryState = SERVICE_START_PENDING; pThis->m_iServiceAction = iServiceActionStart; return pThis->M_EDoExecuteServiceThread(S_ThreadProcStartService); } // S_EStartService()
/////////////////////////////////////////////////////////////////////
// S_EControlService()
//
// Control the execution of a service synchronously. The function is similar
// to EStartService() but use for Stop, Pause or Resume a service.
//
// A clock dialog will appear indicating the progress of the operation.
//
// Return ERROR_SUCCESS if syccessful, otherwise return the error code
// from GetLastError().
//
APIERR CServiceControlProgress::S_EControlService( HWND hwndParent, // IN: Parent of the dialog
SC_HANDLE hScManager, // IN: Handle to service control manager database
LPCTSTR pszMachineName, // IN: Machine name to display to the user
LPCTSTR pszServiceName, // IN: Name of the service to start
LPCTSTR pszServiceDisplayName, // IN: Display name of the service to start
DWORD dwControlCode) // IN: Control code. (SERVICE_CONTROL_STOP, SERVICE_CONTROL_PAUSE or SERVICE_CONTROL_CONTINUE)
{ CServiceControlProgress * pThis;
pThis = new CServiceControlProgress; Assert(pThis->m_dwLastError == ERROR_SUCCESS); // No error yet
if (!pThis->M_FInit( hwndParent, hScManager, pszMachineName, pszServiceName, pszServiceDisplayName)) { delete pThis; return errCannotInitialize; }
return pThis->M_EControlService(dwControlCode); } // S_EControlService()
|