Source code of Windows XP (NT5)
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.

854 lines
13 KiB

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