/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : shutdown.cpp Abstract: IIS Shutdown/restart dialog Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "inetmgr.h" #include "sdprg.h" #include "shutdown.h" // // Shutdown in microseconds // #define IIS_SHUTDOWN_TIMEOUT 30000L // 30 Ms #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CIISShutdownDlg::CIISShutdownDlg( IN LPCTSTR lpszServer, IN CWnd * pParent OPTIONAL ) /*++ Routine Description: Constructor Arguments: LPCTSTR lpszServer : Server name CWnd * pParent : Optional parent window Return Value: N/A --*/ : CDialog(CIISShutdownDlg::IDD, pParent), m_fServicesRestarted(FALSE), m_fLocalMachine(::IsServerLocal(lpszServer)), m_strServer(lpszServer) { //{{AFX_DATA_INIT(CIISShutdownDlg) //}}AFX_DATA_INIT } void CIISShutdownDlg::DoDataExchange( IN CDataExchange * pDX ) /*++ Routine Description: Initialise/Store control data Arguments: CDataExchange * pDX - DDX/DDV control structure Return Value: None --*/ { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CIISShutdownDlg) DDX_Control(pDX, IDC_COMBO_RESTART, m_combo_Restart); DDX_Control(pDX, IDC_STATIC_DETAILS, m_static_Details); //}}AFX_DATA_MAP } void CIISShutdownDlg::SetDetailsText() /*++ Routine Description: Set the details text to correspond to what's in the combo box Arguments: None Return Value: None --*/ { UINT nSel = m_combo_Restart.GetCurSel(); ASSERT(nSel >= 0 && nSel < NUM_ISC_ITEMS); m_static_Details.SetWindowText(m_strDetails[nSel]); } // // Message Map // BEGIN_MESSAGE_MAP(CIISShutdownDlg, CDialog) //{{AFX_MSG_MAP(CIISShutdownDlg) ON_CBN_SELCHANGE(IDC_COMBO_RESTART, OnSelchangeComboRestart) ON_CBN_DBLCLK(IDC_COMBO_RESTART, OnDblclkComboRestart) ON_BN_CLICKED(ID_HELP, OnHelp) //}}AFX_MSG_MAP END_MESSAGE_MAP() CRITICAL_SECTION gcs; UINT __cdecl StopIISServices( IN LPVOID pParam ) /*++ Routine Description: Worker thread to perform IIS Service Control Command Arguments: LPVOID * pParam : Casts to IISCOMMAND (see above) Return Value: UINT --*/ { IISCOMMAND * pCmd = (IISCOMMAND *)pParam; //MessageBeep(0); // // This thread needs its own CoInitialize // CError err(CoInitialize(NULL)); CIISSvcControl isc(pCmd->szServer); err = isc.QueryResult(); // Block access to pCmd: // if user will click on "End Now" then process will // be killed and pCmd could by deleted async in parent // code -- this is why we need gcs EnterCriticalSection(&gcs); if (err.Succeeded()) { err = isc.Stop(IIS_SHUTDOWN_TIMEOUT, TRUE); } // // Clean Up, returning the error code // EnterCriticalSection(&pCmd->cs); pCmd->fFinished = TRUE; pCmd->hReturn = err; LeaveCriticalSection(&pCmd->cs); LeaveCriticalSection(&gcs); return 0; } HRESULT CIISShutdownDlg::PerformCommand( IN int iCmd ) /*++ Routine Description: Perform restart command Arguments: int iCmd - One of the following commands: ISC_START ISC_STOP ISC_SHUTDOWN ISC_RESTART Return Value: HRESULT --*/ { // // Make sure the service is supported // BeginWaitCursor(); CIISSvcControl isc(m_strServer); EndWaitCursor(); CError err(isc.QueryResult()); if (err.Failed()) { return err; } // // Create command structure to hand off to // worker thread // IISCOMMAND * pCommand = new IISCOMMAND; if (!pCommand) { err = ERROR_NOT_ENOUGH_MEMORY; return err; } ZeroMemory(pCommand, sizeof(IISCOMMAND)); lstrcpy(pCommand->szServer, m_strServer); pCommand->dwMilliseconds = IIS_SHUTDOWN_TIMEOUT; pCommand->pParent = this; InitializeCriticalSection(&pCommand->cs); InitializeCriticalSection(&gcs); CShutProgressDlg dlg(pCommand); CWinThread * pStopThread = NULL; BOOL fStartServices = FALSE; INT_PTR nReturn = IDCANCEL; // // Fire off the thread that does the actual work, while we // put up the progress UI // switch(iCmd) { case ISC_RESTART: ++fStartServices; // // Fall through... // case ISC_STOP: // // Stop the services in the workerthread // pStopThread = AfxBeginThread(&StopIISServices, pCommand); nReturn = dlg.DoModal(); break; case ISC_START: ++fStartServices; break; case ISC_SHUTDOWN: BeginWaitCursor(); err = isc.Reboot(IIS_SHUTDOWN_TIMEOUT, m_fLocalMachine); EndWaitCursor(); break; default: // // Internal error! // ASSERT(FALSE && "Invalid command code!"); err = ERROR_INVALID_FUNCTION; } // // Determine if a kill is necessary (timed-out or user // pressed 'Kill') // BeginWaitCursor(); if (nReturn == IDOK) { TRACEEOLID("Killing now!"); err = isc.Kill(); Sleep(1000L); } else { // // Waiting for the thread to finish // if (pStopThread != NULL) { BOOL fDone = FALSE; while(!fDone) { TRACEEOLID("Checking to see if thread has finished"); EnterCriticalSection(&pCommand->cs); if (pCommand->fFinished) { err = pCommand->hReturn; ++fDone; } LeaveCriticalSection(&pCommand->cs); // // Pause a bit... // if (!fDone) { Sleep(500); } } } } // // Everything should be stopped, start it up again // if necessary. // if (err.Succeeded() && fStartServices) { err = isc.Start(IIS_SHUTDOWN_TIMEOUT); m_fServicesRestarted = err.Succeeded(); } EndWaitCursor(); // // Clean Up // EnterCriticalSection(&gcs); DeleteCriticalSection(&pCommand->cs); delete pCommand; LeaveCriticalSection(&gcs); DeleteCriticalSection(&gcs); return err; } // // Message Handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< BOOL CIISShutdownDlg::OnInitDialog() /*++ Routine Description: WM_INITDIALOG handler. Initialize the dialog. Arguments: None. Return Value: TRUE if no focus is to be set automatically, FALSE if the focus is already set. --*/ { CDialog::OnInitDialog(); // // Load combobox text and details // CString strFmt, str; // // This may take a second or two... // BeginWaitCursor(); CIISSvcControl isc(m_strServer); EndWaitCursor(); CError err(isc.QueryResult()); if (err.Failed()) { // // Failed to obtain interface -- quit now. // if (err.HResult() == REGDB_E_CLASSNOTREG || err.HResult() == CS_E_PACKAGE_NOTFOUND ) { // // Friendly message about the interface not being supported // AfxMessageBox(IDS_ERR_NO_SHUTDOWN); } else { err.MessageBox(); } EndDialog(IDCANCEL); } /* TEST code if (isc.Succeeded()) { //LPBYTE pbBuffer; BYTE abBuffer[4096]; DWORD dwReq; DWORD dwNumServices; HRESULT hr = isc.Status(sizeof(abBuffer), abBuffer, &dwReq, &dwNumServices); TRACEEOLID(hr); } */ UINT nOption = IDS_IIS_START; UINT nDetails = IDS_IIS_START_DETAILS; for (int i = ISC_START; i <= ISC_RESTART; ++i) { VERIFY(strFmt.LoadString(nOption++)); str.Format(strFmt, (LPCTSTR)m_strServer); VERIFY(m_strDetails[i].LoadString(nDetails++)); m_combo_Restart.AddString(str); } m_combo_Restart.SetCurSel(ISC_RESTART); m_combo_Restart.SetFocus(); SetDetailsText(); return FALSE; } void CIISShutdownDlg::OnSelchangeComboRestart() /*++ Routine Description: Selection change notification handler. Change the text in the details static text to reflect the new selection in the combo box Arguments: None Return Value: None --*/ { SetDetailsText(); } void CIISShutdownDlg::OnDblclkComboRestart() /*++ Routine Description: Double-click notification handler. Maps to OK Arguments: None Return Value: None --*/ { // // Go with the current selection // OnOK(); } void CIISShutdownDlg::OnOK() /*++ Routine Description: "OK" button has been pressed, and perform the selected action. Arguments: None Return Value: None --*/ { int iCmd = m_combo_Restart.GetCurSel(); CError err = PerformCommand(iCmd); if (!err.MessageBoxOnFailure()) { // // No error, dismiss the dialog // CDialog::OnOK(); } // // Failed -- do not dismiss the dialog // }