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.

779 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994-2001 Microsoft Corporation
  3. Module Name :
  4. shts.cpp
  5. Abstract:
  6. IIS Property sheet classes
  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 "inetprop.h"
  17. #include "InetMgrApp.h"
  18. #include "shts.h"
  19. #include "mime.h"
  20. #include "iisobj.h"
  21. #include "shutdown.h"
  22. #include "util.h"
  23. #include "tracker.h"
  24. extern CPropertySheetTracker g_OpenPropertySheetTracker;
  25. #if defined(_DEBUG) || DBG
  26. extern CDebug_IISObject g_Debug_IISObject;
  27. #endif
  28. #ifdef _DEBUG
  29. #undef THIS_FILE
  30. static char BASED_CODE THIS_FILE[] = __FILE__;
  31. #endif
  32. #define new DEBUG_NEW
  33. //
  34. // CInetPropertySheet class
  35. //
  36. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  37. IMPLEMENT_DYNAMIC(CInetPropertySheet, CPropertySheet)
  38. CInetPropertySheet::CInetPropertySheet(
  39. CComAuthInfo * pAuthInfo,
  40. LPCTSTR lpszMetaPath,
  41. CWnd * pParentWnd,
  42. LPARAM lParam,
  43. LPARAM lParamParentObject,
  44. UINT iSelectPage
  45. )
  46. /*++
  47. Routine Description:
  48. IIS Property Sheet constructor
  49. Arguments:
  50. CComAuthInfo * pAuthInfo : Authentication information
  51. LPCTSTR lpszMetPath : Metabase path
  52. CWnd * pParentWnd : Optional parent window
  53. LPARAM lParam : MMC Console parameter
  54. UINT iSelectPage : Initial page to be selected
  55. Return Value:
  56. N/A
  57. --*/
  58. : CPropertySheet(_T(""), pParentWnd, iSelectPage),
  59. m_auth(pAuthInfo),
  60. m_strMetaPath(lpszMetaPath),
  61. m_dwInstance(0L),
  62. m_bModeless(FALSE),
  63. m_lParam(lParam),
  64. m_lParamParentObject(lParamParentObject),
  65. m_fHasAdminAccess(TRUE), // Assumed by default
  66. m_pCap(NULL),
  67. m_refcount(0),
  68. m_prop_change_flag(PROP_CHANGE_NO_UPDATE),
  69. m_fRestartRequired(FALSE),
  70. m_fChanged(FALSE)
  71. {
  72. m_fIsMasterPath = CMetabasePath::IsMasterInstance(lpszMetaPath);
  73. CIISObject * pNode = (CIISObject *)m_lParam;
  74. CIISObject * pNode2 = (CIISObject *)m_lParamParentObject;
  75. ASSERT(pNode != NULL);
  76. if (pNode)
  77. {
  78. // Tell the object that there is a property page open on it
  79. pNode->SetMyPropertySheetOpen(::GetForegroundWindow());
  80. }
  81. // Addref the object, so that it doesn't get unloaded
  82. // while we have the property sheet open
  83. pNode->AddRef();
  84. pNode->CreateTag();
  85. TRACEEOLID("Tag=" << pNode->m_strTag);
  86. // Add it to the global open property sheet tracker...
  87. g_OpenPropertySheetTracker.Add(pNode);
  88. // And also.... Addref the objects parent, so that it doesn't get unloaded as well
  89. if (pNode2)
  90. {
  91. pNode2->AddRef();
  92. }
  93. #if defined(_DEBUG) || DBG
  94. g_Debug_IISObject.Dump(2);
  95. #endif
  96. }
  97. void
  98. CInetPropertySheet::NotifyMMC()
  99. /*++
  100. Notify MMC that changes have been made, so that the changes are
  101. reflected.
  102. --*/
  103. {
  104. ASSERT(m_lParam != 0L);
  105. CIISObject * pNode = (CIISObject *)m_lParam;
  106. if (pNode != NULL)
  107. {
  108. if (pNode->m_ppHandle != NULL)
  109. {
  110. if ( 0 != (m_prop_change_flag & PROP_CHANGE_DISPLAY_ONLY)
  111. || 0 != (m_prop_change_flag & PROP_CHANGE_REENUM_VDIR)
  112. || 0 != (m_prop_change_flag & PROP_CHANGE_REENUM_FILES)
  113. )
  114. {
  115. pNode->m_UpdateFlag = m_prop_change_flag;
  116. // there is something bad about sending this pNode handle
  117. // as part of the notification...
  118. //
  119. // the scenario is when
  120. // 1. the property page is opened
  121. // 2. the user refreshs a node that s a parent to the object
  122. // which has the property page open. this will delete the
  123. // scope object associated with this object, and will
  124. // orphan the object.
  125. // at this time, the cleaning of the scope object, will
  126. // call release on the object once, but of course since
  127. // we addref/release in the createproperty sheet stuff
  128. // we are still protected from the object getting deleted
  129. // from under us, thus we are at Refcount=1 or something like
  130. // but with no scope/result object in MMC
  131. // 3. now when the user clicks OK and saves changes to this
  132. // orphaned property sheet and passes IT's handle allong
  133. // with the change notification....
  134. // 4. What happens next is -- since there is no MMC scope/result
  135. // item -- thus there is only 1 refcount on the object.
  136. // so when the user clicks OK -- really the object will
  137. // Get DELETED... And this pNode that we are sending below
  138. // will try to get dereferenced by the MMC.
  139. // 5. the MMC will get the notification and get the pointer
  140. // and try to call some refresh or something within the object
  141. // itself.
  142. //
  143. // THUS THIS IS THE PROBLEM WITH SENDING pNode.
  144. //
  145. // To remedy this, what we'll do is:
  146. // 1. when a property sheet is about to get orphaned
  147. // we will set it's m_hScopeItem = 0 (gee since it won't have
  148. // a scope/result item anywas).
  149. // 2. thus if we see that here... that means the object
  150. // doesn't have a mmc type scope/result object and we
  151. // should not send the notification
  152. //
  153. if (pNode->QueryScopeItem() || pNode->QueryResultItem())
  154. {
  155. if (pNode->UseCount() > 0)
  156. {
  157. MMCPropertyChangeNotify(pNode->m_ppHandle, (LPARAM) pNode);
  158. m_prop_change_flag = PROP_CHANGE_NO_UPDATE;
  159. }
  160. }
  161. else
  162. {
  163. TRACEEOLID("MMCPropertyChangeNotify:Looks like this is an orphaned property sheet, don't send notification...");
  164. }
  165. }
  166. }
  167. }
  168. }
  169. void
  170. CInetPropertySheet::NotifyMMC_Node(CIISObject * pNode)
  171. /*++
  172. Notify MMC that changes have been made, so that the changes are
  173. reflected.
  174. --*/
  175. {
  176. if (pNode != NULL)
  177. {
  178. if (pNode->m_ppHandle != NULL)
  179. {
  180. pNode->m_UpdateFlag = m_prop_change_flag;
  181. if (pNode->QueryScopeItem() || pNode->QueryResultItem())
  182. {
  183. if (pNode->UseCount() > 0)
  184. {
  185. MMCPropertyChangeNotify(pNode->m_ppHandle, (LPARAM)pNode);
  186. }
  187. }
  188. else
  189. {
  190. TRACEEOLID("MMCPropertyChangeNotify:Looks like this is an orphaned property sheet, don't send notification...");
  191. }
  192. }
  193. }
  194. }
  195. CInetPropertySheet::~CInetPropertySheet()
  196. {
  197. CIISObject * pNode = (CIISObject *)m_lParam;
  198. CIISObject * pNode2 = (CIISObject *)m_lParamParentObject;
  199. ASSERT(pNode != NULL);
  200. // At this moment we should have in m_pages only pages that were not activated
  201. // in this session.
  202. while (!m_pages.IsEmpty())
  203. {
  204. CInetPropertyPage * pPage = m_pages.RemoveHead();
  205. delete pPage;
  206. }
  207. // if (m_fChanged)
  208. // {
  209. // NotifyMMC();
  210. // }
  211. #if defined(_DEBUG) || DBG
  212. g_Debug_IISObject.Dump(2);
  213. #endif
  214. if (pNode)
  215. {
  216. // Tell the object that there is No property page open on it
  217. pNode->SetMyPropertySheetOpen(NULL);
  218. // Free the MMC notify handle
  219. if (pNode->m_ppHandle)
  220. {
  221. // Verify that is isn't a hosed handle...
  222. if (IsValidAddress( (const void*) pNode->m_ppHandle,sizeof(void*)))
  223. {
  224. MMCFreeNotifyHandle(pNode->m_ppHandle);
  225. pNode->m_ppHandle = 0;
  226. }
  227. }
  228. pNode->Release();
  229. // Remove it from the global open property sheet tracker...
  230. g_OpenPropertySheetTracker.Del(pNode);
  231. }
  232. if (pNode2)
  233. {
  234. pNode2->Release();
  235. }
  236. #if defined(_DEBUG) || DBG
  237. g_Debug_IISObject.Dump(2);
  238. #endif
  239. }
  240. void
  241. CInetPropertySheet::AttachPage(CInetPropertyPage * pPage)
  242. {
  243. m_pages.AddTail(pPage);
  244. }
  245. void
  246. CInetPropertySheet::DetachPage(CInetPropertyPage * pPage)
  247. {
  248. POSITION pos = m_pages.Find(pPage);
  249. ASSERT(pos != NULL);
  250. if (pos != NULL)
  251. {
  252. m_fChanged |= pPage->IsDirty();
  253. m_pages.RemoveAt(pos);
  254. }
  255. }
  256. WORD
  257. CInetPropertySheet::QueryMajorVersion() const
  258. {
  259. CIISMBNode * pNode = (CIISMBNode *)m_lParam;
  260. ASSERT(pNode != NULL);
  261. if (pNode)
  262. {
  263. return pNode->QueryMajorVersion();
  264. }
  265. return 0;
  266. }
  267. WORD
  268. CInetPropertySheet::QueryMinorVersion() const
  269. {
  270. CIISMBNode * pNode = (CIISMBNode *)m_lParam;
  271. ASSERT(pNode != NULL);
  272. if (pNode)
  273. {
  274. return pNode->QueryMinorVersion();
  275. }
  276. return 0;
  277. }
  278. /* virtual */
  279. void
  280. CInetPropertySheet::SetObjectsHwnd()
  281. {
  282. CIISMBNode * pNode = (CIISMBNode *)m_lParam;
  283. // Set the hwnd for the CIISObject...
  284. if (pNode)
  285. {
  286. // Tell the object that there is a property page open on it
  287. pNode->SetMyPropertySheetOpen(::GetForegroundWindow());
  288. }
  289. }
  290. /* virtual */
  291. HRESULT
  292. CInetPropertySheet::LoadConfigurationParameters()
  293. {
  294. //
  295. // Load base values
  296. //
  297. CError err;
  298. if (m_pCap == NULL)
  299. {
  300. //
  301. // Capability info stored off the service path ("lm/w3svc").
  302. //
  303. ASSERT(m_strInfoPath.IsEmpty());
  304. //
  305. // Building path components
  306. //
  307. CMetabasePath::GetServiceInfoPath(m_strMetaPath, m_strInfoPath);
  308. //
  309. // Split into instance and directory paths
  310. //
  311. if (IsMasterInstance())
  312. {
  313. m_strServicePath = m_strInstancePath = QueryMetaPath();
  314. }
  315. else
  316. {
  317. VERIFY(CMetabasePath::GetInstancePath(
  318. QueryMetaPath(),
  319. m_strInstancePath,
  320. &m_strDirectoryPath
  321. ));
  322. VERIFY(CMetabasePath::GetServicePath(
  323. QueryMetaPath(),
  324. m_strServicePath
  325. ));
  326. }
  327. if (m_strDirectoryPath.IsEmpty() && !IsMasterInstance())
  328. {
  329. m_strDirectoryPath = CMetabasePath(FALSE, QueryMetaPath(), g_cszRoot);
  330. }
  331. else
  332. {
  333. m_strDirectoryPath = QueryMetaPath();
  334. }
  335. m_dwInstance = CMetabasePath::GetInstanceNumber(m_strMetaPath);
  336. m_pCap = new CServerCapabilities(QueryAuthInfo(), m_strInfoPath);
  337. if (!m_pCap)
  338. {
  339. err = ERROR_NOT_ENOUGH_MEMORY;
  340. return err;
  341. }
  342. err = m_pCap->LoadData();
  343. if (err.Succeeded())
  344. {
  345. CIISMBNode * pNode = (CIISMBNode *)GetParameter();
  346. CIISMachine * pMachine = pNode->GetOwner();
  347. err = DetermineAdminAccess(&pMachine->m_dwMetabaseSystemChangeNumber);
  348. }
  349. }
  350. return err;
  351. }
  352. /* virtual */
  353. void
  354. CInetPropertySheet::FreeConfigurationParameters()
  355. {
  356. // ASSERT_PTR(m_pCap);
  357. SAFE_DELETE(m_pCap);
  358. }
  359. void
  360. CInetPropertySheet::WinHelp(DWORD dwData, UINT nCmd)
  361. /*++
  362. Routine Description:
  363. WinHelp override. We can't use the base class, because our
  364. 'sheet' doesn't usually have a window handle
  365. Arguments:
  366. DWORD dwData : Help data
  367. UINT nCmd : Help command
  368. --*/
  369. {
  370. WinHelpDebug(dwData);
  371. if (m_hWnd == NULL)
  372. {
  373. /*
  374. //
  375. // Special case
  376. //
  377. ::WinHelp(
  378. HWND hWndMain,
  379. LPCWSTR lpszHelp,
  380. UINT uCommand,
  381. DWORD dwData
  382. );
  383. */
  384. CWnd * pWnd = ::AfxGetMainWnd();
  385. if (pWnd != NULL)
  386. {
  387. pWnd->WinHelp(dwData, nCmd);
  388. }
  389. return;
  390. }
  391. CPropertySheet::WinHelp(dwData, nCmd);
  392. }
  393. //
  394. // Message Map
  395. //
  396. BEGIN_MESSAGE_MAP(CInetPropertySheet, CPropertySheet)
  397. //{{AFX_MSG_MAP(CInetPropertySheet)
  398. //}}AFX_MSG_MAP
  399. END_MESSAGE_MAP()
  400. //
  401. // CInetPropertyPage class
  402. //
  403. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  404. //
  405. // CInetPropertyPage property page
  406. //
  407. IMPLEMENT_DYNAMIC(CInetPropertyPage, CPropertyPage)
  408. #ifdef _DEBUG
  409. /* virtual */
  410. void
  411. CInetPropertyPage::AssertValid() const
  412. {
  413. }
  414. /* virtual */
  415. void
  416. CInetPropertyPage::Dump(CDumpContext& dc) const
  417. {
  418. }
  419. #endif // _DEBUG
  420. CInetPropertyPage::CInetPropertyPage(
  421. IN UINT nIDTemplate,
  422. IN CInetPropertySheet * pSheet,
  423. IN UINT nIDCaption,
  424. IN BOOL fEnableEnhancedFonts OPTIONAL
  425. )
  426. /*++
  427. Routine Description:
  428. IIS Property Page Constructor
  429. Arguments:
  430. UINT nIDTemplate : Resource template
  431. CInetPropertySheet * pSheet : Associated property sheet
  432. UINT nIDCaption : Caption ID
  433. BOOL fEnableEnhancedFonts : Enable enhanced fonts
  434. Return Value:
  435. N/A
  436. --*/
  437. : CPropertyPage(nIDTemplate, nIDCaption),
  438. m_nHelpContext(nIDTemplate + 0x20000),
  439. m_fEnableEnhancedFonts(fEnableEnhancedFonts),
  440. m_bChanged(FALSE),
  441. m_pSheet(pSheet)
  442. {
  443. //{{AFX_DATA_INIT(CInetPropertyPage)
  444. //}}AFX_DATA_INIT
  445. m_psp.dwFlags |= PSP_HASHELP;
  446. ASSERT(m_pSheet != NULL);
  447. if (m_pSheet)
  448. {
  449. m_pSheet->AttachPage(this);
  450. }
  451. }
  452. CInetPropertyPage::~CInetPropertyPage()
  453. {
  454. }
  455. void
  456. CInetPropertyPage::DoDataExchange(CDataExchange * pDX)
  457. {
  458. CPropertyPage::DoDataExchange(pDX);
  459. //{{AFX_DATA_MAP(CInetPropertyPage)
  460. //}}AFX_DATA_MAP
  461. }
  462. /* virtual */
  463. void
  464. CInetPropertyPage::PostNcDestroy()
  465. /*++
  466. Routine Description:
  467. handle destruction of the window by freeing the this
  468. pointer (as this modeless dialog must have been created
  469. on the heap)
  470. Arguments:
  471. None.
  472. Return Value:
  473. None
  474. --*/
  475. {
  476. m_pSheet->Release(this);
  477. delete this;
  478. }
  479. //
  480. // Message Map
  481. //
  482. BEGIN_MESSAGE_MAP(CInetPropertyPage, CPropertyPage)
  483. //{{AFX_MSG_MAP(CInetPropertyPage)
  484. ON_COMMAND(ID_HELP, OnHelp)
  485. ON_WM_HELPINFO()
  486. //}}AFX_MSG_MAP
  487. END_MESSAGE_MAP()
  488. //
  489. // Message Handlers
  490. //
  491. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  492. /* virtual */
  493. BOOL
  494. CInetPropertyPage::OnInitDialog()
  495. /*++
  496. Routine Description:
  497. WM_INITDIALOG handler. Initialize the dialog. Reset changed
  498. status (sometimes gets set by e.g. spinboxes when the dialog is
  499. constructed), so make sure the dialog is considered clean.
  500. --*/
  501. {
  502. m_bChanged = FALSE;
  503. //
  504. // Tell derived class to load its configuration parameters
  505. //
  506. CError err(LoadConfigurationParameters());
  507. // Tell the object which Hwnd it will have.
  508. if (m_pSheet)
  509. {
  510. m_pSheet->SetObjectsHwnd();
  511. }
  512. if (err.Succeeded())
  513. {
  514. err = FetchLoadedValues();
  515. }
  516. else
  517. {
  518. // EndDialog(IDCANCEL);
  519. DestroyWindow();
  520. return TRUE;
  521. }
  522. BOOL bResult = CPropertyPage::OnInitDialog();
  523. err.MessageBoxOnFailure(m_hWnd);
  524. if (m_fEnableEnhancedFonts)
  525. {
  526. CFont * pFont = &m_fontBold;
  527. if (CreateSpecialDialogFont(this, pFont))
  528. {
  529. ApplyFontToControls(this, pFont, IDC_ED_BOLD1, IDC_ED_BOLD5);
  530. }
  531. }
  532. // We should call AddRef here, not in page constructor, because PostNCDestroy()
  533. // is getting called only for pages that were activated, not for all created pages.
  534. // OnInitDialog is also called for activated pages only -- so we will get parity
  535. // and delete property sheet.
  536. //
  537. ASSERT(m_pSheet != NULL);
  538. if (m_pSheet)
  539. {
  540. m_pSheet->AddRef();
  541. }
  542. return bResult;
  543. }
  544. void
  545. CInetPropertyPage::OnHelp()
  546. {
  547. ASSERT_PTR(m_pSheet);
  548. WinHelpDebug(m_nHelpContext);
  549. m_pSheet->WinHelp(m_nHelpContext);
  550. }
  551. BOOL
  552. CInetPropertyPage::OnHelpInfo(HELPINFO * pHelpInfo)
  553. {
  554. OnHelp();
  555. return TRUE;
  556. }
  557. void
  558. CInetPropertyPage::OnCancel()
  559. {
  560. return CPropertyPage::OnCancel();
  561. }
  562. BOOL
  563. CInetPropertyPage::OnApply()
  564. {
  565. BOOL bSuccess = TRUE;
  566. if (IsDirty())
  567. {
  568. CError err(SaveInfo());
  569. if (err.MessageBoxOnFailure(m_hWnd))
  570. {
  571. //
  572. // Failed, sheet will not be dismissed.
  573. //
  574. // CODEWORK: This page should be activated.
  575. //
  576. bSuccess = FALSE;
  577. }
  578. SetModified(!bSuccess);
  579. if (bSuccess && GetSheet()->RestartRequired())
  580. {
  581. // ask user about immediate restart
  582. CIISMBNode * pNode = (CIISMBNode *)m_pSheet->GetParameter();
  583. CIISMachine * pMachine = pNode->GetOwner();
  584. if (IDYES == ::AfxMessageBox(IDS_ASK_TO_RESTART, MB_YESNO | MB_ICONQUESTION))
  585. {
  586. // restart IIS
  587. if (pMachine != NULL)
  588. {
  589. pMachine->AddRef();
  590. CIISShutdownDlg dlg(pMachine, this);
  591. dlg.PerformCommand(ISC_RESTART, FALSE);
  592. bSuccess = dlg.ServicesWereRestarted();
  593. pMachine->Release();
  594. err = pMachine->CreateInterface(TRUE);
  595. bSuccess = err.Succeeded();
  596. }
  597. }
  598. else
  599. {
  600. // user didn't want to restart iis services
  601. // at least let's update the UI
  602. pMachine->RefreshData();
  603. }
  604. // mark restart required false to suppress it on other pages
  605. m_pSheet->NotifyMMC_Node(pMachine);
  606. m_pSheet->SetRestartRequired(FALSE, PROP_CHANGE_NO_UPDATE);
  607. m_pSheet->ResetNotifyFlag();
  608. }
  609. // This call will do nothing if we were in restart code path, at the end of this
  610. // notify flag was reset
  611. m_pSheet->NotifyMMC();
  612. }
  613. return bSuccess;
  614. }
  615. void
  616. CInetPropertyPage::SetModified(BOOL bChanged)
  617. {
  618. CPropertyPage::SetModified(bChanged);
  619. m_bChanged = bChanged;
  620. }