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
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;
|
|
}
|