//____________________________________________________________________________ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1996. // // File: SchState.cxx // // Contents: // // Classes: // // Functions: // // History: 3/27/1996 RaviR Created // //____________________________________________________________________________ #include "..\pch\headers.hxx" #pragma hdrstop #include "dbg.h" #include "macros.h" #include "..\inc\common.hxx" #include "..\inc\resource.h" #include "..\inc\misc.hxx" #include "resource.h" #include "..\schedui\schedui.hxx" #define MAX_MSGLEN 300 #define MAX_SCHED_START_WAIT 60 // seconds #ifdef _CHICAGO_ #define TIMEOUT_INTERVAL 10000 #define TIMEOUT_INCREMENT 10000 #define TIMEOUT_INTERVAL_MAX (5 * 60 * 1000) // 5 minutes //____________________________________________________________________________ // // Function: I_SendMsgTimeout // // Synopsis: Uses SendMessageTimeout to send the message with SMTO_BLOCK // option. If SendMessageTimeout fails due to timeout error, // we prompt the user for retry. // // Arguments: [hwnd] -- IN // [uMsg] -- IN // [pdwRes] -- IN // // Returns: BOOL // // History: 3/29/1996 RaviR Created // //____________________________________________________________________________ BOOL I_SendMsgTimeout( HWND hwnd, UINT uMsg, DWORD * pdwRes) { UINT uTimeOut = TIMEOUT_INTERVAL; int idsErr = 0; TCHAR szErrMsg[MAX_MSGLEN] = TEXT(""); TCHAR szErrCaption[MAX_MSGLEN] = TEXT(""); switch (uMsg) { case SCHED_WIN9X_GETSVCSTATE: idsErr = IERR_GETSVCSTATE; break; case SCHED_WIN9X_STOPSVC: idsErr = IERR_STOPSVC; break; case SCHED_WIN9X_PAUSESVC: idsErr = IERR_PAUSESVC; break; case SCHED_WIN9X_CONTINUESVC: idsErr = IERR_CONTINUESVC; break; } while (1) { if (SendMessageTimeout(hwnd, uMsg, 0L, 0L, SMTO_BLOCK, uTimeOut, pdwRes) == TRUE) { return TRUE; } if (szErrMsg[0] == TEXT('\0')) { UINT iCur = 0; if (idsErr != 0) { LoadString(g_hInstance, idsErr, szErrMsg, MAX_MSGLEN); iCur = lstrlen(szErrMsg); szErrMsg[iCur++] = TEXT(' '); } LoadString(g_hInstance, IERR_SCHEDSVC, &szErrMsg[iCur], MAX_MSGLEN - iCur); LoadString(g_hInstance, IDS_SCHEDULER_NAME, szErrCaption, MAX_MSGLEN); } int iReply = MessageBox(hwnd, szErrMsg, szErrCaption, MB_YESNO); if (iReply == IDNO) { return FALSE; } if (uTimeOut < TIMEOUT_INTERVAL_MAX) { uTimeOut += TIMEOUT_INCREMENT; } } return FALSE; } #endif // _CHICAGO_ //____________________________________________________________________________ // // Function: GetSchSvcState // // Synopsis: returns the schedul service status // // Arguments: [dwState] -- IN // // Returns: HRESULT // // History: 3/29/1996 RaviR Created // //____________________________________________________________________________ HRESULT GetSchSvcState( DWORD &dwState) { #ifdef _CHICAGO_ HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE); if (hwnd == NULL) { dwState = SERVICE_STOPPED; } else { if (I_SendMsgTimeout(hwnd, SCHED_WIN9X_GETSVCSTATE, &dwState) == FALSE) { return E_FAIL; } } return S_OK; #else // _NT1X_ SC_HANDLE hSchSvc = NULL; HRESULT hr = S_OK; do { hSchSvc = OpenScheduleService(SERVICE_QUERY_STATUS); if (hSchSvc == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } SERVICE_STATUS SvcStatus; if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } dwState = SvcStatus.dwCurrentState; } while (0); if (hSchSvc != NULL) { CloseServiceHandle(hSchSvc); } return hr; #endif // _NT1X_ } //____________________________________________________________________________ // // Function: StartScheduler // // Synopsis: Start the schedule service // // Returns: HRESULT // // History: 3/29/1996 RaviR Created // //____________________________________________________________________________ HRESULT StartScheduler(void) { #ifdef _CHICAGO_ // // Persist the change. // AutoStart(TRUE); // // See if it is running. // HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE); if (hwnd != NULL) { // It is already running. return S_OK; } // // Create a process to open the log. // STARTUPINFO sui; PROCESS_INFORMATION pi; ZeroMemory(&sui, sizeof(sui)); sui.cb = sizeof (STARTUPINFO); TCHAR szApp[MAX_PATH]; LPTSTR pszFilePart; DWORD dwRet = SearchPath(NULL, SCHED_SERVICE_APP_NAME, NULL, MAX_PATH, szApp, &pszFilePart); if (dwRet == 0) { DEBUG_OUT_LASTERROR; return HRESULT_FROM_WIN32(GetLastError()); } BOOL fRet = CreateProcess( szApp, // lpszImageName NULL, // lpszCommandLine NULL, // lpsaProcess - security attributes NULL, // lpsaThread - security attributes FALSE, // fInheritHandles CREATE_NEW_CONSOLE // fdwCreate - creation flags | CREATE_NEW_PROCESS_GROUP, NULL, // lpvEnvironment NULL, // lpszCurDir &sui, // lpsiStartInfo &pi ); // lppiProcInfo if (fRet == 0) { DEBUG_OUT_LASTERROR; return HRESULT_FROM_WIN32(GetLastError()); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return S_OK; #else // _NT1X_ SC_HANDLE hSchSvc = NULL; HRESULT hr = S_OK; do { hSchSvc = OpenScheduleService( SERVICE_CHANGE_CONFIG | SERVICE_START | SERVICE_QUERY_STATUS); if (hSchSvc == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } SERVICE_STATUS SvcStatus; if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } if (SvcStatus.dwCurrentState == SERVICE_RUNNING) { // The service is already running. break; } if (StartService(hSchSvc, 0, NULL) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } // // Persist the change. Since the service started successfully, // don't complain if this fails. // HRESULT hrAuto = AutoStart(TRUE); CHECK_HRESULT(hrAuto); } while (0); if (hSchSvc != NULL) { CloseServiceHandle(hSchSvc); } return hr; #endif // _NT1X_ } //____________________________________________________________________________ // // Function: StopScheduler // // Synopsis: Stops the schedule service // // Returns: HRESULT // // History: 3/29/1996 RaviR Created // //____________________________________________________________________________ HRESULT StopScheduler(void) { #ifdef _CHICAGO_ // // Persist the change. // AutoStart(FALSE); // // See if it is running or not. // HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE); if (hwnd == NULL) { // already stopped return S_OK; } else if (I_SendMsgTimeout(hwnd, SCHED_WIN9X_STOPSVC, NULL) == TRUE) { return S_OK; } return E_FAIL; #else // _NT1X_ SC_HANDLE hSchSvc = NULL; HRESULT hr = S_OK; do { hSchSvc = OpenScheduleService( SERVICE_CHANGE_CONFIG | SERVICE_STOP | SERVICE_QUERY_STATUS); if (hSchSvc == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } SERVICE_STATUS SvcStatus; if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } if (SvcStatus.dwCurrentState == SERVICE_STOPPED) { // The service is already stopped. break; } if (ControlService(hSchSvc, SERVICE_CONTROL_STOP, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } // // Persist the change. Since the service was stopped successfully, // don't complain if this fails. // HRESULT hrAuto = AutoStart(FALSE); CHECK_HRESULT(hrAuto); } while (0); if (hSchSvc != NULL) { CloseServiceHandle(hSchSvc); } return hr; #endif // _NT1X_ } //____________________________________________________________________________ // // Function: PauseScheduler // // Synopsis: If fPause==TRUE requests the schedule service to pauses, // else to continue. // // Arguments: [fPause] -- IN // // Returns: HRESULT // // History: 3/29/1996 RaviR Created // //____________________________________________________________________________ HRESULT PauseScheduler( BOOL fPause) { #ifdef _CHICAGO_ HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE); UINT uMsg = fPause ? SCHED_WIN9X_PAUSESVC : SCHED_WIN9X_CONTINUESVC; if ((hwnd != NULL) && (I_SendMsgTimeout(hwnd, uMsg, NULL) == TRUE)) { return S_OK; } return E_FAIL; #else // _NT1X_ SC_HANDLE hSchSvc = NULL; HRESULT hr = S_OK; do { hSchSvc = OpenScheduleService( SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS); if (hSchSvc == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } SERVICE_STATUS SvcStatus; if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } if (fPause == TRUE) { if ((SvcStatus.dwCurrentState == SERVICE_PAUSED) || (SvcStatus.dwCurrentState == SERVICE_PAUSE_PENDING)) { // Nothing to do here. break; } else if ((SvcStatus.dwCurrentState == SERVICE_STOPPED) || (SvcStatus.dwCurrentState == SERVICE_STOP_PENDING)) { Win4Assert(0 && "Unexpected"); hr = E_UNEXPECTED; CHECK_HRESULT(hr); break; } else { if (ControlService(hSchSvc, SERVICE_CONTROL_PAUSE, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } } } else // continue { if ((SvcStatus.dwCurrentState == SERVICE_RUNNING) || (SvcStatus.dwCurrentState == SERVICE_CONTINUE_PENDING)) { // Nothing to do here. break; } else if ((SvcStatus.dwCurrentState == SERVICE_STOPPED) || (SvcStatus.dwCurrentState == SERVICE_STOP_PENDING)) { Win4Assert(0 && "Unexpected"); hr = E_UNEXPECTED; CHECK_HRESULT(hr); break; } else { if (ControlService(hSchSvc, SERVICE_CONTROL_CONTINUE, &SvcStatus) == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_LASTERROR; break; } } } } while (0); if (hSchSvc != NULL) { CloseServiceHandle(hSchSvc); } return hr; #endif // _NT1X_ } //+-------------------------------------------------------------------------- // // Function: UserCanChangeService // // Synopsis: Returns TRUE if the UI should allow the user to invoke // service start, stop, pause/continue, or at account options. // // Returns: TRUE if focus is local machine and OS is win95 or it is NT // and the user is an admin. // // History: 4-16-1997 DavidMun Created // //--------------------------------------------------------------------------- BOOL UserCanChangeService( LPCTSTR pszServerFocus) { if (pszServerFocus) { return FALSE; } #if defined(_CHICAGO_) return TRUE; #else // // Determine if user is an admin. If not, some items under the // advanced menu will be disabled. // BUGBUG A more accurate way to do this would be to attempt to open // the relevant registry keys and service handle. // return IsThreadCallerAnAdmin(NULL); #endif // !defined(_CHICAGO_) } //+-------------------------------------------------------------------------- // // Function: PromptForServiceStart // // Synopsis: If the service is not started or is paused, prompt the user // to allow us to start/continue it. // // Returns: S_OK - service was already running, or was successfully // started or continued. // S_FALSE - user elected not to start/continue service // E_* - error starting/continuing service // // History: 4-16-1997 DavidMun Created // //--------------------------------------------------------------------------- HRESULT PromptForServiceStart( HWND hwnd) { HRESULT hr = S_OK; do { // // Get the current service state // DWORD dwState = SERVICE_STOPPED; hr = GetSchSvcState(dwState); if (FAILED(hr)) { dwState = SERVICE_STOPPED; hr = S_OK; // reset } // // Determine the required action // UINT uMsg = 0; if (dwState == SERVICE_STOPPED || dwState == SERVICE_STOP_PENDING) { uMsg = IDS_START_SERVICE; } else if (dwState == SERVICE_PAUSED || dwState == SERVICE_PAUSE_PENDING) { uMsg = IDS_CONTINUE_SERVICE; } else if (dwState == SERVICE_START_PENDING) { uMsg = IDS_START_PENDING; } // // If the service is running, there's nothing to do. // if (!uMsg) { hr = S_OK; break; } if (uMsg == IDS_START_PENDING) { SchedUIMessageDialog(hwnd, uMsg, MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONINFORMATION | MB_OK, NULL); } else { if (SchedUIMessageDialog(hwnd, uMsg, MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONQUESTION | MB_YESNO, NULL) == IDNO) { hr = S_FALSE; break; } } CWaitCursor waitCursor; if (uMsg == IDS_START_SERVICE) { hr = StartScheduler(); if (FAILED(hr)) { SchedUIErrorDialog(hwnd, IERR_STARTSVC, (LPTSTR)NULL); break; } // Give the schedule service time to start up. Sleep(2000); } else if (uMsg == IDS_CONTINUE_SERVICE) { PauseScheduler(FALSE); } for (int count=0; count < 60; count++) { GetSchSvcState(dwState); if (dwState == SERVICE_RUNNING) { break; } Sleep(1000); // Sleep for 1 seconds. } if (dwState != SERVICE_RUNNING) { // // unable to start/continue the service. // SchedUIErrorDialog(hwnd, (uMsg == IDS_START_SERVICE) ? IERR_STARTSVC : IERR_CONTINUESVC, (LPTSTR)NULL); hr = E_FAIL; break; } } while (0); return hr; } //+-------------------------------------------------------------------------- // // Function: QuietStartContinueService // // Synopsis: Start or continue the service without requiring user // interaction. // // Returns: S_OK - service running // E_FAIL - timeout or failure // // History: 5-19-1997 DavidMun Created // //--------------------------------------------------------------------------- HRESULT QuietStartContinueService() { HRESULT hr = S_OK; DWORD dwState = SERVICE_STOPPED; do { hr = GetSchSvcState(dwState); if (FAILED(hr)) { dwState = SERVICE_STOPPED; hr = S_OK; // reset } // // If the service is running, there's nothing to do. // if (dwState == SERVICE_RUNNING) { break; } // // If it's stopped, request a start. If it's paused, request // continue. // CWaitCursor waitCursor; switch (dwState) { case SERVICE_STOPPED: case SERVICE_STOP_PENDING: hr = StartScheduler(); break; case SERVICE_PAUSED: case SERVICE_PAUSE_PENDING: hr = PauseScheduler(FALSE); break; } if (FAILED(hr)) { CHECK_HRESULT(hr); break; } // // Wait for its state to change to running // for (int count=0; count < MAX_SCHED_START_WAIT; count++) { GetSchSvcState(dwState); if (dwState == SERVICE_RUNNING) { break; } Sleep(1000); // Sleep for 1 seconds. } if (dwState != SERVICE_RUNNING) { // // unable to start/continue the service. // hr = E_FAIL; CHECK_HRESULT(hr); } } while (0); return hr; } //____________________________________________________________________________ // // Function: OpenScheduleService // // Synopsis: Opens a handle to the "Schedule" service // // Arguments: [dwDesiredAccess] -- desired access // // Returns: Handle; if NULL, use GetLastError() // // History: 15-Nov-1996 AnirudhS Created // //____________________________________________________________________________ #ifndef _CHICAGO_ SC_HANDLE OpenScheduleService(DWORD dwDesiredAccess) { SC_HANDLE hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hSC == NULL) { DEBUG_OUT_LASTERROR; return NULL; } SC_HANDLE hSchSvc = OpenService(hSC, SCHED_SERVICE_NAME, dwDesiredAccess); CloseServiceHandle(hSC); if (hSchSvc == NULL) { DEBUG_OUT_LASTERROR; } return hSchSvc; } #endif // !_CHICAGO_