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.
 
 
 
 
 
 

2756 lines
76 KiB

/*++
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 <winuser.h>
#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 <lmdfs.h>
#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);
HRESULT hr = S_OK;
m_DfsRoot = i_pDfsRoot; // Save the IDfsRoot pointer
m_pParent = i_pMmcDfsAdmin; // Save the parent pointer
m_lpConsole = i_lpConsole; // Save the console pointer
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);
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);
m_bNewSchema = (S_OK == GetSchemaVersionEx(bstrDomainName, FALSE));
} else
{
m_bstrDisplayName = m_bstrRootEntryPath;
MMC_DISP_CTOR_RETURN_OUTOFMEMORY_IF_NULL((BSTR)m_bstrDisplayName);
CComBSTR bstrServer, bstrShare;
hr = m_DfsRoot->GetOneDfsHost(&bstrServer, &bstrShare);
MMC_DISP_CTOR_RETURN_HR_IF_FAILED(hr);
m_bNewSchema = (S_OK == GetSchemaVersionEx(bstrServer));
}
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);
HRESULT hr = S_OK;
BOOL bReplicaSetExist = FALSE;
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<LPARAM>(this);
ScopeItemDfsRoot.displayname = (unsigned short *) MMC_CALLBACK;
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);
// select the node to populate m_MmcRepList
m_lpConsole->SelectScopeItem(m_hScopeItem);
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
};
BOOL bReplicaSetExist = FALSE;
HRESULT 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++ )
{
CONTEXTMENUITEM 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;
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 = i_lpContextMenuCallback->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()
{
HRESULT hr = S_OK;
if (m_lDfsRootType != DFS_TYPE_FTDFS)
return S_FALSE; // no replica set associate with standalone root
BOOL bReplicaSetExist = FALSE;
CComBSTR bstrDC;
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;
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());
//CNewReplicaSetPage3 WizPage3(&ReplicaSetInfo);
CComPtr<IPropertySheetCallback> pPropSheetCallback; // MMC Callback used to add pages
hr = m_lpConsole->QueryInterface(IID_IPropertySheetCallback, reinterpret_cast<void**>(&pPropSheetCallback));
RETURN_IF_FAILED(hr);
CComPtr<IPropertySheetProvider> pPropSheetProvider; // MMC callback used to handle wizard
hr = m_lpConsole->QueryInterface(IID_IPropertySheetProvider, reinterpret_cast<void**>(&pPropSheetProvider));
RETURN_IF_FAILED(hr);
//
// Create the wizard
//
hr = pPropSheetProvider->CreatePropertySheet(
_T(""), // title
FALSE, // Wizard and not property sheet.
0, // Cookie
NULL, // IDataobject
MMC_PSO_NEWWIZARDTYPE); // Creation flags
RETURN_IF_FAILED(hr);
hr = pPropSheetCallback->AddPage(WizPage0.Create());
RETURN_IF_FAILED(hr);
hr = pPropSheetCallback->AddPage(WizPage1.Create());
RETURN_IF_FAILED(hr);
hr = pPropSheetCallback->AddPage(WizPage2.Create());
RETURN_IF_FAILED(hr);
/*hr = pPropSheetCallback->AddPage(WizPage3.Create());
RETURN_IF_FAILED(hr); */
// Ask the provider to use the pages from the callback
hr = pPropSheetProvider->AddPrimaryPages(
//(IComponentData *)(m_pParent->m_pScopeManager),
NULL,
TRUE, // Don't create a notify handle
NULL,
TRUE // Scope pane (not result pane)
);
RETURN_IF_FAILED(hr);
//
// Display the wizard
//
HWND hwndParent = NULL;
hr = m_lpConsole->GetMainWindow(&hwndParent);
RETURN_IF_FAILED(hr);
hr = pPropSheetProvider->Show((LONG_PTR)hwndParent, 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);
RETURN_IF_FAILED(hr);
if (SUCCEEDED(hr))
{
ScopeDataItem.nImage += 4;
ScopeDataItem.nOpenImage += 4;
hr = m_lpConsoleNameSpace->SetItem(&ScopeDataItem);
}
m_lpConsole->SelectScopeItem(m_hScopeItem);
}
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;
}
m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1);
m_lpConsole->SelectScopeItem(m_hScopeItem);
return hr;
}
HRESULT
CMmcDfsRoot::OnStopReplication(BOOL bConfirm /* = 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;
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;
(void) m_lpConsoleNameSpace->SetItem(&ScopeDataItem);
}
m_lpConsole->SelectScopeItem(m_hScopeItem);
}
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
m_lpConsole->SelectScopeItem(m_hScopeItem);
RETURN_INVALIDARG_IF_NULL((IConsole*)m_lpConsole);
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
HRESULT 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<IPropertySheetCallback> pPropSheetCallback; // MMC Callback used to add pages
hr = m_lpConsole->QueryInterface(IID_IPropertySheetCallback, reinterpret_cast<void**>(&pPropSheetCallback));
RETURN_IF_FAILED(hr);
CComPtr<IPropertySheetProvider> pPropSheetProvider; // MMC callback used to handle wizard
hr = m_lpConsole->QueryInterface(IID_IPropertySheetProvider, reinterpret_cast<void**>(&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
RETURN_IF_FAILED(hr);
// Create the pages for the wizard. Use the handle return to add to our wizard
hr = pPropSheetCallback->AddPage(WizPage4.Create());
RETURN_IF_FAILED(hr);
hr = pPropSheetCallback->AddPage(WizPage5.Create());
RETURN_IF_FAILED(hr);
hr = pPropSheetCallback->AddPage(WizPage7.Create());
RETURN_IF_FAILED(hr);
_ASSERT(NULL != (m_pParent->m_pScopeManager));
// Ask the provider to use the pages from the callback
hr = pPropSheetProvider->AddPrimaryPages( (IComponentData *)(m_pParent->m_pScopeManager),
TRUE, // Don't create a notify handle
NULL,
TRUE // Scope pane (not result pane)
);
RETURN_IF_FAILED(hr);
HWND hwndMainWin = 0; // MMC main window. Used to make it modal
hr = m_lpConsole->GetMainWindow(&hwndMainWin); // Get the main MMC window
RETURN_IF_FAILED(hr);
// Display the wizard
hr = pPropSheetProvider->Show((LONG_PTR)hwndMainWin, // Parent window of the wizard
0 // Starting page
);
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);
i_piHeaderControl->InsertColumn(0, bstrColumn0, LVCFMT_LEFT, DFS_NAME_COLUMN_WIDTH);
if (m_bShowFRS)
{
CComBSTR bstrColumn1;
hr = LoadStringFromResource(IDS_RESULT_COLUMN_FRS, &bstrColumn1);
RETURN_IF_FAILED(hr);
i_piHeaderControl->InsertColumn(1, bstrColumn1, LVCFMT_LEFT, MMCLV_AUTO);
}
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;
// select the root node
m_lpConsole->SelectScopeItem(m_hScopeItem);
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
)
{
RETURN_INVALIDARG_IF_NULL(i_pJPoint);
dfsDebugOut((_T("CMmcDfsRoot::DeleteMmcJPNode %p, size=%d\n"), i_pJPoint, m_MmcJPList.size()));
for (DFS_JUNCTION_LIST::iterator i = m_MmcJPList.begin(); i != m_MmcJPList.end(); i++)
{
if ((*i)->pJPoint == i_pJPoint)
{
m_MmcJPList.erase(i);
break;
}
}
return(S_OK);
}
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<IEnumVARIANT> 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<IDfsJunctionPoint> 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++;
}
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<IDfsJunctionPoint> 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;
}
}
VariantClear(&varJPObject);
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
m_lpConsole->SelectScopeItem(m_hScopeItem);
// check outstanding property sheet, discontinue if any.
HRESULT hr = CloseAllPropertySheets(FALSE);
if (S_OK != hr)
return hr;
if (DFS_TYPE_STANDALONE == m_lDfsRootType)
{
hr = OnDeleteConnectionToDfsRoot(true);
if (S_OK == hr)
{
CComBSTR bstrDfsServer;
CComBSTR bstrRootShare;
hr = m_DfsRoot->GetOneDfsHost(&bstrDfsServer, &bstrRootShare);
if (SUCCEEDED(hr))
return _DeleteDfsRoot(bstrDfsServer, bstrRootShare, NULL);
}
if (FAILED(hr))
DisplayMessageBoxForHR(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;
//
// 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;
//
// refresh to pick up possible namespace updates by other means on root targets
//
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;
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;
// Enumerate Junction points
(void)EnumerateScopePane(m_lpConsoleNameSpace, m_hScopeItem);
m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 1);
m_lpConsole->SelectScopeItem(m_hScopeItem);
}
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));
return OnRefresh();
}
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);
HRESULT hr = S_OK;
ULONG ulTotalNumOfJPs = 0;
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<IEnumVARIANT> 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<IDfsReplica> 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.
--*/
{
//
// 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 (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 (FAILED(hr))
{
DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_PUBLISHPAGE_ERROR);
hr = S_OK; // allow the other tabs to be brought up
}
/*
//
// Create Security property page for Fault Tolerance DFS root
//
if (DFS_TYPE_FTDFS == m_lDfsRootType)
{
LPTSTR lpszLDAPRoot = NULL;
PLDAP pldap = NULL;
do {
CComBSTR bstrDomainName;
hr = m_DfsRoot->get_DomainName(&bstrDomainName);
BREAK_IF_FAILED(hr);
CComBSTR bstrDfsName;
hr = m_DfsRoot->get_DfsName(&bstrDfsName);
BREAK_IF_FAILED(hr);
CComBSTR bstrServerName;
hr = ConnectToDS(bstrDomainName, &pldap, &bstrServerName);
BREAK_IF_FAILED(hr);
hr = GetLDAPRootPath(pldap, &lpszLDAPRoot);
BREAK_IF_FAILED(hr);
CComBSTR bstrSystemDN;
CComBSTR bstrDfsConfigDN;
CComBSTR bstrFTRootDN;
if (FAILED(hr = ExtendDN(CN_SYSTEM, lpszLDAPRoot, &bstrSystemDN)) ||
FAILED(hr = ExtendDN(CN_DFSCONFIGURATION, bstrSystemDN, &bstrDfsConfigDN)) ||
FAILED(hr = ExtendDN(bstrDfsName, bstrDfsConfigDN, &bstrFTRootDN)) )
break;
CComBSTR bstrObjectPath;
bstrObjectPath = _T("LDAP://");
bstrObjectPath += bstrServerName;
bstrObjectPath += _T("/");
bstrObjectPath += bstrFTRootDN;
hr = CreateDfsSecurityPage(
i_lpPropSheetCallback,
bstrObjectPath,
NULL,
DSSI_IS_ROOT);
} while (0);
if (pldap) CloseConnectionToDS(pldap);
if (lpszLDAPRoot) free(lpszLDAPRoot);
}
*/
} 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);
}
STDMETHODIMP
CMmcDfsRoot::CreatePublishPropertyPage
(
IN LPPROPERTYSHEETCALLBACK i_lpPropSheetCallback,
IN LONG_PTR i_lNotifyHandle
)
{
//
// check schema version
//
if (!m_bNewSchema)
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<LPUNKNOWN*>(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<IPropertySheetProvider> pPropSheetProvider;
HRESULT hr = m_lpConsole->QueryInterface(IID_IPropertySheetProvider, reinterpret_cast<void**>(&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);
// Set the selected item in scope pane to this node
m_lpConsole->SelectScopeItem(m_hScopeItem);
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);
// Set the selected item in scope pane to this node
m_lpConsole->SelectScopeItem(m_hScopeItem);
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
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)
{
(void) ModifySharePublishInfoOnSARoot(
i_bstrServerName,
i_bstrShareName,
FALSE,
NULL,
NULL,
NULL,
NULL
);
}
return hr;
}
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++)
{
delete (*i);
}
m_MmcJPList.erase(m_MmcJPList.begin(), m_MmcJPList.end());
// Delete all child items from scope pane.
if (m_lpConsoleNameSpace)
{
HSCOPEITEM hChild = NULL;
MMC_COOKIE lCookie = 0;
while (SUCCEEDED(hr = m_lpConsoleNameSpace->GetChildItem(m_hScopeItem, &hChild, &lCookie)) && hChild)
{
(void)m_lpConsoleNameSpace->DeleteItem(hChild, TRUE);
}
}
}
return S_OK;
}
STDMETHODIMP CMmcDfsRoot::CleanResultChildren(
)
{
if (!m_MmcRepList.empty())
{
// 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());
// delete result pane items
m_lpConsole->UpdateAllViews((IDataObject*)this, 0, 0);
}
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();
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(LPCTSTR i_pszDisplayName)
{
if (!i_pszDisplayName)
return E_INVALIDARG;
//
// refresh to pick up possible namespace updates on links 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 link to remove, then call back.
//
for (DFS_JUNCTION_LIST::iterator i = m_MmcJPList.begin(); i != m_MmcJPList.end(); i++)
{
if (!lstrcmpi((*i)->pJPoint->m_bstrDisplayName, i_pszDisplayName))
{
hr = (*i)->pJPoint->OnRemoveJP();
break;
}
}
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))
{
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();
switch ((*i)->pReplica->m_lReplicaState)
{
case DFS_REPLICA_STATE_ONLINE:
nMappingOn++;
break;
case DFS_REPLICA_STATE_OFFLINE:
nMappingOff++;
break;
case DFS_REPLICA_STATE_UNREACHABLE:
nUnreachable++;
break;
default:
_ASSERT(FALSE);
break;
}
}
long lDfsState = DFS_STATE_REACHABLE;
hr = m_DfsRoot->get_State(&lDfsState);
RETURN_IF_FAILED(hr);
if (DFS_STATE_REACHABLE == lDfsState)
{
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->AddRef();
*o_ppiReplicaSet = m_piReplicaSet;
}
return hr;
}