Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2833 lines
82 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);
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<LPARAM>(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<IContextMenuCallback2> 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<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);
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<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
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<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++;
}
//
// 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<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;
}
} 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<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.
--*/
{
// 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<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);
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<IHeaderCtrl2> spiHeader;
HRESULT hr = i_pResultData->QueryInterface(IID_IHeaderCtrl2, reinterpret_cast<void**>(&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;
}