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.

849 lines
15 KiB

  1. /*++
  2. Copyright (c) 1994-2001 Microsoft Corporation
  3. Module Name :
  4. shutdown.cpp
  5. Abstract:
  6. IIS Shutdown/restart dialog
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. --*/
  14. #include "stdafx.h"
  15. #include "common.h"
  16. #include "InetMgrApp.h"
  17. #include "iisobj.h"
  18. #include "shutdown.h"
  19. //
  20. // Shutdown in milliseconds
  21. //
  22. #define IIS_SHUTDOWN_TIMEOUT 300000L
  23. #ifdef _DEBUG
  24. #define new DEBUG_NEW
  25. #undef THIS_FILE
  26. static char THIS_FILE[] = __FILE__;
  27. #endif
  28. CRITICAL_SECTION gcs;
  29. UINT
  30. __cdecl
  31. StopIISServices(
  32. IN LPVOID pParam
  33. )
  34. /*++
  35. Routine Description:
  36. Worker thread to perform IIS Service Control Command
  37. Arguments:
  38. LPVOID * pParam : Casts to IISCOMMAND (see above)
  39. Return Value:
  40. UINT
  41. --*/
  42. {
  43. IISCOMMAND * pCmd = (IISCOMMAND *)pParam;
  44. //
  45. // This thread needs its own CoInitialize
  46. //
  47. CError err(CoInitialize(NULL));
  48. ASSERT_PTR(pCmd->pMachine);
  49. CIISSvcControl isc(pCmd->pMachine->QueryAuthInfo());
  50. err = isc.QueryResult();
  51. //
  52. // Block access to pCmd since the main thread will try to
  53. // delete it.
  54. //
  55. EnterCriticalSection(&gcs);
  56. if (err.Succeeded())
  57. {
  58. err = isc.Stop(IIS_SHUTDOWN_TIMEOUT, TRUE);
  59. }
  60. //
  61. // Clean Up, returning the error code
  62. //
  63. EnterCriticalSection(&pCmd->cs);
  64. pCmd->fFinished = TRUE;
  65. pCmd->hReturn = err;
  66. LeaveCriticalSection(&pCmd->cs);
  67. LeaveCriticalSection(&gcs);
  68. return 0;
  69. }
  70. //
  71. // Shutdown progress dialog
  72. //
  73. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  74. //
  75. // Timer ID and values
  76. //
  77. #define ID_TIMER (1)
  78. #define A_SECOND (1000L)
  79. CShutProgressDlg::CShutProgressDlg(IISCOMMAND * pCommand, BOOL bShowCancel)
  80. /*++
  81. Routine Description:
  82. Constructor for shutdown progress dialog
  83. Arguments:
  84. IISCOMMAND * pCommand : Command structure
  85. Return Value:
  86. N/A
  87. --*/
  88. : CDialog(CShutProgressDlg::IDD, pCommand->pParent),
  89. m_pCommand(pCommand),
  90. m_bShowCancel(bShowCancel),
  91. m_uTimeoutSec(pCommand->dwMilliseconds / A_SECOND)
  92. {
  93. //{{AFX_DATA_INIT(CShutProgressDlg)
  94. //}}AFX_DATA_INIT
  95. }
  96. void
  97. CShutProgressDlg::DoDataExchange(
  98. IN CDataExchange * pDX
  99. )
  100. /*++
  101. Routine Description:
  102. Initialise/Store control data
  103. Arguments:
  104. CDataExchange * pDX - DDX/DDV control structure
  105. Return Value:
  106. None
  107. --*/
  108. {
  109. CDialog::DoDataExchange(pDX);
  110. //{{AFX_DATA_MAP(CShutProgressDlg)
  111. DDX_Control(pDX, IDC_STATIC_PROGRESS, m_static_ProgressMsg);
  112. DDX_Control(pDX, IDC_PROGRESS_SHUTDOWN, m_prgShutdown);
  113. //}}AFX_DATA_MAP
  114. }
  115. //
  116. // Message Map
  117. //
  118. BEGIN_MESSAGE_MAP(CShutProgressDlg, CDialog)
  119. //{{AFX_MSG_MAP(CShutProgressDlg)
  120. ON_WM_TIMER()
  121. ON_WM_DESTROY()
  122. //}}AFX_MSG_MAP
  123. END_MESSAGE_MAP()
  124. //
  125. // Message Handlers
  126. //
  127. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  128. BOOL
  129. CShutProgressDlg::OnInitDialog()
  130. /*++
  131. Routine Description:
  132. WM_INITDIALOG handler. Initialize the dialog.
  133. Arguments:
  134. None.
  135. Return Value:
  136. TRUE if no focus is to be set automatically, FALSE if the focus
  137. is already set.
  138. --*/
  139. {
  140. CDialog::OnInitDialog();
  141. VERIFY(m_strProgress.LoadString(IDS_SHUTDOWN_PROGRESS));
  142. m_nProgress = 0;
  143. m_prgShutdown.SetRange32(0, m_uTimeoutSec);
  144. m_prgShutdown.SetPos(m_nProgress);
  145. m_prgShutdown.SetStep(1);
  146. if (!m_bShowCancel)
  147. {
  148. GetDlgItem(IDOK)->EnableWindow(FALSE);
  149. GetDlgItem(IDOK)->ShowWindow(SW_HIDE);
  150. GetDlgItem(IDC_STATIC_STATUS)->EnableWindow(FALSE);
  151. GetDlgItem(IDC_STATIC_STATUS)->ShowWindow(SW_HIDE);
  152. }
  153. //
  154. // Start the progress bar ticking, once per second.
  155. //
  156. UINT_PTR nID = SetTimer(ID_TIMER, A_SECOND, NULL);
  157. if (nID != ID_TIMER)
  158. {
  159. //
  160. // Failed to create the timer. Pop up an error, and
  161. // cancel the dialog.
  162. //
  163. CError err(ERROR_NO_SYSTEM_RESOURCES);
  164. err.MessageBox(m_hWnd);
  165. EndDialog(IDCANCEL);
  166. }
  167. return TRUE;
  168. }
  169. void
  170. CShutProgressDlg::OnTimer(
  171. IN UINT nIDEvent
  172. )
  173. /*++
  174. Routine Description:
  175. Timer handler. Upgrade the progressbar with another second on the clock
  176. Arguments:
  177. UINT nIDEvent : Timer id
  178. Return Value:
  179. None
  180. --*/
  181. {
  182. ASSERT(nIDEvent == ID_TIMER);
  183. m_prgShutdown.SetPos(++m_nProgress);
  184. //
  185. // Display progress on the tick marker
  186. //
  187. CString str;
  188. str.Format(m_strProgress, m_uTimeoutSec - (UINT)m_nProgress + 1);
  189. m_static_ProgressMsg.SetWindowText(str);
  190. //
  191. // Check to see if the stop thread has finished its action already
  192. //
  193. BOOL fFinished;
  194. EnterCriticalSection(&m_pCommand->cs);
  195. fFinished = m_pCommand->fFinished;
  196. LeaveCriticalSection(&m_pCommand->cs);
  197. if (fFinished)
  198. {
  199. //
  200. // The worker thread has finished, so there's no reason to
  201. // keep the user in suspense -- dismiss the dialog
  202. //
  203. EndDialog(IDCANCEL);
  204. }
  205. if ((UINT)m_nProgress > m_uTimeoutSec)
  206. {
  207. //
  208. // We've timed out -- tell the main thread to Kill!()
  209. //
  210. OnOK();
  211. }
  212. //
  213. // I doubt there's any default processing here, but anyway...
  214. //
  215. CDialog::OnTimer(nIDEvent);
  216. }
  217. void
  218. CShutProgressDlg::OnDestroy()
  219. /*++
  220. Routine Description:
  221. Handle dialog destruction, kill the timer.
  222. Arguments:
  223. None
  224. Return Value:
  225. None
  226. --*/
  227. {
  228. CDialog::OnDestroy();
  229. ::KillTimer(m_hWnd, (UINT_PTR)ID_TIMER);
  230. }
  231. void
  232. CShutProgressDlg::OnOK()
  233. /*++
  234. Routine Description:
  235. OK handler -- ok button maps to "Kill Now!"
  236. Arguments:
  237. None
  238. Return Value:
  239. None
  240. --*/
  241. {
  242. //
  243. // Kill!
  244. //
  245. EndDialog(IDOK);
  246. }
  247. void
  248. CShutProgressDlg::OnCancel()
  249. /*++
  250. Routine Description:
  251. Cancel button handler. This dialog cannot be cancelled, so the cancel
  252. notification is eaten.
  253. Arguments:
  254. None
  255. Return Value:
  256. None
  257. --*/
  258. {
  259. //
  260. // Eat cancel command (user pressed escape)
  261. //
  262. }
  263. //
  264. // Shutdown dialog
  265. //
  266. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  267. CIISShutdownDlg::CIISShutdownDlg(
  268. IN CIISMachine * pMachine,
  269. IN CWnd * pParent OPTIONAL
  270. )
  271. /*++
  272. Routine Description:
  273. Constructor
  274. Arguments:
  275. CIISMachine * pMachine : Machine object
  276. CWnd * pParent : Optional parent window
  277. Return Value:
  278. N/A
  279. --*/
  280. : CDialog(CIISShutdownDlg::IDD, pParent),
  281. m_fServicesRestarted(FALSE),
  282. m_pMachine(pMachine)
  283. {
  284. //{{AFX_DATA_INIT(CIISShutdownDlg)
  285. //}}AFX_DATA_INIT
  286. ASSERT_PTR(m_pMachine);
  287. }
  288. void
  289. CIISShutdownDlg::DoDataExchange(
  290. IN CDataExchange * pDX
  291. )
  292. /*++
  293. Routine Description:
  294. Initialise/Store control data
  295. Arguments:
  296. CDataExchange * pDX - DDX/DDV control structure
  297. Return Value:
  298. None
  299. --*/
  300. {
  301. CDialog::DoDataExchange(pDX);
  302. //{{AFX_DATA_MAP(CIISShutdownDlg)
  303. DDX_Control(pDX, IDC_COMBO_RESTART, m_combo_Restart);
  304. DDX_Control(pDX, IDC_STATIC_DETAILS, m_static_Details);
  305. //}}AFX_DATA_MAP
  306. }
  307. void
  308. CIISShutdownDlg::SetDetailsText()
  309. /*++
  310. Routine Description:
  311. Set the details text to correspond to what's in the combo box
  312. Arguments:
  313. None
  314. Return Value:
  315. None
  316. --*/
  317. {
  318. UINT nSel = m_combo_Restart.GetCurSel();
  319. // ASSERT(nSel >= 0 && nSel < NUM_ISC_ITEMS);
  320. m_static_Details.SetWindowText(m_strDetails[nSel]);
  321. }
  322. //
  323. // Message Map
  324. //
  325. BEGIN_MESSAGE_MAP(CIISShutdownDlg, CDialog)
  326. //{{AFX_MSG_MAP(CIISShutdownDlg)
  327. ON_CBN_SELCHANGE(IDC_COMBO_RESTART, OnSelchangeComboRestart)
  328. ON_CBN_DBLCLK(IDC_COMBO_RESTART, OnDblclkComboRestart)
  329. ON_BN_CLICKED(ID_HELP, OnHelp)
  330. //}}AFX_MSG_MAP
  331. END_MESSAGE_MAP()
  332. HRESULT
  333. CIISShutdownDlg::PerformCommand(int iCmd, BOOL bShowCancel)
  334. /*++
  335. Routine Description:
  336. Perform restart command
  337. Arguments:
  338. int iCmd - One of the following commands:
  339. ISC_START
  340. ISC_STOP
  341. ISC_SHUTDOWN
  342. ISC_RESTART
  343. Return Value:
  344. HRESULT
  345. --*/
  346. {
  347. //
  348. // Make sure the service is supported
  349. //
  350. ASSERT_PTR(m_pMachine);
  351. BeginWaitCursor();
  352. CIISSvcControl isc(m_pMachine->QueryAuthInfo());
  353. EndWaitCursor();
  354. CError err(isc.QueryResult());
  355. if (err.Failed())
  356. {
  357. return err;
  358. }
  359. //
  360. // Create command structure to hand off to
  361. // worker thread
  362. //
  363. IISCOMMAND * pCommand = new IISCOMMAND;
  364. if (!pCommand)
  365. {
  366. err = ERROR_NOT_ENOUGH_MEMORY;
  367. return err;
  368. }
  369. ::ZeroMemory(pCommand, sizeof(IISCOMMAND));
  370. pCommand->pMachine = m_pMachine;
  371. pCommand->dwMilliseconds = IIS_SHUTDOWN_TIMEOUT;
  372. pCommand->pParent = this;
  373. InitializeCriticalSection(&pCommand->cs);
  374. InitializeCriticalSection(&gcs);
  375. CShutProgressDlg dlg(pCommand, bShowCancel);
  376. CWinThread * pStopThread = NULL;
  377. BOOL fStartServices = FALSE;
  378. INT_PTR nReturn = IDCANCEL;
  379. //
  380. // Fire off the thread that does the actual work, while we
  381. // put up the progress UI
  382. //
  383. switch(iCmd)
  384. {
  385. case ISC_RESTART:
  386. ++fStartServices;
  387. //
  388. // Fall through...
  389. //
  390. case ISC_STOP:
  391. //
  392. // Stop the services in the workerthread
  393. //
  394. pStopThread = AfxBeginThread(&StopIISServices, pCommand);
  395. nReturn = dlg.DoModal();
  396. break;
  397. case ISC_START:
  398. ++fStartServices;
  399. break;
  400. case ISC_SHUTDOWN:
  401. BeginWaitCursor();
  402. err = isc.Reboot(IIS_SHUTDOWN_TIMEOUT, m_pMachine->IsLocal());
  403. EndWaitCursor();
  404. break;
  405. default:
  406. //
  407. // Internal error!
  408. //
  409. ASSERT_MSG("Invalid command code!");
  410. err = ERROR_INVALID_FUNCTION;
  411. }
  412. //
  413. // Determine if a kill is necessary (timed-out or user
  414. // pressed 'Kill')
  415. //
  416. BeginWaitCursor();
  417. if (nReturn == IDOK)
  418. {
  419. TRACEEOLID("Killing now!");
  420. err = isc.Kill();
  421. Sleep(1000L);
  422. }
  423. else
  424. {
  425. //
  426. // Waiting for the thread to finish
  427. //
  428. if (pStopThread != NULL)
  429. {
  430. BOOL fDone = FALSE;
  431. while(!fDone)
  432. {
  433. TRACEEOLID("Checking to see if thread has finished");
  434. EnterCriticalSection(&pCommand->cs);
  435. if (pCommand->fFinished)
  436. {
  437. err = pCommand->hReturn;
  438. ++fDone;
  439. }
  440. LeaveCriticalSection(&pCommand->cs);
  441. //
  442. // Pause a bit to catch our breath.
  443. //
  444. if (!fDone)
  445. {
  446. Sleep(500);
  447. }
  448. }
  449. }
  450. }
  451. //
  452. // Everything should be stopped, start it up again
  453. // if necessary.
  454. //
  455. if (err.Succeeded() && fStartServices)
  456. {
  457. err = isc.Start(IIS_SHUTDOWN_TIMEOUT);
  458. m_fServicesRestarted = err.Succeeded();
  459. }
  460. EndWaitCursor();
  461. //
  462. // Clean up when the worker thread says we can.
  463. //
  464. EnterCriticalSection(&gcs);
  465. DeleteCriticalSection(&pCommand->cs);
  466. delete pCommand;
  467. LeaveCriticalSection(&gcs);
  468. DeleteCriticalSection(&gcs);
  469. return err;
  470. }
  471. //
  472. // Message Handlers
  473. //
  474. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  475. BOOL
  476. CIISShutdownDlg::OnInitDialog()
  477. /*++
  478. Routine Description:
  479. WM_INITDIALOG handler. Initialize the dialog.
  480. Arguments:
  481. None.
  482. Return Value:
  483. TRUE if no focus is to be set automatically, FALSE if the focus
  484. is already set.
  485. --*/
  486. {
  487. CDialog::OnInitDialog();
  488. //
  489. // Load combobox text and details
  490. //
  491. CString strFmt, str;
  492. //
  493. // This may take a second or two...
  494. //
  495. BeginWaitCursor();
  496. CIISSvcControl isc(m_pMachine->QueryAuthInfo());
  497. EndWaitCursor();
  498. CError err(isc.QueryResult());
  499. if (err.Failed())
  500. {
  501. //
  502. // Failed to obtain interface -- quit now.
  503. //
  504. if (err.HResult() == REGDB_E_CLASSNOTREG
  505. || err.HResult() == CS_E_PACKAGE_NOTFOUND
  506. )
  507. {
  508. //
  509. // Friendly message about the interface not being supported.
  510. //
  511. DoHelpMessageBox(m_hWnd,IDS_ERR_NO_SHUTDOWN, MB_APPLMODAL | MB_OK | MB_ICONINFORMATION, 0);
  512. }
  513. else
  514. {
  515. m_pMachine->DisplayError(err, m_hWnd);
  516. }
  517. EndDialog(IDCANCEL);
  518. }
  519. UINT nOption = IDS_IIS_START;
  520. UINT nDetails = IDS_IIS_START_DETAILS;
  521. for (int i = ISC_START; i <= ISC_RESTART; ++i)
  522. {
  523. VERIFY(strFmt.LoadString(nOption++));
  524. str.Format(strFmt, m_pMachine->QueryServerName());
  525. VERIFY(m_strDetails[i].LoadString(nDetails++));
  526. m_combo_Restart.AddString(str);
  527. }
  528. m_combo_Restart.SetCurSel(ISC_RESTART);
  529. m_combo_Restart.SetFocus();
  530. SetDetailsText();
  531. return FALSE;
  532. }
  533. void
  534. CIISShutdownDlg::OnSelchangeComboRestart()
  535. /*++
  536. Routine Description:
  537. Selection change notification handler. Change the text in the details
  538. static text to reflect the new selection in the combo box
  539. Arguments:
  540. None
  541. Return Value:
  542. None
  543. --*/
  544. {
  545. SetDetailsText();
  546. }
  547. void
  548. CIISShutdownDlg::OnDblclkComboRestart()
  549. /*++
  550. Routine Description:
  551. Double-click notification handler. Maps to OK
  552. Arguments:
  553. None
  554. Return Value:
  555. None
  556. --*/
  557. {
  558. //
  559. // Go with the current selection
  560. //
  561. OnOK();
  562. }
  563. void
  564. CIISShutdownDlg::OnOK()
  565. /*++
  566. Routine Description:
  567. "OK" button has been pressed, and perform the selected action.
  568. Arguments:
  569. None
  570. Return Value:
  571. None
  572. --*/
  573. {
  574. int iCmd = m_combo_Restart.GetCurSel();
  575. CError err = PerformCommand(iCmd);
  576. if (err.Failed())
  577. {
  578. m_pMachine->DisplayError(err, m_hWnd);
  579. //
  580. // Failed -- do not dismiss the dialog
  581. //
  582. return;
  583. }
  584. //
  585. // No error, dismiss the dialog
  586. //
  587. CDialog::OnOK();
  588. }