|
|
/*++
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
//
}
|