/*++ Module Name: MmcRoot.cpp Abstract: This module contains the implementation for CMmcDfsRoot. This is an class for MMC display related calls for the first level node(the DfsRoot nodes) Also contains members and method to be able to manipulate IDfsRoot object and add the same to the MMC Console --*/ #include "stdafx.h" #include #include "DfsGUI.h" #include "Utils.h" // For the LoadStringFromResource method #include "MenuEnum.h" // Contains the menu and toolbar command ids #include "resource.h" // For the Resource ID for strings, etc. #include "MmcAdmin.h" // For class CMmcDfsAdmin #include "MmcRoot.h" #include "MmcJP.h" // For deleteing the child Junction points in the destructor of the root object #include "MmcRep.h" #include "DfsEnums.h" // For DFS_TYPE_STANDALONE and other DfsRoot declarations #include "AddToDfs.h" #include "LinkFilt.h" #include "DfsNodes.h" // For Node GUIDs #include "DfsWiz.h" // For the wizard pages, CCreateDfsRootWizPage1, 2, ... #include #include "permpage.h" #include "ldaputils.h" const int CMmcDfsRoot::m_iIMAGEINDEX = 0; const int CMmcDfsRoot::m_iOPENIMAGEINDEX = 0; ////////////////////////////////////////////////////////////////////////////////////////////////// // Constructor For _JUNCTION_LIST JP_LIST_NODE :: JP_LIST_NODE (CMmcDfsJunctionPoint* i_pMmcJP) { pJPoint = i_pMmcJP; } ////////////////////////////////////////////////////////////////////////////////////////////////// // destructor JP_LIST_NODE :: ~JP_LIST_NODE () { SAFE_RELEASE(pJPoint); } CMmcDfsRoot::CMmcDfsRoot( IN IDfsRoot* i_pDfsRoot, IN CMmcDfsAdmin* i_pMmcDfsAdmin, IN LPCONSOLE2 i_lpConsole, IN ULONG i_ulLinkFilterMaxLimit, // = FILTERDFSLINKS_MAXLIMIT_DEFAULT, IN FILTERDFSLINKS_TYPE i_lLinkFilterType, // = FILTERDFSLINKS_TYPE_NO_FILTER, IN BSTR i_bstrLinkFilterName // = NULL ) { dfsDebugOut((_T("CMmcDfsRoot::CMmcDfsRoot this=%p\n"), this)); MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_pDfsRoot); MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_pMmcDfsAdmin); MMC_DISP_CTOR_RETURN_INVALIDARG_IF_NULL(i_lpConsole); m_DfsRoot = i_pDfsRoot; // Save the IDfsRoot pointer m_pParent = i_pMmcDfsAdmin; // Save the parent pointer m_lpConsole = i_lpConsole; // Save the console pointer HRESULT hr = m_DfsRoot->get_RootEntryPath(&m_bstrRootEntryPath); // Get the Root entrypath. MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr); hr = m_DfsRoot->get_DfsType((long *)&m_lDfsRootType); // Get dfsroot type from the IDfsRoot MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr); m_enumNewSchema = SCHEMA_VERSION_UNKNOWN; if (DFS_TYPE_FTDFS == m_lDfsRootType) { CComBSTR bstrDomainName; CComBSTR bstrDfsName; hr = m_DfsRoot->get_DomainName(&bstrDomainName); MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr); hr = m_DfsRoot->get_DfsName(&bstrDfsName); MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr); hr = GetDfsRootDisplayName(bstrDomainName, bstrDfsName, &m_bstrDisplayName); MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr); } else { m_bstrDisplayName = m_bstrRootEntryPath; MMC_DISP_CTOR_RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDisplayName); } m_lpConsoleNameSpace = NULL; m_CLSIDNodeType = s_guidDfsRootNodeType; m_bstrDNodeType = s_tchDfsRootNodeType; m_lRootJunctionState = DFS_JUNCTION_STATE_UNASSIGNED; m_ulLinkFilterMaxLimit = i_ulLinkFilterMaxLimit; m_lLinkFilterType = i_lLinkFilterType; if (i_bstrLinkFilterName) m_bstrLinkFilterName = i_bstrLinkFilterName; else m_bstrLinkFilterName.Empty(); m_bShowFRS = FALSE; } CMmcDfsRoot::~CMmcDfsRoot( ) { // Silently close all outstanding property sheets. CloseAllPropertySheets(TRUE); // Clean up display objects of children and result pane. CleanScopeChildren(); CleanResultChildren(); if ((IReplicaSet *)m_piReplicaSet) m_piReplicaSet.Release(); dfsDebugOut((_T("CMmcDfsRoot::~CMmcDfsRoot this=%p\n"), this)); } STDMETHODIMP CMmcDfsRoot::AddItemToScopePane( IN LPCONSOLENAMESPACE i_lpConsoleNameSpace, IN HSCOPEITEM i_hItemParent ) /*++ Routine Description: This routine adds the current item(itself) to the Scope pane. Arguments: lpConsoleNameSpace - The interface which tells add item to the scope pane. A callback hItemParent - The handle of the parent. The current item is added as this item's child --*/ { RETURN_INVALIDARG_IF_NULL(i_lpConsoleNameSpace); RETURN_INVALIDARG_IF_NULL(i_hItemParent); BOOL bReplicaSetExist = FALSE; HRESULT hr = m_DfsRoot->get_ReplicaSetExist(&bReplicaSetExist); if (SUCCEEDED(hr)) { SCOPEDATAITEM ScopeItemDfsRoot; ZeroMemory(&ScopeItemDfsRoot, sizeof(ScopeItemDfsRoot)); ScopeItemDfsRoot.mask = SDI_IMAGE | SDI_OPENIMAGE | SDI_PARAM | SDI_STR | SDI_PARENT; ScopeItemDfsRoot.nImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0); ScopeItemDfsRoot.nOpenImage = CMmcDfsRoot::m_iOPENIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0); ScopeItemDfsRoot.lParam = reinterpret_cast(this); ScopeItemDfsRoot.displayname = MMC_TEXTCALLBACK; ScopeItemDfsRoot.relativeID = i_hItemParent; hr = i_lpConsoleNameSpace->InsertItem(&ScopeItemDfsRoot); RETURN_IF_FAILED(hr); m_hScopeItem = ScopeItemDfsRoot.ID; m_lpConsoleNameSpace = i_lpConsoleNameSpace; } return S_OK; } STDMETHODIMP CMmcDfsRoot::AddMenuItems( IN LPCONTEXTMENUCALLBACK i_lpContextMenuCallback, IN LPLONG i_lpInsertionAllowed ) /*++ Routine Description: This routine adds a context menu using the ContextMenuCallback provided. Arguments: lpContextMenuCallback - A callback(function pointer) that is used to add the menu items lpInsertionAllowed - Specifies what menus can be added and where they can be added. --*/ { RETURN_INVALIDARG_IF_NULL(i_lpContextMenuCallback); enum { IDM_CONTEXTMENU_COMMAND_MAX = IDM_ROOT_MAX, IDM_CONTEXTMENU_COMMAND_MIN = IDM_ROOT_MIN }; LONG lInsertionPoints [IDM_CONTEXTMENU_COMMAND_MAX - IDM_CONTEXTMENU_COMMAND_MIN + 1] = { CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP, CCM_INSERTIONPOINTID_PRIMARY_TOP }; LPTSTR aszLanguageIndependentName[IDM_CONTEXTMENU_COMMAND_MAX - IDM_CONTEXTMENU_COMMAND_MIN + 1] = { _T("RootTopNewDfsLink"), _T("RootTopNewRootReplica"), _T("RootTopCheckStatus"), _T("RootTopFilterDfsLinks"), _T("RootTopDeleteConnectionToDfsRoot"), _T("RootTopDeleteDfsRoot"), _T("RootTopDeleteDisplayedDfsLinks"), _T("RootTopReplicationTopology"), _T("RootTopShowReplication"), _T("RootTopHideReplication"), _T("RootTopStopReplication") }; CComPtr spiCallback2; HRESULT hr = i_lpContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (void **)&spiCallback2); RETURN_IF_FAILED(hr); // select the node to populate m_MmcRepList if (m_MmcRepList.empty()) m_lpConsole->SelectScopeItem(m_hScopeItem); BOOL bReplicaSetExist = FALSE; hr = m_DfsRoot->get_ReplicaSetExist(&bReplicaSetExist); RETURN_IF_FAILED(hr); for (int iCommandID = IDM_CONTEXTMENU_COMMAND_MIN,iMenuResource = IDS_MENUS_ROOT_TOP_NEW_DFS_LINK; iCommandID <= IDM_CONTEXTMENU_COMMAND_MAX; iCommandID++,iMenuResource++ ) { CONTEXTMENUITEM2 ContextMenuItem; // The structure which contains menu information ZeroMemory(&ContextMenuItem, sizeof(ContextMenuItem)); switch (iCommandID) { case IDM_ROOT_TOP_NEW_ROOT_REPLICA: { if (DFS_TYPE_STANDALONE == m_lDfsRootType) continue; break; } case IDM_ROOT_TOP_DELETE_DISPLAYED_DFS_LINKS: { if (m_MmcJPList.empty()) continue; break; } case IDM_ROOT_TOP_REPLICATION_TOPOLOGY: { if (bReplicaSetExist || (1 >= m_MmcRepList.size()) || (DFS_TYPE_STANDALONE == m_lDfsRootType)) continue; break; } case IDM_ROOT_TOP_SHOW_REPLICATION: { if (!bReplicaSetExist || m_bShowFRS) continue; break; } case IDM_ROOT_TOP_HIDE_REPLICATION: { if (!bReplicaSetExist || !m_bShowFRS) continue; break; } case IDM_ROOT_TOP_STOP_REPLICATION: { if (!bReplicaSetExist) continue; break; } case IDM_ROOT_TOP_NEW_DFS_LINK: case IDM_ROOT_TOP_CHECK_STATUS: case IDM_ROOT_TOP_FILTER_DFS_LINKS: { // excluded when empty root container if (m_MmcRepList.empty()) continue; break; } } CComBSTR bstrMenuText; CComBSTR bstrStatusBarText; hr = GetMenuResourceStrings(iMenuResource, &bstrMenuText, NULL, &bstrStatusBarText); RETURN_IF_FAILED(hr); ContextMenuItem.strName = bstrMenuText; // Assign the menu text ContextMenuItem.strStatusBarText = bstrStatusBarText; // Assign the menu help text ContextMenuItem.lInsertionPointID = lInsertionPoints[iCommandID - IDM_CONTEXTMENU_COMMAND_MIN]; ContextMenuItem.lCommandID = iCommandID; ContextMenuItem.strLanguageIndependentName = aszLanguageIndependentName[iCommandID - IDM_CONTEXTMENU_COMMAND_MIN]; LONG lInsertionFlag = 0; switch(ContextMenuItem.lInsertionPointID) // Checking for permission to add menus { case CCM_INSERTIONPOINTID_PRIMARY_TOP: lInsertionFlag = CCM_INSERTIONALLOWED_TOP; break; case CCM_INSERTIONPOINTID_PRIMARY_NEW: lInsertionFlag = CCM_INSERTIONALLOWED_NEW; break; case CCM_INSERTIONPOINTID_PRIMARY_TASK: lInsertionFlag = CCM_INSERTIONALLOWED_TASK; break; case CCM_INSERTIONPOINTID_PRIMARY_VIEW: lInsertionFlag = CCM_INSERTIONALLOWED_VIEW; break; default: break; } if (*i_lpInsertionAllowed & lInsertionFlag) { hr = spiCallback2->AddItem(&ContextMenuItem); RETURN_IF_FAILED(hr); } } // for return hr; } STDMETHODIMP CMmcDfsRoot::GetScopeDisplayInfo( IN OUT LPSCOPEDATAITEM io_pScopeDataItem ) /*++ Routine Description: Returns the information required for MMC display for this item. Arguments: i_pScopeDataItem - The ScopeItem which specifies what display information is required --*/ { RETURN_INVALIDARG_IF_NULL(io_pScopeDataItem); HRESULT hr = S_OK; if (SDI_STR & io_pScopeDataItem->mask) // MMC wants the displaystring { ULONG ulTotalNumOfJPs = 0; hr = m_DfsRoot->get_CountOfDfsJunctionPoints((long*)&ulTotalNumOfJPs); RETURN_IF_FAILED(hr); if (m_lLinkFilterType != FILTERDFSLINKS_TYPE_NO_FILTER || m_MmcJPList.size() < ulTotalNumOfJPs) { m_bstrFullDisplayName.Empty(); hr = FormatMessageString(&m_bstrFullDisplayName, 0, IDS_DFSROOT_DISPLAY_STRING, m_bstrDisplayName); RETURN_IF_FAILED(hr); io_pScopeDataItem->displayname = m_bstrFullDisplayName; } else { io_pScopeDataItem->displayname = m_bstrDisplayName; } } if (SDI_IMAGE & io_pScopeDataItem->mask) // MMC wants the image index for the item io_pScopeDataItem->nImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + m_lRootJunctionState; if (SDI_OPENIMAGE & io_pScopeDataItem->mask) // MMC wants the image index for the item io_pScopeDataItem->nOpenImage = CMmcDfsRoot::m_iOPENIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + m_lRootJunctionState; return hr; } STDMETHODIMP CMmcDfsRoot::GetResultDisplayInfo( IN OUT LPRESULTDATAITEM io_pResultDataItem ) /*++ Routine Description: Returns the information required for MMC display for this item. Arguments: io_pResultDataItem - The ResultItem which specifies what display information is required --*/ { RETURN_INVALIDARG_IF_NULL(io_pResultDataItem); if (RDI_IMAGE & io_pResultDataItem->mask) // MMC wants the image index for the item io_pResultDataItem->nImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + m_lRootJunctionState; if (RDI_STR & io_pResultDataItem->mask) // MMC wants the text for the item { if (0 == io_pResultDataItem->nCol) // Return the Dfs Root display name io_pResultDataItem->str = m_bstrDisplayName; } return S_OK; } STDMETHODIMP CMmcDfsRoot::Command( IN LONG i_lCommandID ) /*++ Routine Description: Action to be taken on a context menu selection or click is takes place. Arguments: lCommandID - The Command ID of the menu for which action has to be taken --*/ { HRESULT hr = S_OK; switch (i_lCommandID) { case IDM_ROOT_TOP_NEW_DFS_LINK: hr = OnCreateNewJunctionPoint (); break; case IDM_ROOT_TOP_NEW_ROOT_REPLICA: hr = OnNewRootReplica(); break; case IDM_ROOT_TOP_CHECK_STATUS: hr = OnCheckStatus(); break; case IDM_ROOT_TOP_DELETE_DISPLAYED_DFS_LINKS: hr = OnDeleteDisplayedDfsLinks(); break; case IDM_ROOT_TOP_DELETE_DFS_ROOT: // Delete the Current dfs root hr = OnDeleteDfsRoot(); break; case IDM_ROOT_TOP_DELETE_CONNECTION_TO_DFS_ROOT: // "Delete Connection to Dfs Root" hr = OnDeleteConnectionToDfsRoot(); break; case IDM_ROOT_TOP_FILTER_DFS_LINKS: hr = OnFilterDfsLinks(); break; case IDM_ROOT_TOP_REPLICATION_TOPOLOGY: hr = OnNewReplicaSet(); break; case IDM_ROOT_TOP_SHOW_REPLICATION: case IDM_ROOT_TOP_HIDE_REPLICATION: m_bShowFRS = !m_bShowFRS; hr = OnShowReplication(); break; case IDM_ROOT_TOP_STOP_REPLICATION: hr = OnStopReplication(TRUE); if (FAILED(hr)) DisplayMessageBoxForHR(hr); break; default: hr = E_INVALIDARG; break; } return hr; } HRESULT CMmcDfsRoot::_InitReplicaSet() { if (m_lDfsRootType != DFS_TYPE_FTDFS) return S_FALSE; // no replica set associate with standalone root BOOL bReplicaSetExist = FALSE; CComBSTR bstrDC; HRESULT hr = m_DfsRoot->get_ReplicaSetExistEx(&bstrDC, &bReplicaSetExist); RETURN_IF_FAILED(hr); if (!bReplicaSetExist) { if ((IReplicaSet *)m_piReplicaSet) m_piReplicaSet.Release(); return S_FALSE; // no replica set associate with it } if ((IReplicaSet *)m_piReplicaSet) { CComBSTR bstrTargetedDC; hr = m_piReplicaSet->get_TargetedDC(&bstrTargetedDC); if (FAILED(hr) || lstrcmpi(bstrTargetedDC, bstrDC)) { // something is wrong or we're using a different DC, re-init m_piReplicaSet m_piReplicaSet.Release(); } } if (!m_piReplicaSet) { CComBSTR bstrDomain; hr = m_DfsRoot->get_DomainName(&bstrDomain); RETURN_IF_FAILED(hr); CComBSTR bstrReplicaSetDN; hr = m_DfsRoot->get_ReplicaSetDN(&bstrReplicaSetDN); RETURN_IF_FAILED(hr); // // read info of the replica set from DS // hr = CoCreateInstance(CLSID_ReplicaSet, NULL, CLSCTX_INPROC_SERVER, IID_IReplicaSet, (void**) &m_piReplicaSet); RETURN_IF_FAILED(hr); hr = m_piReplicaSet->Initialize(bstrDomain, bstrReplicaSetDN); if (FAILED(hr)) { m_piReplicaSet.Release(); return hr; } } return hr; } HRESULT CMmcDfsRoot::OnNewReplicaSet() { // // refresh to pick up possible namespace updates on targets by others // HRESULT hr = OnRefresh(); if (S_FALSE == hr) { // this root has been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } CWaitCursor wait; // // Use MMC main window as the parent as our modal wizard // HWND hwndParent = 0; hr = m_lpConsole->GetMainWindow(&hwndParent); RETURN_IF_FAILED(hr); BOOL bReplicaSetExist = FALSE; m_DfsRoot->get_ReplicaSetExist(&bReplicaSetExist); if (bReplicaSetExist) // replica set exist, return return S_OK; CComBSTR bstrDomain; hr = m_DfsRoot->get_DomainName(&bstrDomain); RETURN_IF_FAILED(hr); CComBSTR bstrReplicaSetDN; hr = m_DfsRoot->get_ReplicaSetDN(&bstrReplicaSetDN); RETURN_IF_FAILED(hr); CNewReplicaSet ReplicaSetInfo; hr = ReplicaSetInfo.Initialize(bstrDomain, bstrReplicaSetDN, &m_MmcRepList); RETURN_IF_FAILED(hr); CNewReplicaSetPage0 WizPage0; CNewReplicaSetPage1 WizPage1(&ReplicaSetInfo); CNewReplicaSetPage2 WizPage2(&ReplicaSetInfo, IsNewSchema()); CComPtr pPropSheetCallback; // MMC Callback used to add pages hr = m_lpConsole->QueryInterface(IID_IPropertySheetCallback, reinterpret_cast(&pPropSheetCallback)); RETURN_IF_FAILED(hr); CComPtr pPropSheetProvider; // MMC callback used to handle wizard hr = m_lpConsole->QueryInterface(IID_IPropertySheetProvider, reinterpret_cast(&pPropSheetProvider)); RETURN_IF_FAILED(hr); hr = pPropSheetProvider->CreatePropertySheet( _T(""), // title FALSE, // Wizard and not property sheet. 0, // Cookie NULL, // IDataobject MMC_PSO_NEWWIZARDTYPE); // Creation flags if (SUCCEEDED(hr)) { pPropSheetCallback->AddPage(WizPage0.Create()); pPropSheetCallback->AddPage(WizPage1.Create()); pPropSheetCallback->AddPage(WizPage2.Create()); hr = pPropSheetProvider->AddPrimaryPages( NULL, FALSE, // Don't create a notify handle NULL, TRUE // Scope pane (not result pane) ); if (SUCCEEDED(hr)) hr = pPropSheetProvider->Show((LONG_PTR)hwndParent, 0); // // If failed, call IPropertySheetProvider::Show(-1,0) to // delete the property sheet and free its resources // if (FAILED(hr)) pPropSheetProvider->Show(-1, 0); } RETURN_IF_FAILED(hr); // // handle th result // if (S_OK == ReplicaSetInfo.m_hr) { // // store the interface pointer // m_piReplicaSet = ReplicaSetInfo.m_piReplicaSet; m_DfsRoot->put_ReplicaSetExist(TRUE); // // update icon // SCOPEDATAITEM ScopeDataItem; ZeroMemory(&ScopeDataItem, sizeof(SCOPEDATAITEM)); ScopeDataItem.mask = SDI_IMAGE | SDI_OPENIMAGE; ScopeDataItem.ID = m_hScopeItem; hr = m_lpConsoleNameSpace->GetItem(&ScopeDataItem); if (SUCCEEDED(hr)) { ScopeDataItem.nImage += 4; ScopeDataItem.nOpenImage += 4; m_lpConsoleNameSpace->SetItem(&ScopeDataItem); // update the toolbar m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); } } return hr; } HRESULT CMmcDfsRoot::OnShowReplication() { BOOL bShowFRS = m_bShowFRS; // save it because refresh will reset it to FALSE // // refresh to pick up possible namespace updates on targets by others // HRESULT hr = OnRefresh(); if (S_FALSE == hr) { // this root has been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } CWaitCursor wait; DFS_REPLICA_LIST::iterator i; if (bShowFRS) { // // init m_piReplicaSet // hr = _InitReplicaSet(); if (S_OK != hr) // no replica set, do nothing and return return S_OK; // // fill in each alternate m_bstrFRSColumnText and m_bstrStatusText // for (i = m_MmcRepList.begin(); i != m_MmcRepList.end(); i++) { ((*i)->pReplica)->ShowReplicationInfo(m_piReplicaSet); } m_bShowFRS = TRUE; } // update the toolbar m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); return hr; } HRESULT CMmcDfsRoot::OnStopReplication(BOOL bConfirm /* = FALSE */, BOOL bRefresh /* = TRUE */) { HRESULT hr = S_OK; // // refresh to pick up possible namespace updates on targets by others // if (bRefresh) { hr = OnRefresh(); if (S_FALSE == hr) { // this root has been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } } CWaitCursor wait; BOOL bReplicaSetExist = FALSE; m_DfsRoot->get_ReplicaSetExist(&bReplicaSetExist); if (!bReplicaSetExist) // replica set doesn't exist, return return S_OK; if (bConfirm) { hr = ConfirmOperationOnDfsRoot(IDS_MSG_STOP_REPLICATION); if (S_OK != hr) return hr; } // // init m_piReplicaSet // hr = _InitReplicaSet(); if (S_OK != hr) // no replica set, return return hr; hr = m_piReplicaSet->Delete(); if (SUCCEEDED(hr)) { m_piReplicaSet.Release(); hr = m_DfsRoot->put_ReplicaSetExist(FALSE); SCOPEDATAITEM ScopeDataItem; ZeroMemory(&ScopeDataItem, sizeof(SCOPEDATAITEM)); ScopeDataItem.mask = SDI_IMAGE | SDI_OPENIMAGE; ScopeDataItem.ID = m_hScopeItem; hr = m_lpConsoleNameSpace->GetItem(&ScopeDataItem); if (SUCCEEDED(hr)) { ScopeDataItem.nImage -= 4; ScopeDataItem.nOpenImage -= 4; m_lpConsoleNameSpace->SetItem(&ScopeDataItem); // update the toolbar m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); } } return hr; } STDMETHODIMP CMmcDfsRoot::OnNewRootReplica( ) /*++ Routine Description: Action to be taken on menu command "New Root Replica Member". Here is a wizard is used to guide the user through the process of Deciding a new server and share. --*/ { // Select this node to make sure m_MmcRepList populated if (m_MmcRepList.empty()) m_lpConsole->SelectScopeItem(m_hScopeItem); // // Use MMC main window as the parent as our modal wizard // HWND hwndMainWin = 0; HRESULT hr = m_lpConsole->GetMainWindow(&hwndMainWin); RETURN_IF_FAILED(hr); CREATEDFSROOTWIZINFO CreateWizInfo; // 0 initializes all members to 0. Necessary CreateWizInfo.pMMCAdmin = m_pParent; CreateWizInfo.bRootReplica = true; // Set the flag that says this is for root replica // Set the domain name and the dfs type hr = m_DfsRoot->get_DomainName(&CreateWizInfo.bstrSelectedDomain); RETURN_IF_FAILED(hr); CreateWizInfo.DfsType = DFS_TYPE_FTDFS; hr = m_DfsRoot->get_DfsName(&CreateWizInfo.bstrDfsRootName); RETURN_IF_FAILED(hr); CCreateDfsRootWizPage4 WizPage4(&CreateWizInfo); CCreateDfsRootWizPage5 WizPage5(&CreateWizInfo); CCreateDfsRootWizPage7 WizPage7(&CreateWizInfo); // Get the required interfaces from IConsole2. CComPtr pPropSheetCallback; // MMC Callback used to add pages hr = m_lpConsole->QueryInterface(IID_IPropertySheetCallback, reinterpret_cast(&pPropSheetCallback)); RETURN_IF_FAILED(hr); CComPtr pPropSheetProvider; // MMC callback used to handle wizard hr = m_lpConsole->QueryInterface(IID_IPropertySheetProvider, reinterpret_cast(&pPropSheetProvider)); RETURN_IF_FAILED(hr); // Create the wizard hr = pPropSheetProvider->CreatePropertySheet( _T(""), // Property sheet title. Should not be null so send empty string. FALSE, // Wizard and not property sheet. 0, // Cookie NULL, // IDataobject MMC_PSO_NEWWIZARDTYPE); // Creation flags if (SUCCEEDED(hr)) { pPropSheetCallback->AddPage(WizPage4.Create()); pPropSheetCallback->AddPage(WizPage5.Create()); pPropSheetCallback->AddPage(WizPage7.Create()); hr = pPropSheetProvider->AddPrimaryPages( (IComponentData *)(m_pParent->m_pScopeManager), FALSE, // Don't create a notify handle NULL, TRUE // Scope pane (not result pane) ); if (SUCCEEDED(hr)) hr = pPropSheetProvider->Show( (LONG_PTR)hwndMainWin, // Parent window of the wizard 0 // Starting page ); // // If failed, call IPropertySheetProvider::Show(-1,0) to // delete the property sheet and free its resources // if (FAILED(hr)) pPropSheetProvider->Show(-1, 0); } RETURN_IF_FAILED(hr); if (CreateWizInfo.bDfsSetupSuccess) return OnRefresh(); // to pick the most recent root targets and links return (S_OK); } STDMETHODIMP CMmcDfsRoot::SetColumnHeader( IN LPHEADERCTRL2 i_piHeaderControl ) { RETURN_INVALIDARG_IF_NULL(i_piHeaderControl); CComBSTR bstrColumn0; HRESULT hr = LoadStringFromResource(IDS_RESULT_COLUMN_ROOTREPLICA, &bstrColumn0); RETURN_IF_FAILED(hr); CComBSTR bstrColumn1; hr = LoadStringFromResource(IDS_RESULT_COLUMN_DFSREFERRAL, &bstrColumn1); RETURN_IF_FAILED(hr); CComBSTR bstrColumn2; hr = LoadStringFromResource(IDS_RESULT_COLUMN_STATUS, &bstrColumn2); RETURN_IF_FAILED(hr); i_piHeaderControl->InsertColumn(0, bstrColumn0, LVCFMT_LEFT, DFS_NAME_COLUMN_WIDTH); i_piHeaderControl->InsertColumn(1, bstrColumn1, LVCFMT_LEFT, MMCLV_AUTO); i_piHeaderControl->InsertColumn(2, bstrColumn2, LVCFMT_LEFT, MMCLV_AUTO); if (m_bShowFRS) { CComBSTR bstrColumn3; hr = LoadStringFromResource(IDS_RESULT_COLUMN_FRS, &bstrColumn3); RETURN_IF_FAILED(hr); i_piHeaderControl->InsertColumn(3, bstrColumn3, LVCFMT_LEFT, MMCLV_AUTO); } else { i_piHeaderControl->DeleteColumn(3); } return hr; } STDMETHODIMP CMmcDfsRoot::OnDeleteConnectionToDfsRoot( BOOLEAN i_bForRemoveDfs ) /*++ Routine Description: Used to delete the current object. Both to remove from Scope and from list --*/ { // check outstanding property sheet, discontinue if any. HRESULT hr = CloseAllPropertySheets(FALSE); if (S_OK != hr) return hr; // Confirm with the user, if he wants to delete this connection hr = ConfirmOperationOnDfsRoot(i_bForRemoveDfs ? IDS_MSG_DELETE_DFSROOT : IDS_MSG_DELETE_CONNECTION_TO_DFSROOT); if (S_OK != hr) return hr; CWaitCursor wait; CleanScopeChildren(); // Delete the item from Scope Pane hr = m_lpConsoleNameSpace->DeleteItem(m_hScopeItem, TRUE); RETURN_IF_FAILED(hr); // Delete it from the internal list hr = m_pParent->DeleteMmcRootNode(this); RETURN_IF_FAILED(hr); Release(); // delete this CMmcDfsRoot object return S_OK; } // Delete the node from m_MmcJPList STDMETHODIMP CMmcDfsRoot::DeleteMmcJPNode( IN CMmcDfsJunctionPoint* i_pJPoint, IN BOOL i_bRefresh ) { RETURN_INVALIDARG_IF_NULL(i_pJPoint); dfsDebugOut((_T("CMmcDfsRoot::DeleteMmcJPNode %p, size=%d\n"), i_pJPoint, m_MmcJPList.size())); // Remove the actual junction point(from DS) HRESULT hr = m_DfsRoot->DeleteJunctionPoint(i_pJPoint->m_bstrDisplayName); RETURN_IF_FAILED(hr); // Delete the node from m_MmcJPList for (DFS_JUNCTION_LIST::iterator i = m_MmcJPList.begin(); i != m_MmcJPList.end(); i++) { if ((*i)->pJPoint == i_pJPoint) { (*i)->pJPoint->RemoveFromMMC(); delete (*i); m_MmcJPList.erase(i); break; } } if (i_bRefresh) { hr = OnRefresh(); if (S_FALSE == hr) { // // this root has been deleted by other means, scope pane has been refreshed, // ask user to retry // DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } } return hr; } HRESULT CMmcDfsRoot::ConfirmOperationOnDfsRoot(int idString) /*++ Routine Description: Used to confirm with the user, if he wants to delete the connection to the Dfs Root Return value: S_OK, if the user wants to delete. S_FALSE, if the user decided not to continue with the operation. --*/ { // Confirm delete operation CComBSTR bstrAppName; HRESULT hr = LoadStringFromResource(IDS_APPLICATION_NAME, &bstrAppName); RETURN_IF_FAILED(hr); CComBSTR bstrFormattedMessage; hr = FormatResourceString(idString, m_bstrDisplayName, &bstrFormattedMessage); RETURN_IF_FAILED(hr); // Return now, if the user doesn't want to continue CThemeContextActivator activator; if (IDYES != ::MessageBox(::GetActiveWindow(), bstrFormattedMessage, bstrAppName, MB_YESNO | MB_ICONEXCLAMATION | MB_APPLMODAL)) { return S_FALSE; } return S_OK; } HRESULT CMmcDfsRoot::ConfirmDeleteDisplayedDfsLinks( ) { // Confirm delete operation CComBSTR bstrAppName; HRESULT hr = LoadStringFromResource(IDS_APPLICATION_NAME, &bstrAppName); RETURN_IF_FAILED(hr); CComBSTR bstrMessage; hr = LoadStringFromResource(IDS_MSG_DELETE_DISPLAYEDDFSLINKS, &bstrMessage); RETURN_IF_FAILED(hr); // Return now, if the user doesn't want to continue CThemeContextActivator activator; if (IDYES != ::MessageBox(::GetActiveWindow(), bstrMessage, bstrAppName, MB_YESNO | MB_ICONEXCLAMATION | MB_APPLMODAL)) { return S_FALSE; } return S_OK; } STDMETHODIMP CMmcDfsRoot::EnumerateScopePane( IN LPCONSOLENAMESPACE i_lpConsoleNameSpace, IN HSCOPEITEM i_hParent ) /*++ Routine Description: To eumerate(add) items in the scope pane. Junction points in this case Arguments: i_lpConsoleNameSpace - The callback used to add items to the Scope pane i_hParent - HSCOPEITEM of the parent under which all the items will be added. --*/ { RETURN_INVALIDARG_IF_NULL(i_lpConsoleNameSpace); RETURN_INVALIDARG_IF_NULL(i_hParent); HRESULT hr = m_DfsRoot->put_EnumFilterType(m_lLinkFilterType); RETURN_IF_FAILED(hr); if (m_lLinkFilterType != FILTERDFSLINKS_TYPE_NO_FILTER) { hr = m_DfsRoot->put_EnumFilter(m_bstrLinkFilterName); RETURN_IF_FAILED(hr); } CComPtr pJPEnum; hr = m_DfsRoot->get__NewEnum((IUnknown**) (&pJPEnum)); RETURN_IF_FAILED(hr); hr = m_DfsRoot->get_CountOfDfsJunctionPointsFiltered((long*)&m_ulCountOfDfsJunctionPointsFiltered); RETURN_IF_FAILED(hr); VARIANT varJPObject; VariantInit(&varJPObject); ULONG ulCount = 0; while ( ulCount < m_ulLinkFilterMaxLimit && S_OK == (hr = pJPEnum->Next(1, &varJPObject, NULL)) ) { CComPtr pDfsJPObject; pDfsJPObject = (IDfsJunctionPoint*) varJPObject.pdispVal; // Create the object to be used for MMC display CMmcDfsJunctionPoint* pMMCJPObject = new CMmcDfsJunctionPoint (pDfsJPObject, this, i_lpConsoleNameSpace); if (!pMMCJPObject) { hr = E_OUTOFMEMORY; } else { hr = pMMCJPObject->m_hrValueFromCtor; if (SUCCEEDED(hr)) hr = pMMCJPObject->AddItemToScopePane(i_hParent); if (SUCCEEDED(hr)) { JP_LIST_NODE *pJPList = new JP_LIST_NODE (pMMCJPObject); if (!pJPList) hr = E_OUTOFMEMORY; else m_MmcJPList.push_back(pJPList); } if (FAILED(hr)) delete pMMCJPObject; } VariantClear(&varJPObject); if (FAILED(hr)) break; ulCount++; } // // set the root name appropriately // if (SUCCEEDED(hr)) { SCOPEDATAITEM ScopeDataItem; ZeroMemory(&ScopeDataItem, sizeof(SCOPEDATAITEM)); ScopeDataItem.ID = i_hParent; hr = m_lpConsoleNameSpace->GetItem(&ScopeDataItem); if (SUCCEEDED(hr)) { ScopeDataItem.mask = SDI_STR; ScopeDataItem.displayname = MMC_TEXTCALLBACK; m_lpConsoleNameSpace->SetItem(&ScopeDataItem); } } return hr; } STDMETHODIMP CMmcDfsRoot::SetConsoleVerbs( IN LPCONSOLEVERB i_lpConsoleVerb ) /*++ Routine Description: Routine used to set the console verb settings. Sets all of them except Open off. For all scope pane items, default verb is "open'. For result items, it is "properties" Arguments: i_lpConsoleVerb - The callback used to handle console verbs --*/ { RETURN_INVALIDARG_IF_NULL(i_lpConsoleVerb); i_lpConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_RENAME, HIDDEN, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_OPEN, HIDDEN, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE); i_lpConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); i_lpConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN); //For scope items, default verb is "open" return S_OK; } STDMETHODIMP CMmcDfsRoot :: OnCreateNewJunctionPoint( ) /*++ Routine Description: This method handles the creation of new Junction Points. Display a dialog box to get the user input. --*/ { CAddToDfs AddToDfsDlg; //Add To Dfs Dialog Object HRESULT hr = AddToDfsDlg.put_ParentPath(m_bstrRootEntryPath); RETURN_IF_FAILED(hr); hr = AddToDfsDlg.DoModal(); // Display the dialog box RETURN_IF_NOT_S_OK(hr); hr = OnRefresh(); if (S_FALSE == hr) { // // this root has been deleted by other means, scope pane has been refreshed, // ask user to retry // DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } CWaitCursor wait; CComBSTR bstrJPName; hr = AddToDfsDlg.get_JPName(&bstrJPName); RETURN_IF_FAILED(hr); CComBSTR bstrServerName; hr = AddToDfsDlg.get_Server(&bstrServerName); RETURN_IF_FAILED(hr); CComBSTR bstrShareName; hr = AddToDfsDlg.get_Share(&bstrShareName); RETURN_IF_FAILED(hr); CComBSTR bstrComment; hr = AddToDfsDlg.get_Comment(&bstrComment); RETURN_IF_FAILED(hr); long lTimeout = 0; hr = AddToDfsDlg.get_Time(&lTimeout); RETURN_IF_FAILED(hr); /* we allow interlink at the junction level // Is it a Dfs based path? These are not allowed. if (IsDfsPath(bstrSharePath)) { DisplayMessageBoxWithOK(IDS_MSG_MID_JUNCTION, bstrSharePath); return(S_OK); } */ hr = OnCreateNewJunctionPoint(bstrJPName, bstrServerName, bstrShareName, bstrComment, lTimeout); if (FAILED(hr)) { DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_FAILED_TO_CREATE_JUNCTION_POINT); } return hr; } STDMETHODIMP CMmcDfsRoot :: OnCreateNewJunctionPoint( IN LPCTSTR i_szJPName, IN LPCTSTR i_szServerName, IN LPCTSTR i_szShareName, IN LPCTSTR i_szComment, IN long i_lTimeout ) /*++ Routine Description: This method handles the creation of new Junction Points. It is called by the method that display the message box --*/ { RETURN_INVALIDARG_IF_NULL(i_szJPName); RETURN_INVALIDARG_IF_NULL(i_szServerName); RETURN_INVALIDARG_IF_NULL(i_szShareName); RETURN_INVALIDARG_IF_NULL(i_szComment); VARIANT varJPObject; VariantInit(&varJPObject); HRESULT hr = m_DfsRoot->CreateJunctionPoint( (LPTSTR)i_szJPName, (LPTSTR)i_szServerName, (LPTSTR)i_szShareName, (LPTSTR)i_szComment, i_lTimeout, &varJPObject); RETURN_IF_FAILED(hr); // Add the newly created junction point to scope pane if matches the filter if ( m_MmcJPList.size() < m_ulLinkFilterMaxLimit && FilterMatch(i_szJPName, m_lLinkFilterType, m_bstrLinkFilterName) ) { m_ulCountOfDfsJunctionPointsFiltered++; CComPtr pDfsJPObject = (IDfsJunctionPoint*)varJPObject.pdispVal; // Create the object to be used for MMC display CMmcDfsJunctionPoint* pMMCJPObject = new CMmcDfsJunctionPoint(pDfsJPObject, this, m_lpConsoleNameSpace); if (!pMMCJPObject) { hr = E_OUTOFMEMORY; } else { hr = pMMCJPObject->m_hrValueFromCtor; if (SUCCEEDED(hr)) hr = pMMCJPObject->AddItemToScopePane(m_hScopeItem); if (SUCCEEDED(hr)) { JP_LIST_NODE* pJPList = new JP_LIST_NODE(pMMCJPObject); if (!pJPList) hr = E_OUTOFMEMORY; else m_MmcJPList.push_back(pJPList); } // Select the newly added scope item. if (SUCCEEDED(hr)) { m_lpConsole->SelectScopeItem(pMMCJPObject->m_hScopeItem); } else delete pMMCJPObject; } } else { // select the root scope item to update status text on filtered links m_lpConsole->SelectScopeItem(m_hScopeItem); } VariantClear(&varJPObject); // Send View change notification for all views to update filtered link status text. if (SUCCEEDED(hr)) m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); return hr; } STDMETHODIMP CMmcDfsRoot::DoDelete() /*++ Routine Description: This method allows the item to delete itself. Called when DEL key is pressed or when the "Delete" context menu item is selected. --*/ { return OnDeleteConnectionToDfsRoot(); } STDMETHODIMP CMmcDfsRoot::OnDeleteDfsRoot() { // Select this node to make sure m_MmcRepList populated if (m_MmcRepList.empty()) m_lpConsole->SelectScopeItem(m_hScopeItem); // check outstanding property sheet, discontinue if any. HRESULT hr = CloseAllPropertySheets(FALSE); if (S_OK != hr) return hr; // Confirm with the user, if he wants to delete this dfs root hr = ConfirmOperationOnDfsRoot(IDS_MSG_DELETE_DFSROOT); if (S_OK != hr) return hr; if (DFS_TYPE_STANDALONE == m_lDfsRootType) { CComBSTR bstrDfsServer; CComBSTR bstrRootShare; hr = m_DfsRoot->GetOneDfsHost(&bstrDfsServer, &bstrRootShare); if (SUCCEEDED(hr)) hr = _DeleteDfsRoot(bstrDfsServer, bstrRootShare, NULL); if (SUCCEEDED(hr)) { CleanScopeChildren(); // Delete the item from Scope Pane m_lpConsoleNameSpace->DeleteItem(m_hScopeItem, TRUE); // Delete it from the internal list m_pParent->DeleteMmcRootNode(this); Release(); // delete this CMmcDfsRoot object return S_OK; } return hr; } // // delete the replica set associated with the root (the internal link) // hr = OnStopReplication(); if (S_FALSE == hr) { // this root has already been deleted by others, no more reference // OnStopReplication has already called OnRefresh and popped up the msgbox return hr; } // // delete the rest of replica sets related to this Dfs root // (void)m_DfsRoot->DeleteAllReplicaSets(); // // remove root alternates // UINT nSize = m_MmcRepList.size(); DFS_REPLICA_LIST::iterator i; while (nSize >= 1) { i = m_MmcRepList.begin(); hr = (*i)->pReplica->RemoveReplica(); BREAK_IF_FAILED(hr); nSize--; } if (FAILED(hr)) DisplayMessageBoxForHR(hr); return hr; } STDMETHODIMP CMmcDfsRoot::OnDeleteDisplayedDfsLinks() { // make sure all property pages are closed HRESULT hr = ClosePropertySheetsOfAllLinks(FALSE); if (S_OK != hr) return hr; // property page found, discontinue // Confirm with the user, if he wants to delete all the displayed dfs links hr = ConfirmDeleteDisplayedDfsLinks(); if (S_OK != hr) return hr; CWaitCursor wait; ULONG ulSize = m_MmcJPList.size(); BOOL bSetNoFilter = TRUE; if (m_lLinkFilterType != FILTERDFSLINKS_TYPE_NO_FILTER) { ULONG ulNumOfJPsFiltered = 0; m_DfsRoot->get_CountOfDfsJunctionPointsFiltered((long*)&ulNumOfJPsFiltered); if (ulNumOfJPsFiltered > ulSize) bSetNoFilter = FALSE; } DFS_JUNCTION_LIST::iterator i; while (ulSize >= 1) { i = m_MmcJPList.begin(); hr = ((*i)->pJPoint)->OnRemoveJP(FALSE); BREAK_IF_FAILED(hr); ulSize--; } if (FAILED(hr)) { DisplayMessageBoxForHR(hr); } else { if (bSetNoFilter) m_lLinkFilterType = FILTERDFSLINKS_TYPE_NO_FILTER; // update the scope pane with new filtered links hr = OnRefresh(); if (S_FALSE == hr) { // this root has already been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); } } return hr; } STDMETHODIMP CMmcDfsRoot :: OnFilterDfsLinks( ) /*++ Routine Description: This method handles the link filter options. Display a dialog box to get the user input. --*/ { HRESULT hr = ClosePropertySheetsOfAllLinks(FALSE); if (S_OK != hr) return hr; // property sheet found, discontinue CFilterDfsLinks FilterDfsLinksDlg; hr = FilterDfsLinksDlg.put_EnumFilterType(m_lLinkFilterType); RETURN_IF_FAILED(hr); if (m_lLinkFilterType != FILTERDFSLINKS_TYPE_NO_FILTER) { hr = FilterDfsLinksDlg.put_EnumFilter(m_bstrLinkFilterName); RETURN_IF_FAILED(hr); } hr = FilterDfsLinksDlg.put_MaxLimit(m_ulLinkFilterMaxLimit); RETURN_IF_FAILED(hr); hr = FilterDfsLinksDlg.DoModal(); RETURN_IF_NOT_S_OK(hr); CWaitCursor wait; ULONG ulMaxLimit = 0; hr = FilterDfsLinksDlg.get_MaxLimit(&ulMaxLimit); RETURN_IF_FAILED(hr); FILTERDFSLINKS_TYPE lLinkFilterType = FILTERDFSLINKS_TYPE_NO_FILTER; hr = FilterDfsLinksDlg.get_EnumFilterType(&lLinkFilterType); RETURN_IF_FAILED(hr); CComBSTR bstrFilterName; if (lLinkFilterType != FILTERDFSLINKS_TYPE_NO_FILTER) { hr = FilterDfsLinksDlg.get_EnumFilter(&bstrFilterName); RETURN_IF_FAILED(hr); } m_lLinkFilterType = lLinkFilterType; m_bstrLinkFilterName = bstrFilterName; m_ulLinkFilterMaxLimit = ulMaxLimit; dfsDebugOut((_T("m_lLinkFilterType=%d, m_bstrLinkFilterName=%s, m_ulLinkFilterMaxLimit=%d\n"), m_lLinkFilterType, m_bstrLinkFilterName, m_ulLinkFilterMaxLimit)); hr = OnRefresh(); if (S_FALSE == hr) { // this root has already been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); } return hr; } HRESULT CMmcDfsRoot::SetDescriptionBarText( IN LPRESULTDATA i_lpResultData ) /*++ Routine Description: A routine used set the text in the Description bar above the result view. Arguments: i_lpResultData - Pointer to the IResultData callback which is used to set the description text --*/ { RETURN_INVALIDARG_IF_NULL(i_lpResultData); CComBSTR bstrTextForDescriptionBar; HRESULT hr = FormatResourceString(IDS_DESCRIPTION_BAR_TEXT_ROOT, m_bstrDisplayName, &bstrTextForDescriptionBar); if (SUCCEEDED(hr)) hr = i_lpResultData->SetDescBarText(bstrTextForDescriptionBar); return hr; } HRESULT CMmcDfsRoot::SetStatusText( IN LPCONSOLE2 i_lpConsole ) /*++ Routine Description: Set the text in the Status bar. Arguments: i_lpConsole - IConsole2 from IComponent --*/ { RETURN_INVALIDARG_IF_NULL(i_lpConsole); ULONG ulTotalNumOfJPs = 0; HRESULT hr = m_DfsRoot->get_CountOfDfsJunctionPoints((long*)&ulTotalNumOfJPs); RETURN_IF_FAILED(hr); ULONG ulDisplayedNumOfJPs = m_MmcJPList.size(); CComBSTR bstrText; hr = FormatMessageString(&bstrText, 0, IDS_STATUS_BAR_TEXT_ROOT, ulDisplayedNumOfJPs, ulTotalNumOfJPs); if (SUCCEEDED(hr)) hr = i_lpConsole->SetStatusText(bstrText); return hr; } STDMETHODIMP CMmcDfsRoot::EnumerateResultPane( IN OUT IResultData* io_pResultData ) /*++ Routine Description: To eumerate(add) items in the result pane. Root level Replicas in this case Arguments: io_pResultData - The callback used to add items to the Result pane --*/ { RETURN_INVALIDARG_IF_NULL(io_pResultData); HRESULT hr = S_OK; if (m_MmcRepList.empty()) { CComPtr pRepEnum; hr = m_DfsRoot->get_RootReplicaEnum((IUnknown**) &pRepEnum); RETURN_IF_FAILED(hr); VARIANT varReplicaObject; VariantInit(&varReplicaObject); while ( S_OK == (hr = pRepEnum->Next(1, &varReplicaObject, NULL)) ) { CComPtr pReplicaObject = (IDfsReplica*) varReplicaObject.pdispVal; CMmcDfsReplica* pMMCReplicaObject = new CMmcDfsReplica(pReplicaObject, this); if (!pMMCReplicaObject) { hr = E_OUTOFMEMORY; } else { hr = pMMCReplicaObject->m_hrValueFromCtor; if (SUCCEEDED(hr)) hr = pMMCReplicaObject->AddItemToResultPane(io_pResultData); if (SUCCEEDED(hr)) { REP_LIST_NODE* pRepNode = new REP_LIST_NODE (pMMCReplicaObject); if (!pRepNode) hr = E_OUTOFMEMORY; else m_MmcRepList.push_back(pRepNode); } if (FAILED(hr)) delete pMMCReplicaObject; } VariantClear(&varReplicaObject); if (FAILED(hr)) break; } // while } else { // The replicas of this junction are already enumerated, // and the list exists, just add result items. for (DFS_REPLICA_LIST::iterator i = m_MmcRepList.begin(); i != m_MmcRepList.end(); i++) { hr = ((*i)->pReplica)->AddItemToResultPane(io_pResultData); BREAK_IF_FAILED(hr); } } return hr; } STDMETHODIMP CMmcDfsRoot::QueryPagesFor( ) /*++ Routine Description: Used to decide whether the object wants to display property pages. Returning S_OK typically results in a call to CreatePropertyPages. --*/ { // bug#543194: ask user to close all other open property pages before we bring up the root properties. // This is because the OnRefresh() below will close them silently and we have to call OnRefresh // to pick up possible namespace updates by other DfsGui instances. if (S_FALSE == CloseAllPropertySheets(FALSE)) return S_FALSE; // // refresh to pick up possible namespace updates by others // HRESULT hr = OnRefresh(); if (S_FALSE == hr) { // this root has been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; // no property page } return S_OK; // since we want to display a propertysheet. } // Creates and passes back the pages to be displayed STDMETHODIMP CMmcDfsRoot::CreatePropertyPages( IN LPPROPERTYSHEETCALLBACK i_lpPropSheetCallback, IN LONG_PTR i_lNotifyHandle ) /*++ Routine Description: Used to display the property sheet pages Arguments: i_lpPropSheetCallback - The callback used to create the propertysheet. i_lNotifyHandle - Notify handle used by the property page Return value: S_OK since we want to display a propertysheet. --*/ { RETURN_INVALIDARG_IF_NULL(i_lpPropSheetCallback); m_lpConsole->SelectScopeItem(m_hScopeItem); CWaitCursor WaitCursor; HRESULT hr = S_OK; do { hr = m_PropPage.Initialize((IDfsRoot*)m_DfsRoot, NULL); BREAK_IF_FAILED(hr); // Create the page for the replica set. // Pass it to the Callback HPROPSHEETPAGE h_proppage = m_PropPage.Create(); if (!h_proppage) hr = HRESULT_FROM_WIN32(::GetLastError()); BREAK_IF_FAILED(hr); // Pass on the notify data to the Property Page hr = m_PropPage.SetNotifyData(i_lNotifyHandle, (LPARAM)this); BREAK_IF_FAILED(hr); hr = i_lpPropSheetCallback->AddPage(h_proppage); BREAK_IF_FAILED(hr); // // Create "Replica Set" page // hr = CreateFrsPropertyPage(i_lpPropSheetCallback, i_lNotifyHandle); if (S_OK != hr) { if (FAILED(hr)) DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_REPPAGE_ERROR); hr = S_OK; // allow the other tabs to be brought up } // // Create "Publish" page // hr = CreatePublishPropertyPage(i_lpPropSheetCallback, i_lNotifyHandle); if (S_OK != hr) { if (FAILED(hr)) DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_PUBLISHPAGE_ERROR); hr = S_OK; // allow the other tabs to be brought up } } while (0); if (FAILED(hr)) DisplayMessageBoxForHR(hr); return hr; } STDMETHODIMP CMmcDfsRoot::CreateFrsPropertyPage ( IN LPPROPERTYSHEETCALLBACK i_lpPropSheetCallback, IN LONG_PTR i_lNotifyHandle ) { // // init m_piReplicaSet // HRESULT hr = _InitReplicaSet(); if (S_OK != hr) return hr; CComBSTR bstrType; hr = m_piReplicaSet->get_Type(&bstrType); RETURN_IF_FAILED(hr); if (lstrcmpi(bstrType, FRS_RSTYPE_DFS)) return hr; // // set initial values on the property page // hr = m_frsPropPage.Initialize(m_piReplicaSet); RETURN_IF_FAILED(hr); // // create the property page // HPROPSHEETPAGE h_frsproppage = m_frsPropPage.Create(); if (!h_frsproppage) return HRESULT_FROM_WIN32(::GetLastError()); // // pass on the notify data to the Property Page // hr = m_frsPropPage.SetNotifyData(i_lNotifyHandle, (LPARAM)this); RETURN_IF_FAILED(hr); // // AddPage // return i_lpPropSheetCallback->AddPage(h_frsproppage); } // // m_enumNewSchema is set to SCHEMA_VERSION_UNKNOWN at instance creation time // BOOL CMmcDfsRoot::IsNewSchema() { if (m_enumNewSchema == SCHEMA_VERSION_UNKNOWN) { HRESULT hr = S_OK; if (DFS_TYPE_FTDFS == m_lDfsRootType) { CComBSTR bstrDomainName; hr = m_DfsRoot->get_DomainName(&bstrDomainName); if (SUCCEEDED(hr)) m_enumNewSchema = (S_OK == GetSchemaVersionEx(bstrDomainName, FALSE)) ? SCHEMA_VERSION_NEW : SCHEMA_VERSION_OLD; } else { CComBSTR bstrServer, bstrShare; hr = m_DfsRoot->GetOneDfsHost(&bstrServer, &bstrShare); if (SUCCEEDED(hr)) m_enumNewSchema = (S_OK == GetSchemaVersionEx(bstrServer)) ? SCHEMA_VERSION_NEW : SCHEMA_VERSION_OLD; } } return ((m_enumNewSchema == SCHEMA_VERSION_NEW) ? TRUE : FALSE); } STDMETHODIMP CMmcDfsRoot::CreatePublishPropertyPage ( IN LPPROPERTYSHEETCALLBACK i_lpPropSheetCallback, IN LONG_PTR i_lNotifyHandle ) { // // check schema version // if (!IsNewSchema()) return S_FALSE; // // check group policy // if (!CheckPolicyOnSharePublish()) return S_FALSE; // // create the property page // HPROPSHEETPAGE hpage = m_publishPropPage.Create(); if (!hpage) return HRESULT_FROM_WIN32(::GetLastError()); m_publishPropPage.Initialize(m_DfsRoot); // // pass on the notify data to the Property Page // HRESULT hr = m_publishPropPage.SetNotifyData(i_lNotifyHandle, (LPARAM)this); RETURN_IF_FAILED(hr); // // AddPage // return i_lpPropSheetCallback->AddPage(hpage); } STDMETHODIMP CMmcDfsRoot::PropertyChanged( ) /*++ Routine Description: Used to update the properties. --*/ { return S_OK; } HRESULT CMmcDfsRoot::ToolbarSelect( IN const LONG i_lArg, IN IToolbar* i_pToolBar ) /*++ Routine Description: Handle a select event for a toolbar Create a toolbar, it it doesn't exist. Attach the toolbar and enable the buttons, if the event for a selection. Disable the buttons, if the event was for a deselection Arguments: i_lArg - The argument passed to the actual method. i_pToolBar - Pointer to Toolbar. --*/ { RETURN_INVALIDARG_IF_NULL(i_pToolBar); BOOL bSelect = (BOOL) HIWORD(i_lArg); // Is the event for selection? EnableToolbarButtons(i_pToolBar, IDT_ROOT_MIN, IDT_ROOT_MAX, bSelect); if (bSelect) // Should we disable or enable the toolbar? { BOOL bReplicaSetExist = FALSE; HRESULT hr = m_DfsRoot->get_ReplicaSetExist(&bReplicaSetExist); RETURN_IF_FAILED(hr); if(DFS_TYPE_STANDALONE == m_lDfsRootType) { i_pToolBar->SetButtonState(IDT_ROOT_NEW_ROOT_REPLICA, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_NEW_ROOT_REPLICA, HIDDEN, TRUE); } if (m_MmcJPList.empty()) { i_pToolBar->SetButtonState(IDT_ROOT_DELETE_DISPLAYED_DFS_LINKS, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_DELETE_DISPLAYED_DFS_LINKS, HIDDEN, TRUE); } if (bReplicaSetExist || 1 >= m_MmcRepList.size()) { i_pToolBar->SetButtonState(IDT_ROOT_REPLICATION_TOPOLOGY, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_REPLICATION_TOPOLOGY, HIDDEN, TRUE); } if (!bReplicaSetExist) { i_pToolBar->SetButtonState(IDT_ROOT_SHOW_REPLICATION, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_SHOW_REPLICATION, HIDDEN, TRUE); i_pToolBar->SetButtonState(IDT_ROOT_HIDE_REPLICATION, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_HIDE_REPLICATION, HIDDEN, TRUE); i_pToolBar->SetButtonState(IDT_ROOT_STOP_REPLICATION, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_STOP_REPLICATION, HIDDEN, TRUE); } else { if (m_bShowFRS) { i_pToolBar->SetButtonState(IDT_ROOT_SHOW_REPLICATION, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_SHOW_REPLICATION, HIDDEN, TRUE); } else { i_pToolBar->SetButtonState(IDT_ROOT_HIDE_REPLICATION, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_HIDE_REPLICATION, HIDDEN, TRUE); } } // excluded when empty root container if (m_MmcRepList.empty()) { i_pToolBar->SetButtonState(IDT_ROOT_NEW_DFS_LINK, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_NEW_DFS_LINK, HIDDEN, TRUE); i_pToolBar->SetButtonState(IDT_ROOT_CHECK_STATUS, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_CHECK_STATUS, HIDDEN, TRUE); i_pToolBar->SetButtonState(IDT_ROOT_FILTER_DFS_LINKS, ENABLED, FALSE); i_pToolBar->SetButtonState(IDT_ROOT_FILTER_DFS_LINKS, HIDDEN, TRUE); } } return S_OK; } HRESULT CMmcDfsRoot::CreateToolbar( IN const LPCONTROLBAR i_pControlbar, IN const LPEXTENDCONTROLBAR i_lExtendControlbar, OUT IToolbar** o_ppToolBar ) /*++ Routine Description: Create the toolbar. Involves the actual toolbar creation call, creating the bitmap and adding it and finally adding the buttons to the toolbar Arguments: i_pControlbar - The controlbar used to create toolbar. i_lExtendControlbar - The object implementing IExtendControlbar. This is the class exposed to MMC. o_ppToolBar - The Toolbar pointer. --*/ { RETURN_INVALIDARG_IF_NULL(i_pControlbar); RETURN_INVALIDARG_IF_NULL(i_lExtendControlbar); RETURN_INVALIDARG_IF_NULL(o_ppToolBar); // Create the toolbar HRESULT hr = i_pControlbar->Create(TOOLBAR, i_lExtendControlbar, reinterpret_cast(o_ppToolBar)); RETURN_IF_FAILED(hr); // Add the bitmap to the toolbar hr = AddBitmapToToolbar(*o_ppToolBar, IDB_ROOT_TOOLBAR); RETURN_IF_FAILED(hr); int iButtonPosition = 0; // The first button position for (int iCommandID = IDT_ROOT_MIN, iMenuResource = IDS_MENUS_ROOT_TOP_NEW_DFS_LINK; iCommandID <= IDT_ROOT_MAX; iCommandID++,iMenuResource++,iButtonPosition++) { CComBSTR bstrMenuText; CComBSTR bstrToolTipText; hr = GetMenuResourceStrings(iMenuResource, &bstrMenuText, &bstrToolTipText, NULL); RETURN_IF_FAILED(hr); MMCBUTTON ToolbarButton; ZeroMemory(&ToolbarButton, sizeof ToolbarButton); ToolbarButton.nBitmap = iButtonPosition; ToolbarButton.idCommand = iCommandID; ToolbarButton.fsState = TBSTATE_ENABLED; ToolbarButton.fsType = TBSTYLE_BUTTON; ToolbarButton.lpButtonText = bstrMenuText; // not used anyway ToolbarButton.lpTooltipText = bstrToolTipText; // Add the button to the toolbar hr = (*o_ppToolBar)->InsertButton(iButtonPosition, &ToolbarButton); BREAK_IF_FAILED(hr); } return hr; } STDMETHODIMP CMmcDfsRoot::ToolbarClick( IN const LPCONTROLBAR i_pControlbar, IN const LPARAM i_lParam ) /*++ Routine Description: Action to take on a click on a toolbar Arguments: i_pControlbar - The controlbar used to create toolbar. i_lParam - The lparam to the actual notify. This is the command id of the button on which a click occurred. --*/ { RETURN_INVALIDARG_IF_NULL(i_pControlbar); HRESULT hr = S_OK; switch(i_lParam) { case IDT_ROOT_NEW_DFS_LINK: hr = OnCreateNewJunctionPoint (); break; case IDT_ROOT_NEW_ROOT_REPLICA: hr = OnNewRootReplica(); break; case IDT_ROOT_CHECK_STATUS: hr = OnCheckStatus(); break; case IDT_ROOT_DELETE_DISPLAYED_DFS_LINKS: hr = OnDeleteDisplayedDfsLinks(); break; case IDT_ROOT_DELETE_CONNECTION_TO_DFS_ROOT: hr = OnDeleteConnectionToDfsRoot(); break; case IDT_ROOT_DELETE_DFS_ROOT: hr = OnDeleteDfsRoot(); break; case IDT_ROOT_FILTER_DFS_LINKS: hr = OnFilterDfsLinks(); break; case IDT_ROOT_REPLICATION_TOPOLOGY: hr = OnNewReplicaSet(); break; case IDT_ROOT_SHOW_REPLICATION: case IDT_ROOT_HIDE_REPLICATION: m_bShowFRS = !m_bShowFRS; hr = OnShowReplication(); break; case IDT_ROOT_STOP_REPLICATION: hr = OnStopReplication(TRUE); if (FAILED(hr)) DisplayMessageBoxForHR(hr); break; default: hr = E_INVALIDARG; break; }; return hr; } HRESULT CMmcDfsRoot::ClosePropertySheet(BOOL bSilent) { if (!m_PropPage.m_hWnd && !m_frsPropPage.m_hWnd && !m_publishPropPage.m_hWnd) return S_OK; // no outstanding property sheet, return S_OK; // // handle property sheet for the root // CComPtr pPropSheetProvider; HRESULT hr = m_lpConsole->QueryInterface(IID_IPropertySheetProvider, reinterpret_cast(&pPropSheetProvider)); if (FAILED(hr)) { hr = S_OK; // ignore the QI failure } else { // // find outstanding property sheet and bring it to foreground // hr = pPropSheetProvider->FindPropertySheet((MMC_COOKIE)m_hScopeItem, NULL, this); if (S_OK == hr) { if (!bSilent) { // // ask user to close it, return S_FALSE to quit user's operation // DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_PROPERTYPAGE_NOTCLOSED); return S_FALSE; } else { // // silently close the property sheet, return S_OK // if (m_PropPage.m_hWnd) ::SendMessage(m_PropPage.m_hWnd, WM_PARENT_NODE_CLOSING, 0, 0); if (m_frsPropPage.m_hWnd) ::SendMessage(m_frsPropPage.m_hWnd, WM_PARENT_NODE_CLOSING, 0, 0); if (m_publishPropPage.m_hWnd) ::SendMessage(m_publishPropPage.m_hWnd, WM_PARENT_NODE_CLOSING, 0, 0); } } else { hr = S_OK; // no outstanding property sheet, return S_OK } } // // reset HWND // m_PropPage.m_hWnd = NULL; m_frsPropPage.m_hWnd = NULL; m_publishPropPage.m_hWnd = NULL; return hr; } HRESULT CMmcDfsRoot::ClosePropertySheetsOfAllLinks(BOOL bSilent) { HRESULT hr = S_OK; // // handle property sheets for its links // if (!m_MmcJPList.empty()) { for (DFS_JUNCTION_LIST::iterator i = m_MmcJPList.begin(); i != m_MmcJPList.end(); i++) { hr = ((*i)->pJPoint)->ClosePropertySheet(bSilent); if (!bSilent && S_FALSE == hr) return S_FALSE; // found an outstanding one for a link, return S_FALSE to quit user's operation } } return S_OK; } // Close all outstanding property sheets for its own and its links // Return: S_OK if there is no open property sheet, or they have all been closed silently // Return: S_FALSE if an open sheet is found and msgbox poped up to remind user of closing it HRESULT CMmcDfsRoot::CloseAllPropertySheets(BOOL bSilent) { // // handle property sheet for the root // HRESULT hr = ClosePropertySheet(bSilent); if (!bSilent && S_FALSE == hr) return S_FALSE; // // handle property sheets for its links // return ClosePropertySheetsOfAllLinks(bSilent); } HRESULT CMmcDfsRoot::OnRefresh() { // Select this node first m_lpConsole->SelectScopeItem(m_hScopeItem); CWaitCursor wait; HRESULT hr = S_OK; // silently close outstanding property sheet. CloseAllPropertySheets(TRUE); CleanScopeChildren(); CleanResultChildren(); m_bShowFRS = FALSE; if ((IReplicaSet *)m_piReplicaSet) m_piReplicaSet.Release(); // Re-Initialize! hr = m_DfsRoot->Initialize(m_bstrRootEntryPath); if (S_OK != hr) // failt to init the root, or no such root any more, we have to stop managing the root { if (FAILED(hr)) DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_STOP_MANAGING_ROOT); // Delete the item from Scope Pane (void)m_lpConsoleNameSpace->DeleteItem(m_hScopeItem, TRUE); // Delete it from the internal list (void)m_pParent->DeleteMmcRootNode(this); Release(); // delete this CMmcDfsRoot object return S_FALSE; } BOOL bReplicaSetExist = FALSE; CComBSTR bstrDC; (void)m_DfsRoot->get_ReplicaSetExistEx(&bstrDC, &bReplicaSetExist); // Enumerate Junction points (void)EnumerateScopePane(m_lpConsoleNameSpace, m_hScopeItem); // set the root icon if (m_lpConsoleNameSpace != NULL) { SCOPEDATAITEM ScopeDataItem; ZeroMemory(&ScopeDataItem, sizeof(SCOPEDATAITEM)); ScopeDataItem.ID = m_hScopeItem; hr = m_lpConsoleNameSpace->GetItem(&ScopeDataItem); if (SUCCEEDED(hr)) { ScopeDataItem.mask = SDI_IMAGE | SDI_OPENIMAGE; ScopeDataItem.nImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0); ScopeDataItem.nOpenImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0); m_lpConsoleNameSpace->SetItem(&ScopeDataItem); } } // Re-Display Result Pane. m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); return S_OK; } HRESULT CMmcDfsRoot::OnRefreshFilteredLinks() { // Select this node first m_lpConsole->SelectScopeItem(m_hScopeItem); CWaitCursor wait; HRESULT hr = S_OK; CleanScopeChildren(); CleanResultChildren(); m_bShowFRS = FALSE; if ((IReplicaSet *)m_piReplicaSet) m_piReplicaSet.Release(); BOOL bReplicaSetExist = FALSE; CComBSTR bstrDC; hr = m_DfsRoot->get_ReplicaSetExistEx(&bstrDC, &bReplicaSetExist); if (FAILED(hr)) { return OnRefresh(); // fail to access info, see if the root can be contacted or not } // Enumerate Junction points (void)EnumerateScopePane(m_lpConsoleNameSpace, m_hScopeItem); // set the root icon if (m_lpConsoleNameSpace != NULL) { SCOPEDATAITEM ScopeDataItem; ZeroMemory(&ScopeDataItem, sizeof(SCOPEDATAITEM)); ScopeDataItem.ID = m_hScopeItem; hr = m_lpConsoleNameSpace->GetItem(&ScopeDataItem); if (SUCCEEDED(hr)) { ScopeDataItem.mask = SDI_IMAGE | SDI_OPENIMAGE; ScopeDataItem.nImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0); ScopeDataItem.nOpenImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0); m_lpConsoleNameSpace->SetItem(&ScopeDataItem); } } // re-display the result pane items m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); return S_OK; } HRESULT CMmcDfsRoot::_DeleteDfsRoot( IN BSTR i_bstrServerName, IN BSTR i_bstrShareName, IN BSTR i_bstrFtDfsName ) { /*++ Routine Description: Helper member function to actually delete (Stop hosting) the Dfs Root. This is also called to delete root level replica. Arguments: i_bstrServerName - The server on which the Dfs has to be torn down. i_bRootReplica - This DfsRoot is been torn down as Root Replica. i_bstrFtDfsName - The FtDfs name of the Dfs. NULL for Standalone Dfs. --*/ RETURN_INVALIDARG_IF_NULL(i_bstrServerName); RETURN_INVALIDARG_IF_NULL(i_bstrShareName); CWaitCursor WaitCursor; // Display the wait cursor BOOL bNewSchema = IsNewSchema(); HRESULT hr = m_DfsRoot->DeleteDfsHost(i_bstrServerName, i_bstrShareName, FALSE); BOOL bFTDfs = (i_bstrFtDfsName && *i_bstrFtDfsName); if (bFTDfs) { if (FAILED(hr) && HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hr) { if (IDYES == DisplayMessageBox( GetActiveWindow(), MB_YESNO | MB_ICONEXCLAMATION, hr, IDS_MSG_WIZ_DELETE_FAILURE_RETRY, i_bstrServerName)) { // force delete hr = m_DfsRoot->DeleteDfsHost(i_bstrServerName, i_bstrShareName, TRUE); } else { // leave it alone hr = S_FALSE; } } } if (FAILED(hr)) DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_WIZ_DELETE_FAILURE, i_bstrServerName); // // delete volume object if it's standalone // if (SUCCEEDED(hr) && !bFTDfs && bNewSchema) { (void) ModifySharePublishInfoOnSARoot( i_bstrServerName, i_bstrShareName, FALSE, NULL, NULL, NULL, NULL ); } return hr; } STDMETHODIMP CMmcDfsRoot::RemoveFromMMC() { HRESULT hr = S_OK; if (m_hScopeItem) { if (!m_MmcJPList.empty()) { // clean up the display objects for (DFS_JUNCTION_LIST::iterator i = m_MmcJPList.begin(); i != m_MmcJPList.end(); i++) { (*i)->pJPoint->RemoveFromMMC(); } } // delete result pane items m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 0); // delete itself from MMC scope pane (void)m_lpConsoleNameSpace->DeleteItem(m_hScopeItem, TRUE); m_hScopeItem = NULL; } return S_OK; } STDMETHODIMP CMmcDfsRoot::CleanScopeChildren() { HRESULT hr = S_OK; if (!m_MmcJPList.empty()) { // clean up the display objects for (DFS_JUNCTION_LIST::iterator i = m_MmcJPList.begin(); i != m_MmcJPList.end(); i++) { (*i)->pJPoint->RemoveFromMMC(); delete (*i); } m_MmcJPList.erase(m_MmcJPList.begin(), m_MmcJPList.end()); } return S_OK; } STDMETHODIMP CMmcDfsRoot::CleanResultChildren( ) { if (!m_MmcRepList.empty()) { // delete result pane items m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 0); // delete display object for (DFS_REPLICA_LIST::iterator i = m_MmcRepList.begin(); i != m_MmcRepList.end(); i++) { delete (*i); } m_MmcRepList.erase(m_MmcRepList.begin(), m_MmcRepList.end()); } return(S_OK); } STDMETHODIMP CMmcDfsRoot::RefreshResultChildren( ) { CleanResultChildren(); m_DfsRoot->RefreshRootReplicas(); // Send View change notification for all veiws. m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); return(S_OK); } STDMETHODIMP CMmcDfsRoot::ViewChange( IResultData* i_pResultData, LONG_PTR i_lHint ) /*++ Routine Description: This method handles the MMCN_VIEW_CHANGE notification. This updates the result view for the scope node on which the UpdateAllViews was called. if (0 == i_lHint) clean result pane only. --*/ { RETURN_INVALIDARG_IF_NULL(i_pResultData); i_pResultData->DeleteAllRsltItems(); CComPtr spiHeader; HRESULT hr = i_pResultData->QueryInterface(IID_IHeaderCtrl2, reinterpret_cast(&spiHeader)); RETURN_IF_FAILED(hr); if (m_bShowFRS) { CComBSTR bstrColumn3; hr = LoadStringFromResource(IDS_RESULT_COLUMN_FRS, &bstrColumn3); RETURN_IF_FAILED(hr); spiHeader->DeleteColumn(3); spiHeader->InsertColumn(3, bstrColumn3, LVCFMT_LEFT, MMCLV_AUTO); } else { spiHeader->DeleteColumn(3); } if (i_lHint) EnumerateResultPane(i_pResultData); return(S_OK); } STDMETHODIMP CMmcDfsRoot::AddResultPaneItem( CMmcDfsReplica* i_pReplicaDispObject ) /*++ Routine Description: This method adds a new replica object to the list of replicas displayed in the result view. Arguments: i_pReplicaDispObject - The CMmcReplica display object pointer.. --*/ { REP_LIST_NODE* pNewReplica = new REP_LIST_NODE(i_pReplicaDispObject); if (!pNewReplica) return E_OUTOFMEMORY; m_MmcRepList.push_back(pNewReplica); // Re-display to display this item. m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); return S_OK; } // // This function is called when deleting a link from the scope pane // STDMETHODIMP CMmcDfsRoot::RemoveJP(CMmcDfsJunctionPoint *i_pJPoint, LPCTSTR i_pszDisplayName) { if (!i_pJPoint || !i_pszDisplayName) return E_INVALIDARG; CWaitCursor wait; CComBSTR bstrDisplayName = i_pszDisplayName; HRESULT hr = i_pJPoint->OnRemoveJP(); if (FAILED(hr)) { DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_MSG_WIZ_DELETE_JP_FAILURE, bstrDisplayName); return hr; } return hr; } // // This function is called when removing a target from the result pane // STDMETHODIMP CMmcDfsRoot::RemoveReplica(LPCTSTR i_pszDisplayName) { if (!i_pszDisplayName) return E_INVALIDARG; // // refresh to pick up possible namespace updates on root targets by other means // HRESULT hr = OnRefresh(); if (S_FALSE == hr) { // this root has already been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } CWaitCursor wait; // // locate the correct target to remove, then call back // for (DFS_REPLICA_LIST::iterator i = m_MmcRepList.begin(); i != m_MmcRepList.end(); i++) { if (!lstrcmpi((*i)->pReplica->m_bstrDisplayName, i_pszDisplayName)) { if (m_MmcRepList.size() == 1) { // // We're going to tear down the whole DFS namespace, make sure that // we delete the rest of replica sets related to this Dfs root // (void)m_DfsRoot->DeleteAllReplicaSets(); } hr = (*i)->pReplica->RemoveReplica(); break; } } return hr; } STDMETHODIMP CMmcDfsRoot::RemoveResultPaneItem( CMmcDfsReplica* i_pReplicaDispObject ) /*++ Routine Description: This method removes a replica object from the list of replicas displayed in the result view. Arguments: i_pReplicaDispObject - The CMmcReplica display object pointer.. --*/ { dfsDebugOut((_T("CMmcDfsRoot::RemoveResultPaneItem jplist=%d, replist=%d\n"), m_MmcJPList.size(), m_MmcRepList.size())); // Remove item from list. for (DFS_REPLICA_LIST::iterator i = m_MmcRepList.begin(); i != m_MmcRepList.end(); i++) { if ((*i)->pReplica == i_pReplicaDispObject) { delete (*i); m_MmcRepList.erase(i); break; } } // Last node is removed. if (m_MmcRepList.empty()) { // silently close any open property sheet CloseAllPropertySheets(TRUE); CleanScopeChildren(); // Delete the item from Scope Pane HRESULT hr = m_lpConsoleNameSpace->DeleteItem(m_hScopeItem, TRUE); RETURN_IF_FAILED(hr); // Delete it from the internal list hr = m_pParent->DeleteMmcRootNode(this); RETURN_IF_FAILED(hr); Release(); // delete this CMmsDfsRoot object } else { // Re-display to remove this item. m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1); } return S_OK; } STDMETHODIMP CMmcDfsRoot::OnCheckStatus() { // // refresh to pick up possible namespace updates on targets by others // HRESULT hr = OnRefresh(); if (S_FALSE == hr) { // this root has been deleted by others, no more reference DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, IDS_INVALID_ROOT); return hr; } CWaitCursor wait; UINT nTotal = m_MmcRepList.size(); _ASSERT(nTotal != 0); UINT nMappingOn = 0; UINT nMappingOff = 0; UINT nUnreachable = 0; // Update state of all replicas also. for (DFS_REPLICA_LIST::iterator i = m_MmcRepList.begin(); i != m_MmcRepList.end(); i++) { (*i)->pReplica->OnCheckStatus(); if (DFS_TARGET_STATE_UNREACHABLE == (*i)->pReplica->m_lTargetState) { nUnreachable++; } else { switch ((*i)->pReplica->m_lReferralState) { case DFS_REFERRAL_STATE_ONLINE: nMappingOn++; break; case DFS_REFERRAL_STATE_OFFLINE: nMappingOff++; break; default: _ASSERT(FALSE); break; } } } if (0xffffffff != GetFileAttributes(m_bstrRootEntryPath)) { if (nTotal == nMappingOn) { m_lRootJunctionState = DFS_JUNCTION_STATE_ALL_REP_OK; } else if (nTotal != (nMappingOff + nUnreachable)) { m_lRootJunctionState = DFS_JUNCTION_STATE_NOT_ALL_REP_OK; } else { m_lRootJunctionState = DFS_JUNCTION_STATE_UNREACHABLE; } } else { m_lRootJunctionState = DFS_JUNCTION_STATE_UNREACHABLE; } BOOL bReplicaSetExist = FALSE; hr = m_DfsRoot->get_ReplicaSetExist(&bReplicaSetExist); RETURN_IF_FAILED(hr); if (m_lpConsoleNameSpace) { SCOPEDATAITEM ScopeDataItem; ZeroMemory(&ScopeDataItem, sizeof(SCOPEDATAITEM)); ScopeDataItem.ID = m_hScopeItem; hr = m_lpConsoleNameSpace->GetItem(&ScopeDataItem);// Get the item data RETURN_IF_FAILED(hr); ScopeDataItem.mask = SDI_IMAGE | SDI_OPENIMAGE; // Set the image flag ScopeDataItem.nImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0) + m_lRootJunctionState; // Specify the bitmap to use ScopeDataItem.nOpenImage = CMmcDfsRoot::m_iIMAGEINDEX + ((DFS_TYPE_FTDFS == m_lDfsRootType)? 4 : 0) + (bReplicaSetExist ? 4 : 0) + m_lRootJunctionState; // Specify the bitmap to use hr = m_lpConsoleNameSpace->SetItem(&ScopeDataItem); // set the updated item data RETURN_IF_FAILED(hr); } return hr; } HRESULT CMmcDfsRoot::GetIReplicaSetPtr(IReplicaSet** o_ppiReplicaSet) { RETURN_INVALIDARG_IF_NULL(o_ppiReplicaSet); HRESULT hr = _InitReplicaSet(); if (S_OK == hr) { m_piReplicaSet.p->AddRef(); *o_ppiReplicaSet = m_piReplicaSet; } return hr; }