Leaked source code of windows server 2003
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

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. svcctrl.cpp
  7. Implementation for the dialog that pops up while waiting
  8. for the server to start.
  9. FILE HISTORY:
  10. */
  11. #include "stdafx.h"
  12. #include "cluster.h"
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CServiceCtrlDlg dialog
  20. CServiceCtrlDlg::CServiceCtrlDlg
  21. (
  22. SC_HANDLE hService,
  23. LPCTSTR pServerName,
  24. LPCTSTR pszServiceDesc,
  25. BOOL bStart,
  26. CWnd* pParent /*=NULL*/
  27. )
  28. : CDialog(CServiceCtrlDlg::IDD, pParent)
  29. {
  30. //{{AFX_DATA_INIT(CServiceCtrlDlg)
  31. // NOTE: the ClassWizard will add member initialization here
  32. //}}AFX_DATA_INIT
  33. m_hService = hService;
  34. m_hResource = NULL;
  35. m_nTickCounter = TIMER_MULT;
  36. m_nTotalTickCount = 0;
  37. m_strServerName = pServerName;
  38. m_strServerName.MakeUpper();
  39. m_strServiceDesc = pszServiceDesc;
  40. m_bStart = bStart;
  41. m_timerId = 0;
  42. m_dwErr = 0;
  43. m_dwLastCheckPoint = -1;
  44. }
  45. CServiceCtrlDlg::CServiceCtrlDlg
  46. (
  47. HRESOURCE hResource,
  48. LPCTSTR pServerName,
  49. LPCTSTR pszServiceDesc,
  50. BOOL bStart,
  51. CWnd* pParent /*=NULL*/
  52. )
  53. : CDialog(CServiceCtrlDlg::IDD, pParent)
  54. {
  55. //{{AFX_DATA_INIT(CServiceCtrlDlg)
  56. // NOTE: the ClassWizard will add member initialization here
  57. //}}AFX_DATA_INIT
  58. m_hService = NULL;
  59. m_hResource = hResource;
  60. m_nTickCounter = TIMER_MULT;
  61. m_nTotalTickCount = 0;
  62. m_strServerName = pServerName;
  63. m_strServerName.MakeUpper();
  64. m_strServiceDesc = pszServiceDesc;
  65. m_bStart = bStart;
  66. m_timerId = 0;
  67. m_dwErr = 0;
  68. m_dwLastCheckPoint = -1;
  69. }
  70. void CServiceCtrlDlg::DoDataExchange(CDataExchange* pDX)
  71. {
  72. CDialog::DoDataExchange(pDX);
  73. //{{AFX_DATA_MAP(CServiceCtrlDlg)
  74. DDX_Control(pDX, IDC_STATIC_MESSAGE, m_staticMessage);
  75. DDX_Control(pDX, IDC_ICON_PROGRESS, m_iconProgress);
  76. //}}AFX_DATA_MAP
  77. }
  78. BEGIN_MESSAGE_MAP(CServiceCtrlDlg, CDialog)
  79. //{{AFX_MSG_MAP(CServiceCtrlDlg)
  80. ON_WM_TIMER()
  81. ON_WM_CLOSE()
  82. //}}AFX_MSG_MAP
  83. END_MESSAGE_MAP()
  84. /////////////////////////////////////////////////////////////////////////////
  85. // CServiceCtrlDlg message handlers
  86. BOOL CServiceCtrlDlg::OnInitDialog()
  87. {
  88. CDialog::OnInitDialog();
  89. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  90. m_timerId = SetTimer(TIMER_ID, TIMER_FREQ, NULL);
  91. CString strTemp;
  92. CString strTitle;
  93. UINT idsTitle;
  94. if (m_bStart)
  95. {
  96. AfxFormatString2(strTemp, IDS_STARTING_SERVICE_NOW, m_strServerName,
  97. m_strServiceDesc);
  98. idsTitle = IDS_START_SERVICE_TITLE;
  99. }
  100. else
  101. {
  102. AfxFormatString2(strTemp, IDS_STOPPING_SERVICE_NOW, m_strServerName,
  103. m_strServiceDesc);
  104. idsTitle = IDS_STOP_SERVICE_TITLE;
  105. }
  106. m_staticMessage.SetWindowText(strTemp);
  107. // Setup the title of the window
  108. strTitle.Format(idsTitle, (LPCTSTR) m_strServiceDesc);
  109. SetWindowText(strTitle);
  110. UpdateIndicator();
  111. m_dwTickBegin = GetTickCount();
  112. if (m_hService)
  113. {
  114. // get the wait period
  115. SERVICE_STATUS serviceStatus;
  116. ::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
  117. if (QueryServiceStatus(m_hService, &serviceStatus))
  118. {
  119. m_dwWaitPeriod = serviceStatus.dwWaitHint;
  120. }
  121. }
  122. else
  123. {
  124. GetClusterResourceTimeout();
  125. }
  126. return TRUE; // return TRUE unless you set the focus to a control
  127. // EXCEPTION: OCX Property Pages should return FALSE
  128. }
  129. void CServiceCtrlDlg::OnClose()
  130. {
  131. if (m_timerId)
  132. KillTimer(m_timerId);
  133. CDialog::OnClose();
  134. }
  135. void CServiceCtrlDlg::OnTimer(UINT nIDEvent)
  136. {
  137. //
  138. // Bag-out if it's not our timer.
  139. //
  140. if(nIDEvent != TIMER_ID)
  141. {
  142. return;
  143. }
  144. //
  145. // Advance the progress indicator.
  146. //
  147. UpdateIndicator();
  148. //
  149. // No need to continue if we're just amusing the user.
  150. //
  151. if(--m_nTickCounter > 0)
  152. {
  153. return;
  154. }
  155. m_nTickCounter = TIMER_MULT;
  156. //
  157. // Poll the service to see if the operation is
  158. // either complete or continuing as expected.
  159. //
  160. if (m_hService)
  161. {
  162. CheckService();
  163. }
  164. else
  165. {
  166. CheckClusterService();
  167. }
  168. }
  169. void
  170. CServiceCtrlDlg::GetClusterResourceTimeout()
  171. {
  172. DWORD dwError = 0;
  173. DWORD cPropListSize = 0;
  174. DWORD cPropListAlloc = MAX_NAME_SIZE;
  175. DWORD dwPendingTimeout = 0;
  176. // set the default
  177. m_dwWaitPeriod = 18000;
  178. if ( !g_ClusDLL.LoadFunctionPointers() )
  179. return;
  180. if ( !g_ResUtilsDLL.LoadFunctionPointers() )
  181. return;
  182. PCLUSPROP_LIST pPropList = (PCLUSPROP_LIST)LocalAlloc(LPTR, MAX_NAME_SIZE);
  183. //
  184. // get the wait timeout value
  185. //
  186. dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( m_hResource,
  187. NULL,
  188. CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES,
  189. NULL,
  190. 0,
  191. pPropList,
  192. cPropListAlloc,
  193. &cPropListSize);
  194. //
  195. // Reallocation routine if pPropList is too small
  196. //
  197. if ( dwError == ERROR_MORE_DATA )
  198. {
  199. LocalFree( pPropList );
  200. cPropListAlloc = cPropListSize;
  201. pPropList = (PCLUSPROP_LIST) LocalAlloc( LPTR, cPropListAlloc );
  202. dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( m_hResource,
  203. NULL,
  204. CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES,
  205. NULL,
  206. 0,
  207. pPropList,
  208. cPropListAlloc,
  209. &cPropListSize);
  210. }
  211. //
  212. // find the pending timeout property
  213. //
  214. dwError = ((RESUTILSFINDDWORDPROPERTY) g_ResUtilsDLL[RESUTILS_FIND_DWORD_PROPERTY])(pPropList,
  215. cPropListSize,
  216. _T("PendingTimeout"),
  217. &dwPendingTimeout);
  218. if (dwError == ERROR_SUCCESS)
  219. {
  220. m_dwWaitPeriod = dwPendingTimeout;
  221. }
  222. LocalFree( pPropList );
  223. }
  224. BOOL
  225. CServiceCtrlDlg::CheckForError(SERVICE_STATUS * pServiceStats)
  226. {
  227. BOOL fError = FALSE;
  228. DWORD dwTickCurrent = GetTickCount();
  229. if (pServiceStats->dwCheckPoint == 0)
  230. {
  231. // the service is in some state, not pending anything.
  232. // before calling this function the code should check to see if
  233. // the service is in the correct state. This means it is in
  234. // some unexpected state.
  235. fError = TRUE;
  236. }
  237. else
  238. if ((dwTickCurrent - m_dwTickBegin) > m_dwWaitPeriod)
  239. {
  240. // ok to check the dwCheckPoint field to see if
  241. // everything is going ok
  242. if (m_dwLastCheckPoint == -1)
  243. {
  244. m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
  245. }
  246. else
  247. {
  248. if (m_dwLastCheckPoint >= pServiceStats->dwCheckPoint)
  249. {
  250. fError = TRUE;
  251. }
  252. }
  253. m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
  254. m_dwTickBegin = dwTickCurrent;
  255. m_dwWaitPeriod = pServiceStats->dwWaitHint;
  256. }
  257. return fError;
  258. }
  259. BOOL
  260. CServiceCtrlDlg::CheckForClusterError(SERVICE_STATUS * pServiceStats)
  261. {
  262. BOOL fError = FALSE;
  263. DWORD dwTickCurrent = GetTickCount();
  264. if ((dwTickCurrent - m_dwTickBegin) > m_dwWaitPeriod)
  265. {
  266. // ok to check the dwCheckPoint field to see if
  267. // everything is going ok
  268. if (m_dwLastCheckPoint == -1)
  269. {
  270. m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
  271. }
  272. else
  273. {
  274. if (m_dwLastCheckPoint >= pServiceStats->dwCheckPoint)
  275. {
  276. fError = TRUE;
  277. }
  278. }
  279. m_dwLastCheckPoint = pServiceStats->dwCheckPoint;
  280. m_dwTickBegin = dwTickCurrent;
  281. m_dwWaitPeriod = pServiceStats->dwWaitHint;
  282. }
  283. return fError;
  284. }
  285. void
  286. CServiceCtrlDlg::UpdateIndicator()
  287. {
  288. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  289. if (m_nTotalTickCount % (1000 / TIMER_FREQ) == 0)
  290. {
  291. int nTempTickCount = m_nTotalTickCount / (1000 / TIMER_FREQ);
  292. HICON hIcon;
  293. hIcon = AfxGetApp()->LoadIcon(IDI_PROGRESS_ICON_0 + (nTempTickCount % PROGRESS_ICON_COUNT));
  294. m_iconProgress.SetIcon(hIcon);
  295. }
  296. m_nTotalTickCount++;
  297. }
  298. void
  299. CServiceCtrlDlg::CheckService()
  300. {
  301. SERVICE_STATUS serviceStatus;
  302. ::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
  303. if (!QueryServiceStatus(m_hService, &serviceStatus))
  304. {
  305. //
  306. // Either an error occurred retrieving the
  307. // service status OR the service is returning
  308. // bogus state information.
  309. //
  310. CDialog::OnOK();
  311. }
  312. // If the dwCheckpoint value is 0, then there is no start/stop/pause
  313. // or continue action pending (in which case we can exit no matter
  314. // what happened).
  315. if (m_bStart)
  316. {
  317. if (serviceStatus.dwCurrentState == SERVICE_RUNNING)
  318. {
  319. //
  320. // The operation is complete.
  321. //
  322. CDialog::OnOK();
  323. }
  324. else
  325. {
  326. if (CheckForError(&serviceStatus))
  327. {
  328. // Something failed. Report an error.
  329. CString strTemp;
  330. // Kill the timer so that we don't get any messages
  331. // while the message box is up.
  332. if (m_timerId)
  333. KillTimer(m_timerId);
  334. AfxFormatString2(strTemp, IDS_ERR_STARTING_SERVICE,
  335. m_strServerName,
  336. m_strServiceDesc);
  337. AfxMessageBox(strTemp);
  338. if (serviceStatus.dwWin32ExitCode)
  339. m_dwErr = serviceStatus.dwWin32ExitCode;
  340. else
  341. m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  342. CDialog::OnOK();
  343. }
  344. }
  345. }
  346. else
  347. {
  348. if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
  349. {
  350. //
  351. // The operation is complete.
  352. //
  353. CDialog::OnOK();
  354. }
  355. else
  356. {
  357. if (CheckForError(&serviceStatus))
  358. {
  359. // Something failed. Report an error.
  360. CString strTemp;
  361. // Kill the timer so that we don't get any messages
  362. // while the message box is up.
  363. if (m_timerId)
  364. KillTimer(m_timerId);
  365. AfxFormatString2(strTemp, IDS_ERR_STOPPING_SERVICE,
  366. m_strServerName,
  367. m_strServiceDesc);
  368. AfxMessageBox(strTemp);
  369. if (serviceStatus.dwWin32ExitCode)
  370. m_dwErr = serviceStatus.dwWin32ExitCode;
  371. else
  372. m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  373. CDialog::OnOK();
  374. }
  375. }
  376. }
  377. }
  378. void
  379. CServiceCtrlDlg::CheckClusterService()
  380. {
  381. SERVICE_STATUS serviceStatus = {0};
  382. DWORD dwError = ERROR_SUCCESS;
  383. CLUSTER_RESOURCE_STATE crs;
  384. if ( !g_ClusDLL.LoadFunctionPointers() )
  385. return;
  386. // Check the state before we check the notification port.
  387. crs = ((GETCLUSTERRESOURCESTATE) g_ClusDLL[CLUS_GET_CLUSTER_RESOURCE_STATE])( m_hResource, NULL, NULL, NULL, NULL );
  388. if (crs == ClusterResourceStateUnknown)
  389. {
  390. // get cluster resource state failed
  391. m_dwErr = GetLastError();
  392. CDialog::OnOK();
  393. }
  394. if (m_bStart)
  395. {
  396. if (crs == ClusterResourceOnline)
  397. {
  398. //
  399. // The operation is complete.
  400. //
  401. CDialog::OnOK();
  402. }
  403. else
  404. if (crs == ClusterResourceFailed)
  405. {
  406. //
  407. // resource failed to start. now error code available
  408. //
  409. m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  410. CDialog::OnOK();
  411. }
  412. else
  413. {
  414. Assert(crs == ClusterResourcePending ||
  415. crs == ClusterResourceOnlinePending);
  416. if (CheckForClusterError(&serviceStatus))
  417. {
  418. // Something failed. Report an error.
  419. CString strTemp;
  420. // Kill the timer so that we don't get any messages
  421. // while the message box is up.
  422. if (m_timerId)
  423. KillTimer(m_timerId);
  424. AfxFormatString2(strTemp, IDS_ERR_STARTING_SERVICE,
  425. m_strServerName,
  426. m_strServiceDesc);
  427. AfxMessageBox(strTemp);
  428. if (serviceStatus.dwWin32ExitCode)
  429. m_dwErr = serviceStatus.dwWin32ExitCode;
  430. else
  431. m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  432. CDialog::OnOK();
  433. }
  434. }
  435. }
  436. else
  437. {
  438. if (crs == ClusterResourceOffline)
  439. {
  440. //
  441. // The operation is complete.
  442. //
  443. CDialog::OnOK();
  444. }
  445. if (crs == ClusterResourceFailed)
  446. {
  447. //
  448. // resource failed to start. now error code available
  449. //
  450. m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  451. CDialog::OnOK();
  452. }
  453. else
  454. {
  455. Assert(crs == ClusterResourcePending ||
  456. crs == ClusterResourceOfflinePending);
  457. if (CheckForClusterError(&serviceStatus))
  458. {
  459. // Something failed. Report an error.
  460. CString strTemp;
  461. // Kill the timer so that we don't get any messages
  462. // while the message box is up.
  463. if (m_timerId)
  464. KillTimer(m_timerId);
  465. AfxFormatString2(strTemp, IDS_ERR_STOPPING_SERVICE,
  466. m_strServerName,
  467. m_strServiceDesc);
  468. AfxMessageBox(strTemp);
  469. if (serviceStatus.dwWin32ExitCode)
  470. m_dwErr = serviceStatus.dwWin32ExitCode;
  471. else
  472. m_dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  473. CDialog::OnOK();
  474. }
  475. }
  476. }
  477. }
  478. /////////////////////////////////////////////////////////////////////////////
  479. // CWaitDlg dialog
  480. CWaitDlg::CWaitDlg
  481. (
  482. LPCTSTR pServerName,
  483. LPCTSTR pszText,
  484. LPCTSTR pszTitle,
  485. CWnd* pParent /*=NULL*/
  486. )
  487. : CDialog(CWaitDlg::IDD, pParent)
  488. {
  489. //{{AFX_DATA_INIT(CWaitDlg)
  490. // NOTE: the ClassWizard will add member initialization here
  491. //}}AFX_DATA_INIT
  492. m_nTickCounter = TIMER_MULT;
  493. m_nTotalTickCount = 0;
  494. m_strServerName = pServerName;
  495. m_strServerName.MakeUpper();
  496. m_strText = pszText;
  497. m_strTitle = pszTitle;
  498. m_timerId = 0;
  499. }
  500. void CWaitDlg::DoDataExchange(CDataExchange* pDX)
  501. {
  502. CDialog::DoDataExchange(pDX);
  503. //{{AFX_DATA_MAP(CWaitDlg)
  504. DDX_Control(pDX, IDC_STATIC_MESSAGE, m_staticMessage);
  505. DDX_Control(pDX, IDC_ICON_PROGRESS, m_iconProgress);
  506. //}}AFX_DATA_MAP
  507. }
  508. BEGIN_MESSAGE_MAP(CWaitDlg, CDialog)
  509. //{{AFX_MSG_MAP(CWaitDlg)
  510. ON_WM_TIMER()
  511. ON_WM_CLOSE()
  512. //}}AFX_MSG_MAP
  513. END_MESSAGE_MAP()
  514. /////////////////////////////////////////////////////////////////////////////
  515. // CWaitDlg message handlers
  516. BOOL CWaitDlg::OnInitDialog()
  517. {
  518. CDialog::OnInitDialog();
  519. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  520. m_timerId = SetTimer(TIMER_ID, TIMER_FREQ, NULL);
  521. m_staticMessage.SetWindowText(m_strText);
  522. SetWindowText(m_strTitle);
  523. UpdateIndicator();
  524. return TRUE; // return TRUE unless you set the focus to a control
  525. // EXCEPTION: OCX Property Pages should return FALSE
  526. }
  527. void CWaitDlg::OnClose()
  528. {
  529. CloseTimer();
  530. CDialog::OnClose();
  531. }
  532. void CWaitDlg::CloseTimer()
  533. {
  534. if (m_timerId)
  535. KillTimer(m_timerId);
  536. m_timerId = 0;
  537. }
  538. void CWaitDlg::OnTimer(UINT nIDEvent)
  539. {
  540. //
  541. // Bag-out if it's not our timer.
  542. //
  543. if(nIDEvent != TIMER_ID)
  544. {
  545. return;
  546. }
  547. //
  548. // Advance the progress indicator.
  549. //
  550. UpdateIndicator();
  551. //
  552. // No need to continue if we're just amusing the user.
  553. //
  554. if(--m_nTickCounter > 0)
  555. {
  556. return;
  557. }
  558. m_nTickCounter = TIMER_MULT;
  559. // check here to see if we can exit out
  560. OnTimerTick();
  561. }
  562. void
  563. CWaitDlg::UpdateIndicator()
  564. {
  565. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  566. if (m_nTotalTickCount % (1000 / TIMER_FREQ) == 0)
  567. {
  568. int nTempTickCount = m_nTotalTickCount / (1000 / TIMER_FREQ);
  569. HICON hIcon;
  570. hIcon = AfxGetApp()->LoadIcon(IDI_PROGRESS_ICON_0 + (nTempTickCount % PROGRESS_ICON_COUNT));
  571. m_iconProgress.SetIcon(hIcon);
  572. }
  573. m_nTotalTickCount++;
  574. }