You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
699 lines
17 KiB
699 lines
17 KiB
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
svcctrl.cpp
|
|
Implementation for the dialog that pops up while waiting
|
|
for the server to start.
|
|
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "cluster.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CServiceCtrlDlg dialog
|
|
|
|
|
|
CServiceCtrlDlg::CServiceCtrlDlg
|
|
(
|
|
SC_HANDLE hService,
|
|
LPCTSTR pServerName,
|
|
LPCTSTR pszServiceDesc,
|
|
BOOL bStart,
|
|
CWnd* pParent /*=NULL*/
|
|
)
|
|
: CDialog(CServiceCtrlDlg::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(CServiceCtrlDlg)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_hService = hService;
|
|
m_hResource = NULL;
|
|
m_nTickCounter = TIMER_MULT;
|
|
m_nTotalTickCount = 0;
|
|
m_strServerName = pServerName;
|
|
m_strServerName.MakeUpper();
|
|
m_strServiceDesc = pszServiceDesc;
|
|
m_bStart = bStart;
|
|
m_timerId = 0;
|
|
m_dwErr = 0;
|
|
m_dwLastCheckPoint = -1;
|
|
}
|
|
|
|
|
|
CServiceCtrlDlg::CServiceCtrlDlg
|
|
(
|
|
HRESOURCE hResource,
|
|
LPCTSTR pServerName,
|
|
LPCTSTR pszServiceDesc,
|
|
BOOL bStart,
|
|
CWnd* pParent /*=NULL*/
|
|
)
|
|
: CDialog(CServiceCtrlDlg::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(CServiceCtrlDlg)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_hService = NULL;
|
|
m_hResource = hResource;
|
|
m_nTickCounter = TIMER_MULT;
|
|
m_nTotalTickCount = 0;
|
|
m_strServerName = pServerName;
|
|
m_strServerName.MakeUpper();
|
|
m_strServiceDesc = pszServiceDesc;
|
|
m_bStart = bStart;
|
|
m_timerId = 0;
|
|
m_dwErr = 0;
|
|
m_dwLastCheckPoint = -1;
|
|
}
|
|
|
|
void CServiceCtrlDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CServiceCtrlDlg)
|
|
DDX_Control(pDX, IDC_STATIC_MESSAGE, m_staticMessage);
|
|
DDX_Control(pDX, IDC_ICON_PROGRESS, m_iconProgress);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CServiceCtrlDlg, CDialog)
|
|
//{{AFX_MSG_MAP(CServiceCtrlDlg)
|
|
ON_WM_TIMER()
|
|
ON_WM_CLOSE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CServiceCtrlDlg message handlers
|
|
|
|
BOOL CServiceCtrlDlg::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
m_timerId = SetTimer(TIMER_ID, TIMER_FREQ, NULL);
|
|
|
|
CString strTemp;
|
|
CString strTitle;
|
|
UINT idsTitle;
|
|
|
|
if (m_bStart)
|
|
{
|
|
AfxFormatString2(strTemp, IDS_STARTING_SERVICE_NOW, m_strServerName,
|
|
m_strServiceDesc);
|
|
idsTitle = IDS_START_SERVICE_TITLE;
|
|
}
|
|
else
|
|
{
|
|
AfxFormatString2(strTemp, IDS_STOPPING_SERVICE_NOW, m_strServerName,
|
|
m_strServiceDesc);
|
|
idsTitle = IDS_STOP_SERVICE_TITLE;
|
|
}
|
|
|
|
m_staticMessage.SetWindowText(strTemp);
|
|
|
|
// Setup the title of the window
|
|
strTitle.Format(idsTitle, (LPCTSTR) m_strServiceDesc);
|
|
SetWindowText(strTitle);
|
|
|
|
UpdateIndicator();
|
|
|
|
m_dwTickBegin = GetTickCount();
|
|
|
|
if (m_hService)
|
|
{
|
|
// get the wait period
|
|
SERVICE_STATUS serviceStatus;
|
|
::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
|
|
|
|
if (QueryServiceStatus(m_hService, &serviceStatus))
|
|
{
|
|
m_dwWaitPeriod = serviceStatus.dwWaitHint;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetClusterResourceTimeout();
|
|
}
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
void CServiceCtrlDlg::OnClose()
|
|
{
|
|
if (m_timerId)
|
|
KillTimer(m_timerId);
|
|
|
|
CDialog::OnClose();
|
|
}
|
|
|
|
void CServiceCtrlDlg::OnTimer(UINT nIDEvent)
|
|
{
|
|
//
|
|
// Bag-out if it's not our timer.
|
|
//
|
|
if(nIDEvent != TIMER_ID)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Advance the progress indicator.
|
|
//
|
|
UpdateIndicator();
|
|
|
|
//
|
|
// No need to continue if we're just amusing the user.
|
|
//
|
|
if(--m_nTickCounter > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_nTickCounter = TIMER_MULT;
|
|
|
|
//
|
|
// Poll the service to see if the operation is
|
|
// either complete or continuing as expected.
|
|
//
|
|
|
|
if (m_hService)
|
|
{
|
|
CheckService();
|
|
}
|
|
else
|
|
{
|
|
CheckClusterService();
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
CServiceCtrlDlg::GetClusterResourceTimeout()
|
|
{
|
|
DWORD dwError = 0;
|
|
DWORD cPropListSize = 0;
|
|
DWORD cPropListAlloc = MAX_NAME_SIZE;
|
|
DWORD dwPendingTimeout = 0;
|
|
|
|
// set the default
|
|
m_dwWaitPeriod = 18000;
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return;
|
|
|
|
if ( !g_ResUtilsDLL.LoadFunctionPointers() )
|
|
return;
|
|
|
|
PCLUSPROP_LIST pPropList = (PCLUSPROP_LIST)LocalAlloc(LPTR, MAX_NAME_SIZE);
|
|
|
|
//
|
|
// get the wait timeout value
|
|
//
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( m_hResource,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES,
|
|
NULL,
|
|
0,
|
|
pPropList,
|
|
cPropListAlloc,
|
|
&cPropListSize);
|
|
//
|
|
// Reallocation routine if pPropList is too small
|
|
//
|
|
if ( dwError == ERROR_MORE_DATA )
|
|
{
|
|
LocalFree( pPropList );
|
|
|
|
cPropListAlloc = cPropListSize;
|
|
|
|
pPropList = (PCLUSPROP_LIST) LocalAlloc( LPTR, cPropListAlloc );
|
|
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( m_hResource,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES,
|
|
NULL,
|
|
0,
|
|
pPropList,
|
|
cPropListAlloc,
|
|
&cPropListSize);
|
|
}
|
|
|
|
//
|
|
// find the pending timeout property
|
|
//
|
|
dwError = ((RESUTILSFINDDWORDPROPERTY) g_ResUtilsDLL[RESUTILS_FIND_DWORD_PROPERTY])(pPropList,
|
|
cPropListSize,
|
|
_T("PendingTimeout"),
|
|
&dwPendingTimeout);
|
|
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
m_dwWaitPeriod = dwPendingTimeout;
|
|
}
|
|
|
|
LocalFree( pPropList );
|
|
}
|
|
|
|
BOOL
|
|
CServiceCtrlDlg::CheckForError(SERVICE_STATUS * pServiceStats)
|
|
{
|
|
BOOL fError = FALSE;
|
|
|
|
DWORD dwTickCurrent = GetTickCount();
|
|
|
|
if (pServiceStats->dwCheckPoint == 0)
|
|
{
|
|
// the service is in some state, not pending anything.
|
|
// before calling this function the code should check to see if
|
|
// the service is in the correct state. This means it is in
|
|
// some unexpected state.
|
|
fError = TRUE;
|
|
}
|
|
else
|
|
if ((dwTickCurrent - m_dwTickBegin) > m_dwWaitPeriod)
|
|
{
|
|
// ok to check the dwCheckPoint field to see if
|
|
// everything is going ok
|
|
if (m_dwLastCheckPoint == -1)
|
|
{
|
|
m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
|
|
}
|
|
else
|
|
{
|
|
if (m_dwLastCheckPoint >= pServiceStats->dwCheckPoint)
|
|
{
|
|
fError = TRUE;
|
|
}
|
|
}
|
|
|
|
m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
|
|
m_dwTickBegin = dwTickCurrent;
|
|
m_dwWaitPeriod = pServiceStats->dwWaitHint;
|
|
}
|
|
|
|
return fError;
|
|
}
|
|
|
|
BOOL
|
|
CServiceCtrlDlg::CheckForClusterError(SERVICE_STATUS * pServiceStats)
|
|
{
|
|
BOOL fError = FALSE;
|
|
|
|
DWORD dwTickCurrent = GetTickCount();
|
|
|
|
if ((dwTickCurrent - m_dwTickBegin) > m_dwWaitPeriod)
|
|
{
|
|
// ok to check the dwCheckPoint field to see if
|
|
// everything is going ok
|
|
if (m_dwLastCheckPoint == -1)
|
|
{
|
|
m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
|
|
}
|
|
else
|
|
{
|
|
if (m_dwLastCheckPoint >= pServiceStats->dwCheckPoint)
|
|
{
|
|
fError = TRUE;
|
|
}
|
|
}
|
|
|
|
m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
|
|
m_dwTickBegin = dwTickCurrent;
|
|
m_dwWaitPeriod = pServiceStats->dwWaitHint;
|
|
}
|
|
|
|
return fError;
|
|
}
|
|
|
|
void
|
|
CServiceCtrlDlg::UpdateIndicator()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
if (m_nTotalTickCount % (1000 / TIMER_FREQ) == 0)
|
|
{
|
|
int nTempTickCount = m_nTotalTickCount / (1000 / TIMER_FREQ);
|
|
HICON hIcon;
|
|
|
|
hIcon = AfxGetApp()->LoadIcon(IDI_PROGRESS_ICON_0 + (nTempTickCount % PROGRESS_ICON_COUNT));
|
|
m_iconProgress.SetIcon(hIcon);
|
|
}
|
|
|
|
m_nTotalTickCount++;
|
|
}
|
|
|
|
void
|
|
CServiceCtrlDlg::CheckService()
|
|
{
|
|
SERVICE_STATUS serviceStatus;
|
|
|
|
::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
|
|
|
|
if (!QueryServiceStatus(m_hService, &serviceStatus))
|
|
{
|
|
//
|
|
// Either an error occurred retrieving the
|
|
// service status OR the service is returning
|
|
// bogus state information.
|
|
//
|
|
CDialog::OnOK();
|
|
}
|
|
|
|
// If the dwCheckpoint value is 0, then there is no start/stop/pause
|
|
// or continue action pending (in which case we can exit no matter
|
|
// what happened).
|
|
|
|
if (m_bStart)
|
|
{
|
|
if (serviceStatus.dwCurrentState == SERVICE_RUNNING)
|
|
{
|
|
//
|
|
// The operation is complete.
|
|
//
|
|
CDialog::OnOK();
|
|
}
|
|
else
|
|
{
|
|
if (CheckForError(&serviceStatus))
|
|
{
|
|
// Something failed. Report an error.
|
|
CString strTemp;
|
|
|
|
// Kill the timer so that we don't get any messages
|
|
// while the message box is up.
|
|
if (m_timerId)
|
|
KillTimer(m_timerId);
|
|
|
|
AfxFormatString2(strTemp, IDS_ERR_STARTING_SERVICE,
|
|
m_strServerName,
|
|
m_strServiceDesc);
|
|
AfxMessageBox(strTemp);
|
|
|
|
if (serviceStatus.dwWin32ExitCode)
|
|
m_dwErr = serviceStatus.dwWin32ExitCode;
|
|
else
|
|
m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
|
|
{
|
|
//
|
|
// The operation is complete.
|
|
//
|
|
CDialog::OnOK();
|
|
}
|
|
else
|
|
{
|
|
if (CheckForError(&serviceStatus))
|
|
{
|
|
// Something failed. Report an error.
|
|
CString strTemp;
|
|
|
|
// Kill the timer so that we don't get any messages
|
|
// while the message box is up.
|
|
if (m_timerId)
|
|
KillTimer(m_timerId);
|
|
|
|
AfxFormatString2(strTemp, IDS_ERR_STOPPING_SERVICE,
|
|
m_strServerName,
|
|
m_strServiceDesc);
|
|
AfxMessageBox(strTemp);
|
|
|
|
if (serviceStatus.dwWin32ExitCode)
|
|
m_dwErr = serviceStatus.dwWin32ExitCode;
|
|
else
|
|
m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CServiceCtrlDlg::CheckClusterService()
|
|
{
|
|
SERVICE_STATUS serviceStatus = {0};
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
CLUSTER_RESOURCE_STATE crs;
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return;
|
|
|
|
// Check the state before we check the notification port.
|
|
crs = ((GETCLUSTERRESOURCESTATE) g_ClusDLL[CLUS_GET_CLUSTER_RESOURCE_STATE])( m_hResource, NULL, NULL, NULL, NULL );
|
|
|
|
if (crs == ClusterResourceStateUnknown)
|
|
{
|
|
// get cluster resource state failed
|
|
m_dwErr = GetLastError();
|
|
CDialog::OnOK();
|
|
}
|
|
|
|
|
|
if (m_bStart)
|
|
{
|
|
if (crs == ClusterResourceOnline)
|
|
{
|
|
//
|
|
// The operation is complete.
|
|
//
|
|
CDialog::OnOK();
|
|
}
|
|
else
|
|
if (crs == ClusterResourceFailed)
|
|
{
|
|
//
|
|
// resource failed to start. now error code available
|
|
//
|
|
m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
else
|
|
{
|
|
Assert(crs == ClusterResourcePending ||
|
|
crs == ClusterResourceOnlinePending);
|
|
|
|
if (CheckForClusterError(&serviceStatus))
|
|
{
|
|
// Something failed. Report an error.
|
|
CString strTemp;
|
|
|
|
// Kill the timer so that we don't get any messages
|
|
// while the message box is up.
|
|
if (m_timerId)
|
|
KillTimer(m_timerId);
|
|
|
|
AfxFormatString2(strTemp, IDS_ERR_STARTING_SERVICE,
|
|
m_strServerName,
|
|
m_strServiceDesc);
|
|
AfxMessageBox(strTemp);
|
|
|
|
if (serviceStatus.dwWin32ExitCode)
|
|
m_dwErr = serviceStatus.dwWin32ExitCode;
|
|
else
|
|
m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (crs == ClusterResourceOffline)
|
|
{
|
|
//
|
|
// The operation is complete.
|
|
//
|
|
CDialog::OnOK();
|
|
}
|
|
if (crs == ClusterResourceFailed)
|
|
{
|
|
//
|
|
// resource failed to start. now error code available
|
|
//
|
|
m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
else
|
|
{
|
|
Assert(crs == ClusterResourcePending ||
|
|
crs == ClusterResourceOfflinePending);
|
|
|
|
if (CheckForClusterError(&serviceStatus))
|
|
{
|
|
// Something failed. Report an error.
|
|
CString strTemp;
|
|
|
|
// Kill the timer so that we don't get any messages
|
|
// while the message box is up.
|
|
if (m_timerId)
|
|
KillTimer(m_timerId);
|
|
|
|
AfxFormatString2(strTemp, IDS_ERR_STOPPING_SERVICE,
|
|
m_strServerName,
|
|
m_strServiceDesc);
|
|
AfxMessageBox(strTemp);
|
|
|
|
if (serviceStatus.dwWin32ExitCode)
|
|
m_dwErr = serviceStatus.dwWin32ExitCode;
|
|
else
|
|
m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWaitDlg dialog
|
|
|
|
|
|
CWaitDlg::CWaitDlg
|
|
(
|
|
LPCTSTR pServerName,
|
|
LPCTSTR pszText,
|
|
LPCTSTR pszTitle,
|
|
CWnd* pParent /*=NULL*/
|
|
)
|
|
: CDialog(CWaitDlg::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(CWaitDlg)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_nTickCounter = TIMER_MULT;
|
|
m_nTotalTickCount = 0;
|
|
m_strServerName = pServerName;
|
|
m_strServerName.MakeUpper();
|
|
m_strText = pszText;
|
|
m_strTitle = pszTitle;
|
|
m_timerId = 0;
|
|
}
|
|
|
|
|
|
void CWaitDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CWaitDlg)
|
|
DDX_Control(pDX, IDC_STATIC_MESSAGE, m_staticMessage);
|
|
DDX_Control(pDX, IDC_ICON_PROGRESS, m_iconProgress);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CWaitDlg, CDialog)
|
|
//{{AFX_MSG_MAP(CWaitDlg)
|
|
ON_WM_TIMER()
|
|
ON_WM_CLOSE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CWaitDlg message handlers
|
|
|
|
BOOL CWaitDlg::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
m_timerId = SetTimer(TIMER_ID, TIMER_FREQ, NULL);
|
|
|
|
m_staticMessage.SetWindowText(m_strText);
|
|
|
|
SetWindowText(m_strTitle);
|
|
|
|
UpdateIndicator();
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
void CWaitDlg::OnClose()
|
|
{
|
|
CloseTimer();
|
|
CDialog::OnClose();
|
|
}
|
|
|
|
|
|
void CWaitDlg::CloseTimer()
|
|
{
|
|
if (m_timerId)
|
|
KillTimer(m_timerId);
|
|
m_timerId = 0;
|
|
}
|
|
|
|
void CWaitDlg::OnTimer(UINT nIDEvent)
|
|
{
|
|
//
|
|
// Bag-out if it's not our timer.
|
|
//
|
|
if(nIDEvent != TIMER_ID)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Advance the progress indicator.
|
|
//
|
|
UpdateIndicator();
|
|
|
|
//
|
|
// No need to continue if we're just amusing the user.
|
|
//
|
|
if(--m_nTickCounter > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_nTickCounter = TIMER_MULT;
|
|
|
|
// check here to see if we can exit out
|
|
OnTimerTick();
|
|
}
|
|
|
|
void
|
|
CWaitDlg::UpdateIndicator()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
if (m_nTotalTickCount % (1000 / TIMER_FREQ) == 0)
|
|
{
|
|
int nTempTickCount = m_nTotalTickCount / (1000 / TIMER_FREQ);
|
|
HICON hIcon;
|
|
|
|
hIcon = AfxGetApp()->LoadIcon(IDI_PROGRESS_ICON_0 + (nTempTickCount % PROGRESS_ICON_COUNT));
|
|
m_iconProgress.SetIcon(hIcon);
|
|
}
|
|
|
|
m_nTotalTickCount++;
|
|
}
|
|
|
|
|