Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3914 lines
101 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 1999
//
// File: scoptree.cpp
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#include "scopiter.h"
#include "scopndcb.h"
#include "addsnpin.h"
#include "ScopImag.h"
#include "NodeMgr.h"
#include "amcmsgid.h"
#include "regutil.h"
#include "copypast.h"
#include "multisel.h"
#include "nodepath.h"
#include "tasks.h"
#include "colwidth.h"
#include "viewpers.h"
#include <comdbg.h>
#include "conframe.h"
#include "siprop.h"
#include "fldrsnap.h"
#include "variant.h"
#include "condoc.h"
#include "oncmenu.h"
#include "conview.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifdef DBG
CTraceTag tagScopeTreeAddSnapin(TEXT("CScopeTree"), TEXT("ScAddSnapIn"));
#endif
//############################################################################
//############################################################################
//
// Implementation of class CSnapIns
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
* class CSnapIns
*
*
* PURPOSE: Implements the SnapIns automation interface.
*
*+-------------------------------------------------------------------------*/
class _CSnapIns :
public CMMCIDispatchImpl<SnapIns>,
public CTiedComObject<CScopeTree>
{
protected:
typedef CScopeTree CMyTiedObject;
public:
BEGIN_MMC_COM_MAP(_CSnapIns)
END_MMC_COM_MAP()
// SnapIns interface
public:
MMC_METHOD4(Add, BSTR /*bstrSnapinNameOrCLSID*/, VARIANT /*varParentSnapinNode*/, VARIANT /*varProperties*/, PPSNAPIN /*ppSnapIn*/);
MMC_METHOD2(Item, long /*Index*/, PPSNAPIN /*ppSnapIn*/);
MMC_METHOD1(Remove, PSNAPIN /*pSnapIn*/)
MMC_METHOD1(get_Count, PLONG /*pCount*/);
IUnknown *STDMETHODCALLTYPE get__NewEnum() {return NULL;}
};
// this typedefs the real CSnapIns class. Implements get__NewEnum using CMMCEnumerator and a CSnapIns_Positon object
typedef CMMCNewEnumImpl<_CSnapIns, CScopeTree::CSnapIns_Positon> CSnapIns;
//############################################################################
//############################################################################
//
// Implementation of class CScopeNamespace
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
* class CScopeNamespace
*
*
* PURPOSE: Implements the ScopeNamespace automation interface.
*
*+-------------------------------------------------------------------------*/
class CScopeNamespace :
public CMMCIDispatchImpl<ScopeNamespace>,
public CTiedComObject<CScopeTree>
{
protected:
typedef CScopeTree CMyTiedObject;
public:
BEGIN_MMC_COM_MAP(CScopeNamespace)
END_MMC_COM_MAP()
// ScopeNamespace interface
public:
MMC_METHOD2(GetParent, PNODE /*pNode*/, PPNODE /*ppParent*/);
MMC_METHOD2(GetChild, PNODE /*pNode*/, PPNODE /*ppChild*/);
MMC_METHOD2(GetNext, PNODE /*pNode*/, PPNODE /*ppNext*/);
MMC_METHOD1(GetRoot, PPNODE /*ppRoot*/);
MMC_METHOD1(Expand, PNODE /*pNode*/);
};
//############################################################################
//############################################################################
//
// Implementation of class CMMCScopeNode
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::~CMMCScopeNode
*
* PURPOSE: Destructor
*
* PARAMETERS:
*
* RETURNS:
*
*+-------------------------------------------------------------------------*/
CMMCScopeNode::~CMMCScopeNode()
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::~CMMCScopeNode"));
CScopeTree *pScopeTree = CScopeTree::GetScopeTree();
sc = ScCheckPointers(pScopeTree, E_UNEXPECTED);
if (!sc)
{
sc = pScopeTree->ScUnadviseMMCScopeNode(this);
}
}
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::ScIsValid
*
* PURPOSE: Returns an error if the COM object is no longer valid.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CMMCScopeNode::ScIsValid()
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::ScIsValid"));
if(!GetMTNode())
return (sc = E_INVALIDARG);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::get_Name
*
* PURPOSE: Returns the display name of the node.
*
* PARAMETERS:
* PBSTR pbstrName :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CMMCScopeNode::get_Name( PBSTR pbstrName)
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::get_Name"));
// check parameters
if (!pbstrName)
return ((sc = E_INVALIDARG).ToHr());
CMTNode* pMTNode = GetMTNode();
sc = ScCheckPointers (pMTNode, E_UNEXPECTED);
if (sc)
return (sc.ToHr());
tstring strName = pMTNode->GetDisplayName();
if (strName.empty())
return ((sc = E_UNEXPECTED).ToHr());
USES_CONVERSION;
*pbstrName = ::SysAllocString (T2COLE(strName.data())); // caller frees
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::ScGetDataObject
*
* PURPOSE: Returns the data object for a scope node.
*
* PARAMETERS:
* IDataObject ** ppDataObject :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CMMCScopeNode::ScGetDataObject(IDataObject **ppDataObject)
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::ScGetDataObject"));
sc = ScCheckPointers(ppDataObject);
if(sc)
return sc;
// init out parameter
*ppDataObject = NULL;
// get the MT node
CMTNode *pMTNode = GetMTNode();
sc = ScCheckPointers( pMTNode, E_UNEXPECTED );
if(sc)
return sc;
CComponentData* pCCD = pMTNode->GetPrimaryComponentData();
sc = ScCheckPointers( pCCD, E_NOTIMPL ); // no component data -> no property...
if(sc)
return sc;
// ensure node is expanded before requesting data object
if (pMTNode->WasExpandedAtLeastOnce() == FALSE)
pMTNode->Expand();
// Get the data object for the cookie from the owner snap-in
sc = pCCD->QueryDataObject(pMTNode->GetUserParam(), CCT_SCOPE, ppDataObject);
return sc;
}
/***************************************************************************\
*
* METHOD: CMMCScopeNode::get_Property
*
* PURPOSE: returns snapins property for scope node
*
* PARAMETERS:
* BSTR bstrPropertyName -[in] property name (clipboard format)
* PBSTR pbstrPropertyValue -[out] property value
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
STDMETHODIMP
CMMCScopeNode::get_Property( BSTR bstrPropertyName, PBSTR pbstrPropertyValue )
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::get_Property"));
// parameter check
sc = ScCheckPointers(bstrPropertyName, pbstrPropertyValue);
if (sc)
return sc.ToHr();
// init out parameter
*pbstrPropertyValue = NULL;
IDataObjectPtr spDataObject;
sc = ScGetDataObject(&spDataObject);
if(sc)
return sc.ToHr();
// get the MT node
CMTNode *pMTNode = GetMTNode();
sc = ScCheckPointers( pMTNode, E_UNEXPECTED );
if(sc)
return sc.ToHr();
// try to get the property from the INodeProperties interface
sc = pMTNode->ScGetPropertyFromINodeProperties(spDataObject, bstrPropertyName, pbstrPropertyValue);
if( (!sc.IsError()) && (sc != S_FALSE) ) // got it, exit
return sc.ToHr();
// didn't find it, continue
sc.Clear();
// get the property from data object
sc = CNodeCallback::ScGetProperty(spDataObject, bstrPropertyName, pbstrPropertyValue);
if(sc)
return sc.ToHr();
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::get_Bookmark
*
* PURPOSE: Returns the bookmark of the node (XML format).
*
* PARAMETERS:
* PBSTR pbstrBookmark :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CMMCScopeNode::get_Bookmark( PBSTR pbstrBookmark )
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::get_Bookmark"));
// parameter checking
sc = ScCheckPointers( pbstrBookmark );
if(sc)
return sc.ToHr();
// cleanup result
*pbstrBookmark = NULL;
// get the MT node
CMTNode *pMTNode = GetMTNode();
sc = ScCheckPointers( pMTNode, E_FAIL );
if(sc)
return sc.ToHr();
// get the pointer to bookmark
CBookmark* pBookmark = pMTNode->GetBookmark();
sc = ScCheckPointers( pBookmark, E_UNEXPECTED );
if(sc)
return sc.ToHr();
std::wstring xml_contents;
sc = pBookmark->ScSaveToString(&xml_contents);
if(sc)
return sc.ToHr();
// store the result
CComBSTR bstrBuff(xml_contents.c_str());
*pbstrBookmark = bstrBuff.Detach();
sc = ScCheckPointers( *pbstrBookmark, E_OUTOFMEMORY );
if(sc)
return sc.ToHr();
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::IsScopeNode
*
* PURPOSE: Returns TRUE indicating that the node is a scope node.
*
* PARAMETERS:
* PBOOL pbIsScopeNode :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CMMCScopeNode::IsScopeNode(PBOOL pbIsScopeNode)
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::IsScopeNode"));
// check parameters
if(!pbIsScopeNode)
{
sc = E_UNEXPECTED;
return sc.ToHr();
}
*pbIsScopeNode = TRUE;
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CMMCScopeNode::get_Nodetype
*
* PURPOSE: Returns the nodetype of a scope node.
*
* PARAMETERS:
* PBSTR Nodetype :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CMMCScopeNode::get_Nodetype(PBSTR Nodetype)
{
DECLARE_SC(sc, TEXT("CMMCScopeNode::get_Nodetype"));
// parameter check
sc = ScCheckPointers(Nodetype);
if (sc)
return sc.ToHr();
// init out parameter
*Nodetype = NULL;
// get the data object
IDataObjectPtr spDataObject;
sc = ScGetDataObject(&spDataObject);
if(sc)
return sc.ToHr();
// get the nodetype from the data object
sc = CNodeCallback::ScGetNodetype(spDataObject, Nodetype);
if(sc)
return sc.ToHr();
return sc.ToHr();
}
///////////////////////////////////////////////////////////////////////////////
//
// Forward declaration of local function
//
static SC
ScCreateMTNodeTree(PNEWTREENODE pNew, CMTNode* pmtnParent,
CMTNode** ppNodeCreated);
HRESULT AmcNodeWizard(MID_LIST NewNodeType, CMTNode* pNode, HWND hWnd);
//////////////////////////////////////////////////////////////////////////////
//
// Public variables
//
const wchar_t* AMCSnapInCacheStreamName = L"cash";
const wchar_t* AMCTaskpadListStreamName = L"TaskpadList";
///////////////////////////////////////////////////////////////////////////////
//
// Implementation of CScopeTree class
//
DEBUG_DECLARE_INSTANCE_COUNTER(CScopeTree);
bool CScopeTree::m_fRequireSyncExpand = false;
CScopeTree* CScopeTree::m_pScopeTree = NULL;
IStringTablePrivatePtr CScopeTree::m_spStringTable;
CScopeTree::CScopeTree()
: m_pMTNodeRoot(NULL),
m_pImageCache(NULL),
m_pConsoleData(NULL),
m_pConsoleTaskpads(NULL),
m_pDefaultTaskpads(NULL)
{
DEBUG_INCREMENT_INSTANCE_COUNTER(CScopeTree);
ASSERT (m_pScopeTree == NULL);
m_pScopeTree = this;
}
CScopeTree::~CScopeTree()
{
/*
* Clear out the string table interface (before Cleanup!) to keep
* CMTNode dtors from removing their names from the string table.
*/
m_spStringTable = NULL;
Cleanup();
ASSERT (m_pScopeTree == this);
if (m_pScopeTree == this)
m_pScopeTree = NULL;
DEBUG_DECREMENT_INSTANCE_COUNTER(CScopeTree);
}
HRESULT CScopeTree::SetConsoleData(LPARAM lConsoleData)
{
m_pConsoleData = reinterpret_cast<SConsoleData*>(lConsoleData);
return (S_OK);
}
extern const CLSID CLSID_FolderSnapin;
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetRoot
*
* PURPOSE: Creates the root node if necessary, and returns it. The root node
* is created using the built-in folder snap-in.
*
* PARAMETERS:
* voi d :
*
* RETURNS:
* CMTNode*. If unable to create the root node, the application will exit.
*
*+-------------------------------------------------------------------------*/
CMTNode*
CScopeTree::GetRoot(void)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetRoot"));
if (m_pMTNodeRoot == NULL)
{
CSnapInPtr spSI;
IComponentDataPtr spIComponentData;
CComponentData* pCCD = NULL;
CStr rootName;
// create a new CMTSnapInNode.
// TODO: move this down below the CoCreateInstance and QI for
// ISnapinProperties; if supported, create and pass CSnapinProperties
// to CMTSnapInNode ctor.
CMTSnapInNode *pMTSINodeRoot = new CMTSnapInNode(NULL);
if(NULL == pMTSINodeRoot)
{
sc = E_OUTOFMEMORY;
goto Error;
}
// Create an instance of the snapin
sc = theApp.GetSnapInsCache()->ScGetSnapIn(CLSID_FolderSnapin, &spSI);
if(sc)
goto Error;
sc = CoCreateInstance(CLSID_FolderSnapin, NULL, CLSCTX_INPROC_SERVER, IID_IComponentData, (void **)&spIComponentData);
if(sc)
goto Error;
if(spIComponentData == NULL)
{
sc = E_OUTOFMEMORY;
goto Error;
}
pMTSINodeRoot->SetPrimarySnapIn(spSI);
pCCD = pMTSINodeRoot->GetPrimaryComponentData();
if(!pCCD)
{
sc = E_UNEXPECTED;
goto Error;
}
pCCD->SetIComponentData(spIComponentData);
USES_CONVERSION;
rootName.LoadString(GetStringModule(), IDS_ROOTFOLDER_NAME);
//The code that follows makes use of knowledge of the Folder snapin internals.
//There seems to be no easier way of doing this.
// Need to prevent MMC from putting up the "Save File?" dialog every time.
pMTSINodeRoot->OnRename(true, (LPOLESTR)T2COLE(rootName)); // clever, huh? This just renames the node to Console Root!
pMTSINodeRoot->SetDisplayName(rootName); // this sets the dirty flag
pMTSINodeRoot->SetDirty(false); // this clears it.
// need to tell the snapin to reset its dirty flag - there seems to be no way to avoid this dynamic cast.
CFolderSnapinData *pFolderSnapinpData = dynamic_cast<CFolderSnapinData *>(pCCD->GetIComponentData());
if(!pFolderSnapinpData)
{
sc = E_UNEXPECTED;
goto Error;
}
pMTSINodeRoot->SetPreloadRequired(true); // this is also part of the dirty flag check.
pFolderSnapinpData->SetDirty(false); // clear the dirty flag on the snapin.
theApp.GetSnapInsCache()->SetDirty(false); // need to clear the dirty bit on the snapin cache too.
m_pMTNodeRoot = pMTSINodeRoot;
}
Cleanup:
return m_pMTNodeRoot;
Error:
MMCErrorBox(sc);
exit(1); // Fatal error - cannot continue.
goto Cleanup;
}
STDMETHODIMP CScopeTree::Initialize(HWND hwndFrame, IStringTablePrivate* pStringTable)
{
MMC_TRY
CSnapInsCache* pSnapInsCache = NULL;
/*
* assume invalid argument
*/
SC sc = E_INVALIDARG;
if (hwndFrame == 0)
goto Error;
/*
* assume out of memory from here on
*/
sc = E_OUTOFMEMORY;
pSnapInsCache = new CSnapInsCache;
if (pSnapInsCache == NULL)
goto Error;
theApp.SetSnapInsCache(pSnapInsCache);
m_pImageCache = new CSPImageCache();
if (m_pImageCache == NULL)
goto Error;
ASSERT (pStringTable != NULL);
ASSERT (m_spStringTable == NULL);
m_spStringTable = pStringTable;
// create the ctp list and default ctp list.
ASSERT (m_pConsoleTaskpads == NULL);
m_pConsoleTaskpads = new CConsoleTaskpadList;
if (m_pConsoleTaskpads == NULL)
goto Error;
ASSERT (m_pDefaultTaskpads == NULL);
m_pDefaultTaskpads = new CDefaultTaskpadList;
if (m_pDefaultTaskpads == NULL)
goto Error;
/*
* success!
*/
return (S_OK);
Error:
/*
* clean up everything that might have been allocated
*/
theApp.SetSnapInsCache (NULL);
m_spStringTable = NULL;
delete m_pDefaultTaskpads; m_pDefaultTaskpads = NULL;
delete m_pConsoleTaskpads; m_pConsoleTaskpads = NULL;
SAFE_RELEASE (m_pImageCache);
delete pSnapInsCache;
TraceError (_T("CScopeTree::Initialize"), sc);
return (sc.ToHr());
MMC_CATCH
}
STDMETHODIMP CScopeTree::QueryIterator(IScopeTreeIter** ppIter)
{
MMC_TRY
if (ppIter == NULL)
return E_POINTER;
CComObject<CScopeTreeIterator>* pObject;
CComObject<CScopeTreeIterator>::CreateInstance(&pObject);
return pObject->QueryInterface(IID_IScopeTreeIter,
reinterpret_cast<void**>(ppIter));
MMC_CATCH
}
STDMETHODIMP CScopeTree::QueryNodeCallback(INodeCallback** ppNodeCallback)
{
MMC_TRY
if (ppNodeCallback == NULL)
return E_POINTER;
CComObject<CNodeCallback>* pObject;
CComObject<CNodeCallback>::CreateInstance(&pObject);
HRESULT hr = pObject->QueryInterface(IID_INodeCallback,
reinterpret_cast<void**>(ppNodeCallback));
if (*ppNodeCallback != NULL)
(*ppNodeCallback)->Initialize(this);
return hr;
MMC_CATCH
}
STDMETHODIMP CScopeTree::CreateNode(HMTNODE hMTNode, LONG_PTR lViewData,
BOOL fRootNode, HNODE* phNode)
{
MMC_TRY
if (hMTNode == NULL)
return E_INVALIDARG;
if (phNode == NULL)
return E_POINTER;
CViewData* pViewData = reinterpret_cast<CViewData*>(lViewData);
ASSERT(IsBadReadPtr(pViewData, sizeof(*pViewData)) == 0);
CMTNode* pMTNode = CMTNode::FromHandle(hMTNode);
CNode* pNode = NULL;
if (pMTNode != NULL)
{
pNode = pMTNode->GetNode(pViewData, fRootNode);
*phNode = CNode::ToHandle(pNode);
return S_OK;
}
return E_FAIL;
MMC_CATCH
}
HRESULT CScopeTree::CloseView(int viewID)
{
MMC_TRY
if (m_pMTNodeRoot == NULL)
return S_OK;
HRESULT hr = m_pMTNodeRoot->CloseView(viewID);
ASSERT(hr == S_OK);
// Garbage collect view related column persistence data.
CColumnPersistInfo* pColPersInfo = NULL;
if ( (NULL != m_pConsoleData) && (NULL != m_pConsoleData->m_spPersistStreamColumnData) )
{
pColPersInfo = dynamic_cast<CColumnPersistInfo*>(
static_cast<IPersistStream*>(m_pConsoleData->m_spPersistStreamColumnData));
if (pColPersInfo)
pColPersInfo->DeleteColumnDataOfView(viewID);
}
// Ask the CViewSettingsPersistor to cleanup data for this view.
hr = CNode::ScDeleteViewSettings(viewID).ToHr();
return hr == S_OK ? S_OK : E_FAIL;
MMC_CATCH
}
HRESULT CScopeTree::DeleteView(int viewID)
{
MMC_TRY
if (m_pMTNodeRoot == NULL)
return S_OK;
HRESULT hr = m_pMTNodeRoot->DeleteView(viewID);
ASSERT(hr == S_OK);
return hr == S_OK ? S_OK : E_FAIL;
MMC_CATCH
}
STDMETHODIMP CScopeTree::DestroyNode(HNODE hNode)
{
// convert to real type
CNode* pNode = CNode::FromHandle(hNode);
delete pNode;
return S_OK;
}
HRESULT CScopeTree::HandsOffStorage()
{
// obsolete method.
// this method is left here since we use IPersistStorage to export
// persistence to CONUI side and we need to implement it.
// But this interface will never be called to save data
// [we will use CPersistor-based XML saving instead]
// so the method will always fail.
ASSERT(FALSE && "Should never come here");
return E_NOTIMPL;
}
static const wchar_t* AMCSignatureStreamName = L"signature";
static const long double dOldVersion10 = 0.00000015; // MMC version 1.0
static const long double dOldVersion11 = 1.1; // MMC version 1.1
static const BYTE byStreamVersionMagic = 0xFF;
HRESULT CScopeTree::InitNew(IStorage *pStg)
{
MMC_TRY
ASSERT(m_spPersistData == NULL);
ASSERT(pStg != NULL);
if (pStg == NULL)
return E_INVALIDARG;
// Create the perist data interface and attach it to the storage
CComObject<PersistData>* pPersistData;
HRESULT hr = CComObject<PersistData>::CreateInstance(&pPersistData);
m_spPersistData = pPersistData;
ASSERT(SUCCEEDED(hr) && m_spPersistData != NULL);
if (FAILED(hr))
return hr;
hr = m_spPersistData->Create(pStg);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
CMTNode* const pRoot = GetRoot();
ASSERT(pRoot != NULL);
if (pRoot == NULL)
return E_POINTER;
hr = pRoot->InitNew(m_spPersistData);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
return S_OK;
MMC_CATCH
}
HRESULT CScopeTree::IsDirty()
{
MMC_TRY
/*
* check for dirty taskpads
*/
CConsoleTaskpadList::iterator itDirty =
std::find_if (m_pConsoleTaskpads->begin(),
m_pConsoleTaskpads->end(),
const_mem_fun_ref (&CConsoleTaskpad::IsDirty));
if (itDirty != m_pConsoleTaskpads->end())
{
TraceDirtyFlag(TEXT("CScopeTree"), true);
return (S_OK);
}
/*
* check for dirty nodes
*/
HRESULT hr;
if (m_pMTNodeRoot != NULL)
{
hr = m_pMTNodeRoot->IsDirty();
ASSERT(SUCCEEDED(hr));
if (hr != S_FALSE)
{
TraceDirtyFlag(TEXT("CScopeTree"), true);
return hr;
}
}
/*
* check for dirty snap-in cache
*/
SC sc = theApp.GetSnapInsCache()->ScIsDirty();
ASSERT(!sc.IsError());
if(sc)
return sc.ToHr();
TraceDirtyFlag(TEXT("CScopeTree"), (sc==SC(S_OK)) ? true : false);
return sc.ToHr();
MMC_CATCH
}
HRESULT CScopeTree::GetFileVersion (IStorage* pstgRoot, int* pnVersion)
{
MMC_TRY
ASSERT(pstgRoot != NULL);
if (pstgRoot == NULL)
return MMC_E_INVALID_FILE;
// Open the stream containing the signature
IStreamPtr spStream;
HRESULT hr = OpenDebugStream(pstgRoot, AMCSignatureStreamName,
STGM_SHARE_EXCLUSIVE | STGM_READ, L"\\signature", &spStream);
ASSERT(SUCCEEDED(hr) && spStream != NULL);
if (FAILED(hr))
return MMC_E_INVALID_FILE;
/*
* read the signature (stream extraction operators will throw
* _com_error's, so we need an exception block here)
*/
try
{
/*
* MMC v1.2 and later write a marker as the first
* byte of the signature stream.
*/
BYTE byMagic;
*spStream >> byMagic;
/*
* if this file was written by v1.2 or later,
* read the console file version (int)
*/
if (byMagic == byStreamVersionMagic)
{
*spStream >> *pnVersion;
ASSERT (*pnVersion >= FileVer_0120);
}
/*
* Otherwise, the file was written by v1.0 or v1.1.
* Back up to re-read the marker byte, and read the old-style
* file version (long double), then map it to a new-style version
*/
else
{
LARGE_INTEGER pos = {0, 0};
spStream->Seek (pos, STREAM_SEEK_SET, NULL);
long double dVersion;
*spStream >> dVersion;
// v1.1?
if (dVersion == dOldVersion11)
*pnVersion = FileVer_0110;
// v1.0?
else if (dVersion == dOldVersion10)
{
/*
* If we got a v1.0 signature, we still may have a v1.1 file.
* There was a period of time where MMC v1.1 wrote a v1.0
* signature, but the file format had in fact changed. We
* can determine this by checking the \FrameData stream in
* the file. If the first DWORD in the \FrameData stream is
* sizeof(WINDOWPLACEMENT), we have a true v1.0 file, otherwise
* it's a funky v1.1 file.
*/
IStreamPtr spFrameDataStm;
hr = OpenDebugStream (pstgRoot, L"FrameData",
STGM_SHARE_EXCLUSIVE | STGM_READ,
&spFrameDataStm);
if (FAILED(hr))
return MMC_E_INVALID_FILE;
DWORD dw;
*spFrameDataStm >> dw;
if (dw == sizeof (WINDOWPLACEMENT))
*pnVersion = FileVer_0100;
else
*pnVersion = FileVer_0110;
}
// unexpected version
else
{
ASSERT (false && "Unexpected old-style signature");
hr = MMC_E_INVALID_FILE;
}
}
}
catch (_com_error& err)
{
hr = err.Error();
ASSERT (false && "Caught _com_error");
return (hr);
}
return (hr);
MMC_CATCH
}
STDMETHODIMP
CScopeTree::GetIDPath(
MTNODEID id,
MTNODEID** ppIDs,
long* pLength)
{
ASSERT(ppIDs);
ASSERT(pLength);
if (!ppIDs || !pLength)
return E_POINTER;
CMTNode* pMTNode = NULL;
HRESULT hr = Find(id, &pMTNode);
ASSERT(pMTNode);
if (!pMTNode)
return E_POINTER;
ASSERT(pMTNode->GetID() == id);
long len = 0;
for (CMTNode* pMTNodeTemp = pMTNode;
pMTNodeTemp;
pMTNodeTemp = pMTNodeTemp->Parent())
{
++len;
}
if (!len)
{
*pLength = 0;
*ppIDs = 0;
return E_FAIL;
}
MTNODEID* pIDs = (MTNODEID*) CoTaskMemAlloc (len * sizeof (MTNODEID));
if (pIDs == NULL)
{
*pLength = 0;
*ppIDs = 0;
return E_OUTOFMEMORY;
}
*pLength = len;
*ppIDs = pIDs;
for (pMTNodeTemp = pMTNode;
pMTNodeTemp;
pMTNodeTemp = pMTNodeTemp->Parent())
{
ASSERT(len != NULL);
pIDs[--len] = pMTNodeTemp->GetID();
}
return S_OK;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetNodeIDFromStream
*
* PURPOSE: Reads in a bookmark from the stream, and returns the NodeID of
* the node it represents.
*
* PARAMETERS:
* IStream * pStm :
* MTNODEID* pID :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CScopeTree::GetNodeIDFromStream(IStream *pStm, MTNODEID* pID)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetIDFromPath"));
// check parameters
sc = ScCheckPointers(pStm, pID);
if(sc)
return sc.ToHr();
CBookmarkEx bm;
*pStm >> bm;
bool bExactMatchFound = false; // out value from GetNodeIDFromBookmark.
return GetNodeIDFromBookmark(bm, pID, bExactMatchFound);
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetNodeIDFromBookmark
*
* PURPOSE: Returns the node ID of the MTNode represented by a bookmark.
*
* PARAMETERS:
* HBOOKMARK hbm : [in] bookmark
* MTNODEID* pID : [out] node-id
* bool& bExactMatchFound : [out] Is the exact match found or not.
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CScopeTree::GetNodeIDFromBookmark(HBOOKMARK hbm, MTNODEID* pID, bool& bExactMatchFound)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetNodeIDFromBookmark"));
CBookmark *pbm = CBookmark::GetBookmark(hbm);
bExactMatchFound = false;
sc = ScCheckPointers(pID, pbm);
if(sc)
return sc.ToHr();
CBookmarkEx bm = *pbm;
ASSERT (bm.IsValid());
CMTNode *pMTNode = NULL;
sc = bm.ScGetMTNode(false /*bExactMatchRequired*/, &pMTNode, bExactMatchFound);
if(sc)
return sc.ToHr();
if(!pMTNode)
{
sc = E_UNEXPECTED;
return sc.ToHr();
}
*pID = pMTNode->GetID();
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetNodeFromBookmark
*
* PURPOSE: Returns a Node object corresponding to the scope node whose
* Bookmark is passed in.
*
* PARAMETERS:
* HBOOKMARK hbm : [in] the given bookmark
* CConsoleView *pConsoleView : [in]
* PPNODE ppNode : [out] the node corresponding to the bookmark.
* bool bExactMatchFound : [out] did we find exactly matching node?
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP
CScopeTree::GetNodeFromBookmark(HBOOKMARK hbm, CConsoleView *pConsoleView, PPNODE ppNode, bool& bExactMatchFound)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetNodeFromBookmark"));
sc = ScCheckPointers(pConsoleView, ppNode);
if(sc)
return sc.ToHr();
// Get the node id
MTNODEID id = 0;
bExactMatchFound = false; // out value from GetNodeIDFromBookmark.
sc = GetNodeIDFromBookmark(hbm, &id, bExactMatchFound);
if(sc)
return sc.ToHr();
// find the node
CMTNode *pMTNode = NULL;
sc = Find(id, &pMTNode);
if(sc)
return sc.ToHr();
// make sure that the node is available
sc = pConsoleView->ScExpandNode(id, true /*bExpand*/, false /*bExpandVisually*/);
if(sc)
return sc.ToHr();
// Create a Node object
sc = ScGetNode(pMTNode, ppNode);
return sc.ToHr();
}
HRESULT CScopeTree::GetPathString(HMTNODE hmtnRoot, HMTNODE hmtnLeaf, LPOLESTR* ppszPath)
{
ASSERT(hmtnLeaf != NULL && ppszPath != NULL);
CMTNode* pmtnLeaf = CMTNode::FromHandle(hmtnLeaf);
CMTNode* pmtnRoot = (hmtnRoot == NULL) ? m_pMTNodeRoot : CMTNode::FromHandle(hmtnRoot);
CStr strPath;
_GetPathString(pmtnRoot, pmtnLeaf, strPath);
if (!strPath.IsEmpty())
{
*ppszPath = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc((strPath.GetLength()+1) * sizeof(OLECHAR)));
if (*ppszPath == NULL)
return E_OUTOFMEMORY;
USES_CONVERSION;
wcscpy(*ppszPath, T2COLE(strPath));
return S_OK;
}
return E_FAIL;
}
void CScopeTree::_GetPathString(CMTNode* pmtnRoot, CMTNode* pmtnCur, CStr& strPath)
{
ASSERT(pmtnRoot != NULL && pmtnCur != NULL);
// if haven't reached the root node yet, recursively get path from
// root to current node's parent
if (pmtnCur != pmtnRoot)
{
_GetPathString(pmtnRoot, pmtnCur->Parent(), strPath);
strPath += _T('\\');
}
// now append the name for the current node
strPath += pmtnCur->GetDisplayName().data();
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScAddSnapin
*
* PURPOSE: Adds the specified snapin to the console file beneath console root.
*
* TODO: 1) Allow the caller to specify the parent snapin.
* 2) Right now specifying snapins by name does not work. Add this.
*
* PARAMETERS:
* LPCTSTR szSnapinNameOrCLSID : The name or GUID of the snapin.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScAddSnapin (
LPCWSTR szSnapinNameOrCLSID, /* I:name or CLSID of the snapin */
SnapIn* pParentSnapinNode, /* I:Parent snapin under which this snapin is added (optional)*/
Properties* pProperties, /* I:props to init with (optional) */
SnapIn*& rpSnapIn) /* O:the snap-in that was created */
{
DECLARE_SC(sc, TEXT("CScopeTree::ScAddSnapin"));
CSnapinManager snapinMgr(GetRoot());
Trace(tagScopeTreeAddSnapin, TEXT("CScopeTree::ScAddSnapin"));
// adding the snapin below this node.
sc = snapinMgr.ScAddSnapin(szSnapinNameOrCLSID, pParentSnapinNode, pProperties);
if(sc)
return sc;
// get the "list" of one node to add
NewNodeList* pNewNodes = snapinMgr.GetNewNodes();
if (pNewNodes == NULL)
return (sc = E_UNEXPECTED);
// the list should have an item in it
CNewTreeNode* pNewNode = pNewNodes->GetHead();
if (pNewNode == NULL)
return (sc = E_UNEXPECTED);
// Update the scope tree with changes made by snapin manager.
sc = ScAddOrRemoveSnapIns(snapinMgr.GetDeletedNodesList(),
pNewNodes);
if(sc)
return sc;
// if ScAddOrRemoveSnapIns succeeded, it better have created a CMTSnapInNode for us
CMTSnapInNode* pNewSnapInNode = pNewNode->m_pmtNewSnapInNode;
if (pNewSnapInNode == NULL)
return (sc = E_UNEXPECTED);
// get the SnapIn interface for the client
sc = pNewSnapInNode->ScGetSnapIn (&rpSnapIn);
if (sc)
return (sc);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::QuerySnapIns
*
* PURPOSE: Creates, AddRefs, and returns a SnapIns object.
*
* PARAMETERS:
* SnapIns ** ppSnapIns :
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT
CScopeTree::QuerySnapIns(SnapIns **ppSnapIns)
{
DECLARE_SC(sc, TEXT("CScopeTree::QuerySnapIns"));
// parameter check
sc = ScCheckPointers(ppSnapIns);
if (sc)
return sc.ToHr();
// init out parameter
*ppSnapIns = NULL;
// create a CSnapIns object if needed.
sc = CTiedComObjectCreator<CSnapIns>::ScCreateAndConnect(*this, m_spSnapIns);
if(sc)
return sc.ToHr();
if(m_spSnapIns == NULL)
{
sc = E_UNEXPECTED;
return sc.ToHr();
}
// addref the pointer for the client.
m_spSnapIns->AddRef();
*ppSnapIns = m_spSnapIns;
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::QueryScopeNamespace
*
* PURPOSE: Creates, AddRefs, and returns a ScopeNamespace object.
*
* PARAMETERS:
* ScopeNamespace ** ppScopeNamespace :
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT
CScopeTree::QueryScopeNamespace(ScopeNamespace **ppScopeNamespace)
{
DECLARE_SC(sc, TEXT("CScopeTree::QueryScopeNamespace"));
// parameter check
sc = ScCheckPointers(ppScopeNamespace);
if (sc)
return sc.ToHr();
// init out parameter
*ppScopeNamespace = NULL;
// create a CScopeNamespace object if needed.
sc = CTiedComObjectCreator<CScopeNamespace>::ScCreateAndConnect(*this, m_spScopeNamespace);
if(sc)
return sc.ToHr();
if(m_spScopeNamespace == NULL)
{
sc = E_UNEXPECTED;
return sc.ToHr();
}
// addref the pointer for the client.
m_spScopeNamespace->AddRef();
*ppScopeNamespace = m_spScopeNamespace;
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
* CScopeTree::CreateProperties
*
* Creates a new, empty Properties object. This function does the work
* behind _Document::CreateProperties.
*--------------------------------------------------------------------------*/
HRESULT CScopeTree::CreateProperties (Properties** ppProperties)
{
DECLARE_SC (sc, _T("CScopeTree::CreateProperties"));
/*
* validate parameters
*/
sc = ScCheckPointers (ppProperties);
if (sc)
return (sc.ToHr());
/*
* create a new properties collection
*/
CComObject<CSnapinProperties> *pProperties = NULL;
sc = CComObject<CSnapinProperties>::CreateInstance (&pProperties);
if (sc)
return (sc.ToHr());
if (pProperties == NULL)
return ((sc = E_UNEXPECTED).ToHr());
/*
* put a ref on for the client
*/
(*ppProperties) = pProperties;
(*ppProperties)->AddRef();
return (sc.ToHr());
}
//+-------------------------------------------------------------------
//
// Member: CScopeTree::QueryRootNode
//
// Synopsis: Returns COM object to the Root Node.
//
// Arguments: [ppRootNode] - Ptr in which root node will be returned.
//
// Returns: HRESULT
//
//--------------------------------------------------------------------
HRESULT CScopeTree::QueryRootNode (PPNODE ppRootNode)
{
DECLARE_SC(sc, _T("CScopeTree::QueryRootNode"));
sc = ScGetRootNode(ppRootNode);
return (sc.ToHr());
}
HRESULT CScopeTree::Load(IStorage *pStg)
{
MMC_TRY
ASSERT(m_spPersistData == NULL);
if (m_spPersistData != NULL)
return E_UNEXPECTED;
ASSERT(pStg != NULL);
if (pStg == NULL)
return E_INVALIDARG;
// Create the perist data interface and attach it to the storage
CComObject<PersistData>* pPersistData;
HRESULT hr = CComObject<PersistData>::CreateInstance(&pPersistData);
m_spPersistData = pPersistData;
ASSERT(SUCCEEDED(hr) && m_spPersistData != NULL);
if (FAILED(hr))
return hr;
hr = m_spPersistData->Open(pStg);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
// Open the stream for the cache
IStreamPtr spStream;
hr = OpenDebugStream(pStg, AMCSnapInCacheStreamName,
STGM_SHARE_EXCLUSIVE | STGM_READWRITE, L"SnapInCache", &spStream);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
SC sc = theApp.GetSnapInsCache()->ScLoad(spStream);
ASSERT(!sc.IsError());
if (sc)
return sc.ToHr();
ASSERT(m_pMTNodeRoot == NULL);
sc = CMTNode::ScLoad (m_spPersistData, &m_pMTNodeRoot);
ASSERT(!sc.IsError() && m_pMTNodeRoot != NULL);
if (sc)
return sc.ToHr();
hr = LoadTaskpadList(pStg);
return hr;
MMC_CATCH
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::Persist
*
* PURPOSE: Persists the CScopeTree to the specified persistor.
*
* PARAMETERS:
* HPERSISTOR pPersistor:
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT CScopeTree::Persist(HPERSISTOR hPersistor)
{
DECLARE_SC(sc, TEXT("CScopeTree::Persist"));
try
{
sc = ScCheckPointers((void *)hPersistor,theApp.GetSnapInsCache());
if (sc)
sc.Throw();
CPersistor &persistor = *reinterpret_cast<CPersistor *>(hPersistor);
CPersistor persistorScopeTree(persistor, XML_TAG_SCOPE_TREE);
// persist the snapin cache.
persistorScopeTree.Persist(*theApp.GetSnapInsCache());
// persist the MTNode hierarchy.
CPersistor persistorMTNodes(persistorScopeTree, XML_TAG_SCOPE_TREE_NODES);
if (persistor.IsStoring())
{
if(!m_pMTNodeRoot)
sc.Throw(E_POINTER);
persistorMTNodes.Persist(*m_pMTNodeRoot);
}
else
{
// here we imitate how the collection fixes on the element
// despite we only have one, CMTNode::PersistNewNode thinks else
CPersistor persistor1Node(persistorMTNodes, XML_TAG_MT_NODE);
CPersistor persistor1NodeLocked(persistor1Node,persistor1Node.GetCurrentElement(),true);
CMTNode::PersistNewNode(persistor1NodeLocked, &m_pMTNodeRoot);
sc = ScCheckPointers(m_pMTNodeRoot,E_FAIL);
if (sc)
sc.Throw();
}
// persist all taskpads
if(m_pConsoleTaskpads)
{
persistor.Persist(*m_pConsoleTaskpads);
}
}
catch (SC e_sc)
{
sc = e_sc;
}
catch (_com_error e_com)
{
sc = e_com.Error();
}
catch (HRESULT e_hr)
{
sc = e_hr;
}
return sc.ToHr();
}
HRESULT CScopeTree::Save(IStorage *pStg, BOOL fSameAsLoad)
{
// obsolete method.
// this method is left here since we use IPersistStorage to export
// persistence to CONUI side and we need to implement it.
// But this interface will never be called to save data
// [we will use CPersistor-based XML saving instead]
// so the method will always fail.
ASSERT(FALSE && "Should never come here");
return E_NOTIMPL;
}
HRESULT CScopeTree::LoadTaskpadList(IStorage *pStg)
{
HRESULT hr = S_OK;
m_pConsoleTaskpads->clear();
m_pDefaultTaskpads->clear();
// Open the stream for the cache
IStreamPtr spStream;
hr = OpenDebugStream(pStg, AMCTaskpadListStreamName,
STGM_SHARE_EXCLUSIVE | STGM_READWRITE, L"TaskpadList", &spStream);
if (FAILED(hr))
return S_OK; // might be pre-MMC1.2, so if we don't find the stream just exit normally.
hr = m_pConsoleTaskpads->Read(*(spStream.GetInterfacePtr()));
if(FAILED(hr))
return hr;
// Read the list of default taskpads.
hr = m_pDefaultTaskpads->Read(*(spStream.GetInterfacePtr()));
if(FAILED(hr))
return hr;
return hr;
}
HRESULT CScopeTree::SaveCompleted(IStorage *pStg)
{
// obsolete method.
// this method is left here since we use IPersistStorage to export
// persistence to CONUI side and we need to implement it.
// But this interface will never be called to save data
// [we will use CPersistor-based XML saving instead]
// so the method will always fail.
ASSERT(FALSE && "Should never come here");
return E_NOTIMPL;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::Find
*
* PURPOSE:
*
* PARAMETERS:
* MTNODEID mID :
* CMTNode** ppMTNode :
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT CScopeTree::Find(MTNODEID mID, CMTNode** ppMTNode)
{
if (ppMTNode == NULL)
return E_POINTER;
*ppMTNode = NULL;
CMTNode* pMTRootNode = GetRoot();
if (pMTRootNode == NULL)
return (E_FAIL);
*ppMTNode = pMTRootNode->Find(mID);
return ((*ppMTNode == NULL) ? E_FAIL : S_OK);
}
HRESULT CScopeTree::Find(MTNODEID mID, HMTNODE* phMTNode)
{
if (phMTNode == NULL)
return E_POINTER;
*phMTNode = NULL;
CMTNode* pMTNode;
HRESULT hr = Find (mID, &pMTNode);
if (FAILED (hr))
return (hr);
*phMTNode = CMTNode::ToHandle (pMTNode);
return ((*phMTNode == NULL) ? E_FAIL : S_OK);
}
HRESULT CScopeTree::GetClassID(CLSID *pClassID)
{
MMC_TRY
if (pClassID == NULL)
return E_INVALIDARG;
*pClassID = CLSID_ScopeTree;
return S_OK;
MMC_CATCH
}
#define SDI_RELATIVEID_MASK (SDI_PARENT | SDI_PREVIOUS | SDI_NEXT)
SC
CScopeTree::ScInsert(LPSCOPEDATAITEM pSDI, COMPONENTID nID,
CMTNode** ppMTNodeNew)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScInsert"));
// check parameters
if (m_pMTNodeRoot == NULL)
{
sc = E_INVALIDARG;
return sc;
}
try
{
*ppMTNodeNew = NULL;
HMTNODE hMTNodePrev = (HMTNODE) TVI_LAST;
CMTNode* pMTNodeRelative = CMTNode::FromScopeItem(pSDI->relativeID);
CMTNode* pMTNodeParent = NULL;
if (pSDI->mask & SDI_RELATIVEID_MASK)
{
if (pMTNodeRelative->GetOwnerID() != nID)
{
sc = E_INVALIDARG;
return sc;
}
pMTNodeParent = pMTNodeRelative->Parent();
}
else
{
pMTNodeParent = pMTNodeRelative;
}
if (pMTNodeParent == NULL)
{
sc = E_INVALIDARG;
return sc;
}
ASSERT(pMTNodeParent->WasExpandedAtLeastOnce() == TRUE);
if (pMTNodeParent->WasExpandedAtLeastOnce() == FALSE)
{
sc = E_POINTER;
return sc;
}
if (IsBadWritePtr(pMTNodeParent, sizeof(CMTNode*)) != 0)
{
sc = E_POINTER;
return sc;
}
CMTSnapInNode* pMTSINode = pMTNodeParent->GetStaticParent();
CComponentData* pCCD = pMTSINode->GetComponentData(nID);
ASSERT(pCCD != NULL);
CMTNode* pMTNode = new CMTNode;
if (pMTNode == NULL)
return (sc = E_OUTOFMEMORY);
pMTNode->SetPrimaryComponentData(pCCD);
pMTNode->SetOwnerID(nID);
pMTNode->SetUserParam(pSDI->lParam);
if (pSDI->mask & SDI_STATE)
pMTNode->SetState(pSDI->nState);
if (pSDI->mask & SDI_IMAGE)
pMTNode->SetImage(pSDI->nImage);
if (pSDI->mask & SDI_OPENIMAGE)
pMTNode->SetOpenImage(pSDI->nOpenImage);
if ((pSDI->mask & SDI_CHILDREN) && (pSDI->cChildren == 0))
pMTNode->SetNoPrimaryChildren();
pSDI->ID = reinterpret_cast<HSCOPEITEM>(pMTNode);
pMTNode->AttachParent(pMTNodeParent);
if (pMTNodeParent->Child() == NULL)
{
pMTNodeParent->AttachChild(pMTNode);
}
else if (pSDI->mask & SDI_PREVIOUS)
{
pMTNode->AttachNext(pMTNodeRelative->Next());
pMTNodeRelative->AttachNext(pMTNode);
hMTNodePrev = CMTNode::ToHandle(pMTNodeRelative);
}
else if (pSDI->mask & SDI_NEXT)
{
pMTNode->AttachNext(pMTNodeRelative);
CMTNode* pMTNodePrev = _FindPrev(pMTNodeRelative);
if (pMTNodePrev != NULL)
{
pMTNodePrev->AttachNext(pMTNode);
hMTNodePrev = CMTNode::ToHandle(pMTNodePrev);
}
else
{
pMTNodeParent->AttachChild(pMTNode);
hMTNodePrev = (HMTNODE) TVI_FIRST;
}
}
else if (pSDI->mask & SDI_FIRST)
{
pMTNode->AttachNext(pMTNodeParent->Child());
pMTNodeParent->AttachChild(pMTNode);
hMTNodePrev = (HMTNODE) TVI_FIRST;
}
else
{
CMTNode* pMTNodeLastChild = _FindLastChild(pMTNodeParent);
ASSERT(pMTNodeLastChild != NULL);
pMTNodeLastChild->AttachNext(pMTNode);
// hMTNodePrev = (HMTNODE) TVI_LAST;
}
*ppMTNodeNew = pMTNode;
// Now inform the views to add as needed.
SViewUpdateInfo vui;
vui.newNode = CMTNode::ToHandle(pMTNode);
vui.insertAfter = hMTNodePrev;
pMTNode->Parent()->CreatePathList(vui.path);
UpdateAllViews(VIEW_UPDATE_ADD, reinterpret_cast<LPARAM>(&vui));
}
catch( std::bad_alloc )
{
sc = E_OUTOFMEMORY;
return sc;
}
catch (...)
{
sc = E_FAIL;
return sc;
}
return sc;
}
CMTNode* CScopeTree::_FindLastChild(CMTNode* pMTNodeParent)
{
ASSERT(pMTNodeParent != NULL);
CMTNode* pMTNode = pMTNodeParent->Child();
if (pMTNode != NULL)
{
while (pMTNode->Next())
pMTNode = pMTNode->Next();
}
return pMTNode;
}
CMTNode* CScopeTree::_FindPrev(CMTNode* pMTNodeIn)
{
ASSERT(pMTNodeIn != NULL);
CMTNode* pMTNode = pMTNodeIn->Parent()->Child();
ASSERT(pMTNode != NULL);
if (pMTNode == pMTNodeIn)
return NULL;
while (pMTNode->Next() != pMTNodeIn)
{
pMTNode = pMTNode->Next();
ASSERT(pMTNode != NULL);
}
return pMTNode;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScInsert
*
* PURPOSE: Inserts a single item into the scope tree.
*
* PARAMETERS:
* CMTNode* pmtnParent : Should be non-NULL. The node to insert under.
* CMTNode* pmtnToInsert : The node to be inserted.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScInsert(CMTNode* pmtnParent, CMTNode* pmtnToInsert)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScInsert"));
// check parameters
sc = ScCheckPointers(pmtnParent, pmtnToInsert);
if(sc)
return sc;
pmtnToInsert->AttachParent(pmtnParent);
if (pmtnParent->Child() == NULL)
{
pmtnParent->AttachChild(pmtnToInsert);
}
else
{
// attach the node as a sibling of the last child node.
for (CMTNode * pmtn = pmtnParent->Child();
pmtn->Next() != NULL;
pmtn = pmtn->Next())
{}
pmtn->AttachNext(pmtnToInsert);
}
pmtnToInsert->NotifyAddedToTree ();
SViewUpdateInfo vui;
pmtnToInsert->Parent()->CreatePathList(vui.path);
vui.newNode = CMTNode::ToHandle(pmtnToInsert);
UpdateAllViews(VIEW_UPDATE_ADD, reinterpret_cast<LPARAM>(&vui));
vui.path.RemoveAll();
return sc;
}
typedef CArray<COMPONENTID, COMPONENTID> CComponentIDArray;
//---------------------------------------------------------------------------------------
// NotifyExtensionsOfNodeDeletion
//
// This method enumerated the children of a node, building a list of all the snap-in
// components that have added children. It then sends a REMOVE_CHILDREN notification to
// each of the components.
//
// The component that owns the node is treated in a special way. It is only notified if
// the node is staic or the bNotifyRoot param is TRUE. This is because we don't want
// to send notifications for nodes that belong to a subtree rooted at a node owned by
// the same component (see InformSnapinsOfDeletion).
//---------------------------------------------------------------------------------------
void NotifyExtensionsOfNodeDeletion(CMTNode* pMTNode, CComponentIDArray& rgID,
BOOL bNotifyRoot = FALSE)
{
if (pMTNode == NULL)
return;
CMTSnapInNode* pMTSINode = pMTNode->GetStaticParent();
ASSERT(pMTSINode != NULL);
if (pMTSINode == NULL)
return;
COMPONENTID idOwner = pMTNode->GetPrimaryComponentID();
int nTemp = pMTSINode->GetNumberOfComponentDatas() + 1;
rgID.SetSize(nTemp);
for (int i=0; i < nTemp; ++i)
rgID[i] = -1;
// Build list of all component ID's that have added children to this node
// except for component that owns the node.
BOOL bOwnerChildren = FALSE;
CMTNode* pMTNodeTemp = pMTNode->Child();
for (int iMax = -1; pMTNodeTemp != NULL; pMTNodeTemp = pMTNodeTemp->Next())
{
COMPONENTID id = pMTNodeTemp->GetPrimaryComponentID();
// if owner ID just note it, else add ID to list
if (id == idOwner)
{
bOwnerChildren = TRUE;
}
else
{
// search list for ID
for (int j=0; j <= iMax; ++j)
{
if (rgID[j] == id)
break;
}
// if not found, add to list
if (j > iMax)
rgID[++iMax] = id;
}
}
// Include owner conponent only if it needs to be notified
if (bOwnerChildren && (bNotifyRoot == TRUE || pMTNode->IsStaticNode()))
rgID[++iMax] = idOwner;
if (!pMTNode->IsInitialized())
return;
IDataObjectPtr spDataObject;
HRESULT hr = pMTNode->QueryDataObject(CCT_SCOPE, &spDataObject);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return;
LPARAM lScopeItem = CMTNode::ToScopeItem(pMTNode);
pMTNode->SetRemovingChildren(true);
for (i = 0; i <= iMax; ++i)
{
ASSERT(rgID[i] != -1);
CComponentData* pCD = pMTSINode->GetComponentData(rgID[i]);
ASSERT(pCD != NULL);
Dbg(DEB_TRACE, _T("Remove Children - node = %s, ID = %d\n"), pMTNode->GetDisplayName(), rgID[i]);
hr = pCD->Notify(spDataObject, MMCN_REMOVE_CHILDREN, lScopeItem, 0);
CHECK_HRESULT(hr);
}
pMTNode->SetRemovingChildren(false);
}
//-----------------------------------------------------------------------------------------------
// InformSnapinsOfDeletion
//
// This function traverse the node subtree rooted at pMTNode and sends a REMOVE_CHILDREN to all
// snap-in components that have added children to the tree. A component is sent one notification
// for each node it has extended that belongs to another component. No notification is sent where
// a component has extended one of its own nodes. There are two exceptions to this rule. Owners
// of static nodes are always notified. Also the owner of the top node is notified if bNotifyRoot
// is TRUE.
//
// Another way to look at this is that MMC searches the tree for subtrees of nodes provided by
// a single component. It sends a notification to the component to delete the top node of the
// subtree. The component is responsible for identifying and deleting the rest of its nodes in
// the subtree.
//
// This method just handles the recursion and iteration required to traverse the whole tree. It
// calls NotifyExtensionsOfNodeDeletion to enumerate the children of a node and send notifications
// to the right components.
//
//------------------------------------------------------------------------------------------------
void InformSnapinsOfDeletion(CMTNode* pMTNode, BOOL fNext,
CComponentIDArray& rgID, BOOL bNotifyRoot = FALSE)
{
if (pMTNode == NULL)
return;
if (pMTNode->Child() != NULL)
{
// Recursively clear nodes's subtree first
InformSnapinsOfDeletion(pMTNode->Child(), TRUE, rgID, FALSE);
// Notify extensions of node itself
NotifyExtensionsOfNodeDeletion(pMTNode, rgID, bNotifyRoot);
}
// If requested, handle all siblings of this node
// (iteratively rather than recursively to avoid deep stack use)
if (fNext == TRUE)
{
CMTNode* pMTNodeNext = pMTNode->Next();
while (pMTNodeNext != NULL)
{
InformSnapinsOfDeletion(pMTNodeNext, FALSE, rgID, FALSE);
pMTNodeNext = pMTNodeNext->Next();
}
}
}
/*+-------------------------------------------------------------------------*
* CScopeTree::Delete
*
* PURPOSE: Deletes a tree rooted at a node. Also sends a notification to
* the selected item in each view asking them whether they need to
* be reselected once the item is deleted.
*
* Called by CNodeInitObject::DeleteItem
*
* PARAMETERS:
* CMTNode* pmtn: The root of the tree to be deleted
* BOOL fDeleteThis: Whether the root itself requires deletion as well
* COMPONENTID nID:
*
* RETURNS:
* void
/*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScDelete(CMTNode* pmtn, BOOL fDeleteThis, COMPONENTID nID)
{
DECLARE_SC(sc, TEXT("CScopeTree::Delete"));
// check parameters
if (pmtn == NULL)
{
sc = E_INVALIDARG;
return sc;
}
// Is this call a result of sending MMCN_REMOVE_CHILDREN to a parent node?
// If so return immediately since MMC does delete all the child nodes.
if (pmtn->AreChildrenBeingRemoved() == true)
return sc;
// if deleting node and children, just do one call to delete the
// whole subtree.
if (fDeleteThis)
{
// can't delete static root node OR nodes put up by other components!
if ( ( pmtn->GetOwnerID() == TVOWNED_MAGICWORD) || (pmtn->GetOwnerID() != nID) )
{
sc = E_INVALIDARG;
return sc;
}
#ifdef DBG
CMTNode* pmtnParent = pmtn->Parent();
CMTNode* pmtnPrev = NULL;
CMTNode* pmtnNext = pmtn->Next();
if (pmtnParent->Child() != pmtn)
{
pmtnPrev = pmtnParent->Child();
while (pmtnPrev->Next() != pmtn)
pmtnPrev = pmtnPrev->Next();
ASSERT(pmtnPrev != NULL);
}
#endif
DeleteNode(pmtn);
#ifdef DBG
if (pmtnParent != NULL)
{
ASSERT(pmtnParent != NULL);
if (pmtnPrev == NULL)
{
ASSERT(pmtnParent->Child() == pmtnNext);
}
else
{
ASSERT(pmtnPrev->Next() == pmtnNext);
}
}
#endif
}
// else we have to enum the children and delete only the ones
// created by the calling snap-in
else
{
CMTNode* pMTNode = pmtn->Child();
// Enum children and delete those that are owned by the
// requesting component (i.e., with matching ID)
while(pMTNode != NULL)
{
CMTNode *pMTNodeNext = pMTNode->Next();
if (!pMTNode->IsStaticNode() &&
(pMTNode->GetPrimaryComponentID() == nID))
{
DeleteNode(pMTNode);
}
pMTNode = pMTNodeNext;
}
}
return sc;
}
void CScopeTree::DeleteNode(CMTNode* pmtn)
{
if (pmtn == NULL)
return;
// always update the views
SViewUpdateInfo vui;
vui.flag = VUI_DELETE_THIS;
pmtn->CreatePathList (vui.path);
// We are changing selection, so snapin may call delete
// on this node during this process (MMCN_SELECT, MMCN_SHOW...),
// Do an AddRef and Release to protect ourself from such deletes.
pmtn->AddRef();
UpdateAllViews (VIEW_UPDATE_SELFORDELETE, reinterpret_cast<LPARAM>(&vui));
if (pmtn->Release() == 0)
return; // The object was already deleted during selection change.
UpdateAllViews (VIEW_UPDATE_DELETE, reinterpret_cast<LPARAM>(&vui));
CComponentIDArray rgID;
rgID.SetSize(20, 10);
InformSnapinsOfDeletion(pmtn, FALSE, rgID, (pmtn->IsStaticNode() == FALSE));
CMTNode* pmtnParent = pmtn->Parent();
_DeleteNode(pmtn);
pmtnParent->OnChildrenChanged();
UpdateAllViews (VIEW_UPDATE_DELETE_EMPTY_VIEW, 0);
}
void CScopeTree::_DeleteNode(CMTNode* pmtn)
{
//
// Delete from the scope tree.
//
if (m_pMTNodeRoot == pmtn)
{
m_pMTNodeRoot = NULL;
}
CMTNode* pmtnParent = pmtn->Parent();
CMTNode* pmtnSibling = pmtnParent->Child();
ASSERT(pmtnSibling != NULL);
if (pmtnSibling == pmtn)
{
pmtnParent->AttachChild(pmtn->Next());
}
else
{
for (; pmtnSibling->Next() != pmtn; pmtnSibling = pmtnSibling->Next());
pmtnSibling->AttachNext(pmtn->Next());
}
pmtn->AttachNext(NULL);
pmtn->AttachParent(NULL);
pmtn->Release();
pmtnParent->SetDirty();
}
void CScopeTree::UpdateAllViews(LONG lHint, LPARAM lParam)
{
CConsoleFrame* pFrame = GetConsoleFrame();
ASSERT (pFrame != NULL);
if (pFrame == NULL)
return;
SC sc = pFrame->ScUpdateAllScopes (lHint, lParam);
if (sc)
goto Error;
Cleanup:
return;
Error:
TraceError (_T("CScopeTree::UpdateAllViews"), sc);
goto Cleanup;
}
void CScopeTree::DeleteDynamicNodes(CMTNode* pMTNode)
{
ASSERT(pMTNode != NULL);
ASSERT(pMTNode->IsStaticNode() == TRUE);
if (pMTNode == NULL)
return;
CMTSnapInNode* pMTSINode = dynamic_cast<CMTSnapInNode*>(pMTNode);
ASSERT(pMTSINode != NULL);
if (pMTSINode == NULL)
return;
for (CMTNode* pMTNodeTemp = pMTNode->Child(); pMTNodeTemp != NULL;
pMTNodeTemp = pMTNodeTemp->Next())
{
if (pMTNodeTemp->IsDynamicNode())
{
CComponentIDArray rgID;
rgID.SetSize(20, 10);
InformSnapinsOfDeletion(pMTNodeTemp, FALSE, rgID, FALSE);
}
}
CComponentIDArray rgID;
NotifyExtensionsOfNodeDeletion(pMTSINode, rgID, FALSE);
CMTNode* pMTNodeNext = pMTNode->Child();
while (pMTNodeNext != NULL)
{
pMTNodeTemp = pMTNodeNext;
pMTNodeNext = pMTNodeNext->Next();
if (pMTNodeTemp->IsStaticNode() == FALSE)
_DeleteNode(pMTNodeTemp);
}
}
inline BOOL CScopeTree::ExtensionsHaveChanged(CMTSnapInNode* pMTSINode)
{
CSnapIn* pSnapIn = pMTSINode->GetPrimarySnapIn();
ASSERT(pSnapIn != NULL);
return pSnapIn->HasNameSpaceChanged();
}
void CScopeTree::HandleExtensionChanges(CMTNode* pMTNode)
{
if (pMTNode == NULL)
return;
HandleExtensionChanges(pMTNode->Next());
if (pMTNode->IsStaticNode() == TRUE)
{
HandleExtensionChanges(pMTNode->Child());
if (ExtensionsHaveChanged(dynamic_cast<CMTSnapInNode*>(pMTNode)) == TRUE)
{
SViewUpdateInfo vui;
vui.flag = VUI_DELETE_SETAS_EXPANDABLE;
pMTNode->CreatePathList(vui.path);
UpdateAllViews(VIEW_UPDATE_SELFORDELETE, reinterpret_cast<LPARAM>(&vui));
UpdateAllViews(VIEW_UPDATE_DELETE, reinterpret_cast<LPARAM>(&vui));
vui.path.RemoveAll();
DeleteDynamicNodes(pMTNode);
m_MTNodesToBeReset.AddHead(pMTNode);
UpdateAllViews(VIEW_UPDATE_DELETE_EMPTY_VIEW, 0);
}
}
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::RunSnapIn
*
* PURPOSE: Runs the Snap-In Manager to prompt the user to add and remove snap-ins.
*
* PARAMETERS:
* HWND hwndParent :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
STDMETHODIMP CScopeTree::RunSnapIn(HWND hwndParent)
{
MMC_TRY
DECLARE_SC(sc, TEXT("CScopeTree::RunSnapIn"));
CSnapinManager dlg(GetRoot());
if (dlg.DoModal() == IDOK)
{
sc = ScAddOrRemoveSnapIns(dlg.GetDeletedNodesList(), dlg.GetNewNodes());
if(sc)
return sc.ToHr();
}
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
* class CEnableProcessingSnapinCacheChanges
*
*
* PURPOSE: A class that sets/re-sets ProcessingSnapinChanges so that
* the ProcessingSnapinChanges is re-set automatically when
* this object is destroyed.
*
*+-------------------------------------------------------------------------*/
class CEnableProcessingSnapinCacheChanges
{
public:
CEnableProcessingSnapinCacheChanges()
{
theApp.SetProcessingSnapinChanges(TRUE);
}
~CEnableProcessingSnapinCacheChanges()
{
theApp.SetProcessingSnapinChanges(FALSE);
}
};
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScAddOrRemoveSnapIns
*
* PURPOSE: Called after a snapin is added/removed (extension is enabled/disabled)
* to update scopetree with those changes.
*
* PARAMETERS:
* MTNodesList * pmtnDeletedList : The list of nodes to remove. Can be NULL.
* NewNodeList * pnnList : The list of nodes to add. Can be NULL.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScAddOrRemoveSnapIns(MTNodesList * pmtnDeletedList, NewNodeList * pnnList)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScAddOrRemoveSnapIns"));
sc = ScCheckPointers(m_pConsoleData, m_pConsoleData->m_pConsoleDocument, E_UNEXPECTED);
if (sc)
return sc;
CConsoleDocument *pConsoleDoc = m_pConsoleData->m_pConsoleDocument;
ASSERT(NULL != pConsoleDoc);
// 1. Prevent access to snapin data while processing changes.
CEnableProcessingSnapinCacheChanges processSnapinChanges;
// 2. Delete static nodes.
{
CMTNode * pmtnTemp;
POSITION pos;
if (pmtnDeletedList)
{
pos = pmtnDeletedList->GetHeadPosition();
while (pos)
{
pmtnTemp = pmtnDeletedList->GetNext(pos);
CMTSnapInNode * pMTSINode = dynamic_cast<CMTSnapInNode*>(pmtnTemp);
// forward to the document to generate the script event
if (pMTSINode)
{
SnapInPtr spSnapIn;
// construct snapin com object
sc = pMTSINode->ScGetSnapIn(&spSnapIn);
if (sc)
sc.TraceAndClear(); // it's only events. Should not affect main functionality
else
{
// emit the event
sc = pConsoleDoc->ScOnSnapinRemoved(spSnapIn);
if (sc)
sc.TraceAndClear(); // it's only events. Should not affect main functionality
}
}
DeleteNode(pmtnTemp);
}
}
}
// 3. Handle extension changes
HandleExtensionChanges(m_pMTNodeRoot->Child());
CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache();
sc = ScCheckPointers(pSnapInCache, E_UNEXPECTED);
if (sc)
goto Error;
// 4. Purge the snapin cache
// (duplicates what is done in ~CSnapinManager, since doing it here is too early
// - snapin manager still has a reference to the snapins)
// but some code relies in this to remove the snapin from cache
// look at windows bug #276340 (ntbug9, 1/10/2001).
pSnapInCache->Purge();
// 5. Re-Init
{
POSITION pos = m_MTNodesToBeReset.GetHeadPosition();
while (pos)
{
CMTNode* pMTNode = m_MTNodesToBeReset.GetNext(pos);
ASSERT(pMTNode != NULL);
if (pMTNode != NULL)
pMTNode->Reset();
}
m_MTNodesToBeReset.RemoveAll();
// Re-set processing changes explicitly eventhough the
// dtor for CEnableProcessingSnapinCacheChanges will do this.
theApp.SetProcessingSnapinChanges(FALSE);
}
// 6. Cleanup controlbar cache and reselect currently selected node.
UpdateAllViews(VIEW_RESELECT, 0);
// 7. Add new static nodes
if (pnnList)
{
PNEWTREENODE pNew;
CMTNode * pmtnTemp;
POSITION pos = pnnList->GetHeadPosition();
while (pos)
{
pNew = pnnList->GetNext(pos);
sc = ScCheckPointers(pNew, E_UNEXPECTED);
if (sc)
goto Error;
pmtnTemp = NULL;
sc = ScCreateMTNodeTree(pNew, pNew->m_pmtNode, &pmtnTemp);
if (sc)
goto Error;
sc = ScCheckPointers(pmtnTemp, E_UNEXPECTED);
if (sc)
goto Error;
sc = ScInsert(pNew->m_pmtNode, pmtnTemp);
if(sc)
goto Error;
CMTSnapInNode * pMTSINode = dynamic_cast<CMTSnapInNode*>(pmtnTemp);
// forward to the document to generate the script event
if (pMTSINode)
{
SnapInPtr spSnapIn;
// construct snapin com object
sc = pMTSINode->ScGetSnapIn(&spSnapIn);
if (sc)
sc.TraceAndClear(); // it's only events. Should not affect main functionality
else
{
// emit the event
sc = pConsoleDoc->ScOnSnapinAdded(spSnapIn);
if (sc)
sc.TraceAndClear(); // it's only events. Should not affect main functionality
}
}
}
UpdateAllViews(VIEW_RESELECT, 0);
}
if (pSnapInCache->IsHelpCollectionDirty())
{
sc = ScSetHelpCollectionInvalid();
if (sc)
goto Error;
}
Cleanup:
sc.Clear();
return sc;
Error:
sc.Trace_();
goto Cleanup;
MMC_CATCH
}
/*+-------------------------------------------------------------------------*
* ScCreateMTNodeTree
*
* Creates the tree of CMTNode's described by the CNewTreeNode tree rooted
* at pNew. This CMTNode tree can then be used for insertion in the scope
* tree.
*
* Returns a pointer to the root of the CMTNode tree.
*
*--------------------------------------------------------------------------*/
SC
ScCreateMTNodeTree(PNEWTREENODE pNew, CMTNode* pmtnParent,
CMTNode** ppNodeCreated)
{
DECLARE_SC(sc, TEXT("ScCreateMTNodeTree"));
sc = ScCheckPointers(ppNodeCreated);
if (sc)
return sc;
*ppNodeCreated = NULL;
sc = ScCheckPointers(pNew, pmtnParent);
if (sc)
return sc;
CMTNode* pmtnFirst = NULL;
CMTNode* pmtnCur = NULL;
CMTNode* pmtnPrev = NULL;
while (pNew != NULL)
{
if (pNew->m_pmtNewNode == NULL)
{
CSnapInPtr spSI;
SC sc = theApp.GetSnapInsCache()->ScGetSnapIn(pNew->m_clsidSnapIn, &spSI);
if (sc)
goto finally;
CMTSnapInNode* pmtn = new CMTSnapInNode(pNew->m_spSnapinProps);
if (pmtn == NULL)
{
sc = E_OUTOFMEMORY;
goto finally;
}
// get hold on the node:
// it either will be connected or deleted (on failure)
pmtnCur = pmtn;
pmtn->SetPrimarySnapIn(spSI);
sc = ScCheckPointers(pNew->m_spIComponentData, E_UNEXPECTED);
if (sc)
goto finally;
CComponentData* pCCD = pmtn->GetPrimaryComponentData();
sc = ScCheckPointers(pCCD, E_UNEXPECTED);
if (sc)
goto finally;
pCCD->SetIComponentData(pNew->m_spIComponentData);
sc = pmtn->Init();
if (sc)
{
TraceError (_T("CScopeTree::ScCreateMTNodeTree"), sc);
// continue even on error
sc.Clear();
}
if (pNew->m_spIComponentData != NULL)
{
CStr strBuf;
sc = LoadRootDisplayName(pNew->m_spIComponentData, strBuf);
if (sc)
{
TraceError (_T("CScopeTree::ScCreateMTNodeTree"), sc);
// continue even on error
sc.Clear();
}
else
{
pmtn->SetDisplayName(strBuf);
}
}
pNew->m_pmtNewSnapInNode = pmtn;
}
else
{
pmtnCur = pNew->m_pmtNewNode;
pmtnCur->AddRef();
}
pmtnCur->AttachParent(pmtnParent);
if (pNew->m_pChild != NULL)
{
CMTNode* pNodeCreated = NULL;
sc = ScCreateMTNodeTree(pNew->m_pChild, pmtnCur, &pNodeCreated);
if (sc)
goto finally;
sc = ScCheckPointers(pNodeCreated, E_UNEXPECTED);
if (sc)
goto finally;
pmtnCur->AttachChild(pNodeCreated);
}
if (pmtnPrev)
{
pmtnPrev->AttachNext(pmtnCur);
}
else if (pmtnFirst == NULL)
{
pmtnFirst = pmtnCur;
}
pmtnPrev = pmtnCur;
pmtnCur = NULL;
pNew = pNew->m_pNext;
}
finally:
if (sc)
{
// error - cleanup before return
while (pmtnFirst)
{
// point to the next
pmtnPrev = pmtnFirst;
pmtnFirst = pmtnPrev->Next();
// destroy the first one
pmtnPrev->AttachNext(NULL);
pmtnPrev->AttachParent(NULL);
pmtnPrev->Release();
}
if (pmtnCur)
{
pmtnCur->AttachParent(NULL);
pmtnCur->Release();
}
}
else
{
// assign the tree to be returned
*ppNodeCreated = pmtnFirst;
}
return sc;
}
void CScopeTree::Cleanup(void)
{
Dbg(DEB_USER1, "CScopeTree::CleanUp\n");
// Reset the MT node IDs to ROOTNODEID (e.g 1) so the new scope tree
// can start over correctly with new numbers
CMTNode::ResetID();
CComponentIDArray rgID;
rgID.SetSize(20, 10);
InformSnapinsOfDeletion(m_pMTNodeRoot, FALSE, rgID);
SAFE_RELEASE(m_pMTNodeRoot);
SAFE_RELEASE(m_pImageCache);
delete m_pDefaultTaskpads; m_pDefaultTaskpads = NULL;
delete m_pConsoleTaskpads; m_pConsoleTaskpads = NULL;
}
STDMETHODIMP CScopeTree::GetImageList(PLONG_PTR pImageList)
{
MMC_TRY
if (pImageList == NULL)
return E_POINTER;
HIMAGELIST* phiml = reinterpret_cast<HIMAGELIST *>(pImageList);
*phiml = GetImageList();
return ((*phiml) ? S_OK : E_FAIL);
MMC_CATCH
}
HIMAGELIST CScopeTree::GetImageList () const
{
ASSERT(m_pImageCache != NULL);
if (m_pImageCache == NULL)
return NULL;
return (m_pImageCache->GetImageList()->m_hImageList);
}
HRESULT CScopeTree::InsertConsoleTaskpad (CConsoleTaskpad *pConsoleTaskpad,
CNode *pNodeTarget, bool bStartTaskWizard)
{
DECLARE_SC (sc, _T("CScopeTree::InsertConsoleTaskpad"));
ASSERT(pConsoleTaskpad);
m_pConsoleTaskpads->push_back(*pConsoleTaskpad);
// make sure the taskpad now points to the one that is inside the list.
CConsoleTaskpad & consoleTaskpad = m_pConsoleTaskpads->back();
pConsoleTaskpad = &consoleTaskpad;
// reselect all nodes.
UpdateAllViews(VIEW_RESELECT, 0);
if(bStartTaskWizard)
{
typedef CComObject<CConsoleTaskCallbackImpl> t_TaskCallbackImpl;
t_TaskCallbackImpl* pTaskCallbackImpl;
sc = t_TaskCallbackImpl::CreateInstance(&pTaskCallbackImpl);
if (sc)
return (sc.ToHr());
ITaskCallbackPtr spTaskCallback = pTaskCallbackImpl; // addrefs/releases the object.
sc = pTaskCallbackImpl->ScInitialize(pConsoleTaskpad, this, pNodeTarget);
if (sc)
return (sc.ToHr());
pTaskCallbackImpl->OnNewTask();
UpdateAllViews(VIEW_RESELECT, 0);
}
return (sc.ToHr());
}
HRESULT CScopeTree::IsSynchronousExpansionRequired()
{
return (_IsSynchronousExpansionRequired() ? S_OK : S_FALSE);
}
HRESULT CScopeTree::RequireSynchronousExpansion(BOOL fRequireSyncExpand)
{
_RequireSynchronousExpansion (fRequireSyncExpand ? true : false);
return (S_OK);
}
//############################################################################
//############################################################################
//
// CScopeTree Object model methods - SnapIns collection methods
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScAdd
*
* PURPOSE: Adds a snap-in with the supplied CLSID or PROGID to the console.
*
* PARAMETERS:
* BSTR bstrSnapinNameOrCLSID :
* VARIANT varProperties
* SnapIn** ppSnapIn
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScAdd(
BSTR bstrSnapinNameOrCLSID, /* I:what snap-in? */
VARIANT varParentSnapinNode, /* I:Snapin under which this new snapin will be added (optional)*/
VARIANT varProperties, /* I:props to create with (optional)*/
SnapIn** ppSnapIn) /* O:created snap-in */
{
DECLARE_SC(sc, TEXT("CScopeTree::ScAdd"));
/*
* dereference VT_BYREF VARIANTs that VBScript might have passed us
*/
VARIANT* pProperties = ConvertByRefVariantToByValue (&varProperties);
VARIANT* pParentSnapinNode = ConvertByRefVariantToByValue (&varParentSnapinNode);
/*
* validate the parameters
*/
sc = ScCheckPointers(ppSnapIn, pProperties, pParentSnapinNode);
if (sc)
return (sc);
/*
* Get the properties for the new snap-in. This is an optional
* parameter, so VT_ERROR with DISP_E_PARAMNOTFOUND is OK
*/
PropertiesPtr spProperties;
if (!IsOptionalParamMissing (*pProperties))
{
/*
* Assign from the VARIANT (ain't smart pointers great?).
* If the QI returned E_NOINTERFACE, the smart pointer will be
* assigned NULL. If the QI failed in some other way, operator=
* will throw a _com_error containing the failure HRESULT.
*/
try
{
if ((spProperties = _variant_t(*pProperties)) == NULL)
sc = E_NOINTERFACE;
}
catch (_com_error& err)
{
sc = err.Error();
}
if (sc)
return (sc.ToHr());
}
/*
* Get the parent snapin node for the new snap-in. This is an optional
* parameter, so VT_ERROR with DISP_E_PARAMNOTFOUND is OK
*/
SnapInPtr spParentSnapIn;
if (!IsOptionalParamMissing (*pParentSnapinNode))
{
/*
* Assign from the VARIANT (ain't smart pointers great?).
* If the QI returned E_NOINTERFACE, the smart pointer will be
* assigned NULL. If the QI failed in some other way, operator=
* will throw a _com_error containing the failure HRESULT.
*/
try
{
if ((spParentSnapIn = _variant_t(*pParentSnapinNode)) == NULL)
sc = E_NOINTERFACE;
}
catch (_com_error& err)
{
sc = err.Error();
}
if (sc)
return (sc.ToHr());
}
sc = ScAddSnapin(bstrSnapinNameOrCLSID, spParentSnapIn, spProperties, *ppSnapIn);
return sc.ToHr();
}
//+-------------------------------------------------------------------
//
// Member: CScopeTree:ScRemove
//
// Synopsis: Remove given snapin.
//
// Arguments: [pSnapIn] - the snapin (disp) interface.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScopeTree::ScRemove (PSNAPIN pSnapIn)
{
DECLARE_SC(sc, _T("CScopeTree:ScRemove"));
sc = ScCheckPointers(pSnapIn);
if (sc)
return sc;
// Get the MTNode for this snapin root.
CMTSnapInNode *pMTSnapinNode = NULL;
sc = CMTSnapInNode::ScGetCMTSnapinNode(pSnapIn, &pMTSnapinNode);
if (sc)
return sc;
CSnapinManager snapinMgr(GetRoot());
// Ask snapin mgr to add this snapin to deletednodes list.
sc = snapinMgr.ScRemoveSnapin(pMTSnapinNode);
if (sc)
return sc;
// Update the scope tree with changes made by snapin manager.
sc = ScAddOrRemoveSnapIns(snapinMgr.GetDeletedNodesList(),
snapinMgr.GetNewNodes());
if (sc)
return sc;
return (sc);
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetNextStaticNode
*
* PURPOSE: Returns the next static node (either the child or sibling) of the supplied node.
* This is slightly different from CMTNode::NextStaticNode(), which includes the node
* itself in the search.
*
* PARAMETERS:
* CMTNode *pMTNode : The supplied node.
*
* RETURNS:
* CMTSnapInNode *
*
*+-------------------------------------------------------------------------*/
CMTSnapInNode *
CScopeTree::GetNextStaticNode(CMTNode *pMTNode)
{
CMTSnapInNode *pMTSnapInNode = NULL;
if(!pMTNode)
return NULL;
// go thru all the children, then thru all the siblings.
CMTNode *pMTNodeChild = pMTNode->Child();
CMTNode *pMTNodeNext = pMTNode->Next();
CMTNode *pMTNodeParent= pMTNode->Parent();
// see if the child is a snapin
pMTSnapInNode = dynamic_cast<CMTSnapInNode*>(pMTNodeChild);
if(pMTSnapInNode)
return pMTSnapInNode;
// the child wasn't a snap-in node. Try its children.
if(pMTNodeChild)
{
pMTSnapInNode = GetNextStaticNode(pMTNodeChild);
if(pMTSnapInNode)
return pMTSnapInNode;
}
// That didn't work either. Check to see if the next node is a snapin
pMTSnapInNode = dynamic_cast<CMTSnapInNode*>(pMTNodeNext);
if(pMTSnapInNode)
return pMTSnapInNode;
// the next node wasn't a snap-in node. Try its children.
if(pMTNodeNext)
{
pMTSnapInNode = GetNextStaticNode(pMTNodeNext);
if(pMTSnapInNode)
return pMTSnapInNode;
}
// nothing was found in the next node's tree. Go to the next node of the parent.
if(pMTNodeParent)
{
CMTNode *pMTNodeParentNext = pMTNodeParent->Next();
if(pMTNodeParentNext)
{
pMTSnapInNode = dynamic_cast<CMTSnapInNode*>(pMTNodeParentNext);
if(pMTSnapInNode)
return pMTSnapInNode;
// the parent's next node was not a snapin node. Try its children
return GetNextStaticNode(pMTNodeParentNext);
}
}
// nothing left.
return NULL;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScItem
*
* PURPOSE: Returns a pointer to the i'th snap-in object.
*
* PARAMETERS:
* long Index : 1-based.
* PPSNAPIN ppSnapIn :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScItem(long Index, PPSNAPIN ppSnapIn)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScItem"));
// check parameters.
if( (Index <= 0) || (!ppSnapIn) )
return (sc = E_INVALIDARG);
CMTNode * pMTNode = GetRoot();
if(!pMTNode)
return (sc = E_UNEXPECTED);
CMTSnapInNode * pMTSINode = dynamic_cast<CMTSnapInNode*>(pMTNode);
// This should not be true as console root is a snapin.
sc = ScCheckPointers(pMTSINode, E_UNEXPECTED);
if (sc)
return sc;
while(--Index)
{
pMTSINode = GetNextStaticNode(pMTSINode);
if(!pMTSINode)
return (sc = E_INVALIDARG); // no more snap-ins. Argument was out of bounds.
}
if(!pMTSINode)
return (sc = E_UNEXPECTED); // defensive. Should never happen.
sc = pMTSINode->ScGetSnapIn(ppSnapIn);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::Scget_Count
*
* PURPOSE: Returns the number of stand alone snapins in the collection.
*
* PARAMETERS:
* PLONG Ptr to count.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::Scget_Count(PLONG pCount)
{
DECLARE_SC(sc, TEXT("CScopeTree::Scget_Count"));
sc = ScCheckPointers(pCount);
if (sc)
return sc;
*pCount = 0;
CMTNode * pMTNode = GetRoot();
if(!pMTNode)
return (sc = E_UNEXPECTED);
CMTSnapInNode * pMTSINode = dynamic_cast<CMTSnapInNode*>(pMTNode);
// This should not be true as console root is a snapin.
sc = ScCheckPointers(pMTSINode, E_UNEXPECTED);
if (sc)
return sc;
// Count all the static nodes (that are snapins).
do
{
(*pCount)++;
} while( (pMTSINode = GetNextStaticNode(pMTSINode)) != NULL);
return sc;
}
//############################################################################
//############################################################################
//
// CScopeTree Object model methods - SnapIns enumerator
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScGetNextSnapInPos
*
* PURPOSE: Returns the next snap-in in position.
*
* PARAMETERS:
* CSnapIns_Positon & pos : [in, out]: Must be non-NULL.
*
*
*
* RETURNS:
* SC: S_FALSE if there are no more items in the collection
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScGetNextSnapInPos(CSnapIns_Positon &pos)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetNextSnapInPos"));
if(pos == NULL)
return (sc = S_FALSE);
// for safety, copy the value and zero the output
CSnapIns_Positon posIn = pos;
pos = NULL;
ASSERT(posIn != NULL); //sanity check, already checked above.
CMTNode * pMTNode = GetRoot();
if(!pMTNode)
{
return (sc = E_UNEXPECTED);
}
CMTSnapInNode * pMTSINode = dynamic_cast<CMTSnapInNode*>(pMTNode);
if(!pMTSINode)
return (sc = S_FALSE);
// If we're not starting at the beginning, look for the current position.
// walk down the tree looking for the snap-in.
// although the position pointer is simply the pointer, we cannot dereference
// it because it may not be valid anymore.
while(pMTSINode != NULL)
{
CMTSnapInNode *pMTSINodeNext = GetNextStaticNode(pMTSINode);
if(posIn == pMTSINode) // found the position. Return the next one
{
pos = pMTSINodeNext;
return (sc = (pos == NULL) ? S_FALSE : S_OK);
}
pMTSINode = pMTSINodeNext;
}
return (sc = S_FALSE);
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScEnumNext
*
* PURPOSE: Returns the next snapin object pointer.
*
* PARAMETERS:
* _Position & pos :
* PDISPATCH & pDispatch :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScEnumNext(CSnapIns_Positon &pos, PDISPATCH & pDispatch)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScEnumNext"));
if( NULL==pos )
{
sc = S_FALSE;
return sc;
}
// at this point, we have a valid position.
SnapInPtr spSnapIn;
sc = pos->ScGetSnapIn(&spSnapIn);
if(sc)
return sc;
if(spSnapIn == NULL)
{
sc = E_UNEXPECTED; // should never happen.
return sc;
}
/*
* return the IDispatch for the object and leave a ref on it for the client
*/
pDispatch = spSnapIn.Detach();
//ignore this error
ScGetNextSnapInPos(pos); // this gets the correct pointer without dereferencing the present one.
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScEnumSkip
*
* PURPOSE: Skips the next celt items
*
* PARAMETERS:
* unsigned long :
* CSnapIns_Positon & pos :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScEnumSkip(unsigned long celt, unsigned long& celtSkipped, CSnapIns_Positon &pos)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScEnumSkip"));
// skip celt positions, don't check the last skip.
for(celtSkipped =0; celtSkipped<celt; celt++)
{
if (pos == NULL)
{
sc = S_FALSE;
return sc;
}
// go to the next view
sc = ScGetNextSnapInPos(pos);
if(sc.IsError() || sc == SC(S_FALSE))
return sc;
}
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScEnumReset
*
* PURPOSE: Sets the position to the first item
*
* PARAMETERS:
* CSnapIns_Positon & pos :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScEnumReset(CSnapIns_Positon &pos)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScEnumReset"));
// initial case. Return Console Root.
pos = dynamic_cast<CMTSnapInNode*>(CScopeTree::GetScopeTree()->GetRoot());
return sc;
}
//############################################################################
//############################################################################
//
// CScopeTree Object model methods - ScopeNamespace methods
//
//############################################################################
//############################################################################
/*+-------------------------------------------------------------------------*
*
* ScCheckInputs
*
* PURPOSE: little helper for the following three functions.
*
* PARAMETERS:
* PNODE pNode : Checked for NULL, and that it is a CMMCScopeNode.
* Also pNode->m_pMTNode is checked for NULL.
* PPNODE ppNode : Checked for NULL.
* PMTNODE pMTNode: [out]: pNode->m_pMTNode;
*
* RETURNS:
* inline SC
*
*+-------------------------------------------------------------------------*/
inline SC
ScCheckInputs(PNODE pNode, PPNODE ppNode, PMTNODE & pMTNode)
{
SC sc; // don't need DECLARE_SC here.
// check parameters
if( (NULL == pNode) || (NULL == ppNode) )
{
sc = E_INVALIDARG;
return sc;
}
// make sure we have a scope node
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(pNode);
if(!pScopeNode)
{
sc = E_INVALIDARG;
return sc;
}
// make sure it's node pointer is good
if(!pScopeNode->GetMTNode())
{
sc = E_UNEXPECTED;
return sc;
}
pMTNode = pScopeNode->GetMTNode();
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScGetParent
*
* PURPOSE:
*
* PARAMETERS:
* PNODE pNode :
* PPNODE ppParent :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScGetParent(PNODE pNode, PPNODE ppParent)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetParent"));
PMTNODE pMTNode = NULL;
// check parameters
sc = ScCheckInputs(pNode, ppParent, pMTNode);
if(sc)
return sc;
sc = ScGetNode(pMTNode->Parent(), ppParent);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScGetChild
*
* PURPOSE:
*
* PARAMETERS:
* PNODE pNode :
* PPNODE ppChild :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScGetChild(PNODE pNode, PPNODE ppChild)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetChild"));
PMTNODE pMTNode = NULL;
// check parameters
sc = ScCheckInputs(pNode, ppChild, pMTNode);
if(sc)
return sc;
sc = ScGetNode(pMTNode->Child(), ppChild);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScGetNext
*
* PURPOSE:
*
* PARAMETERS:
* PNODE pNode :
* PPNODE ppNext :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScGetNext(PNODE pNode, PPNODE ppNext)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetNext"));
PMTNODE pMTNode = NULL;
// check parameters
sc = ScCheckInputs(pNode, ppNext, pMTNode);
if(sc)
return sc;
sc = ScGetNode(pMTNode->Next(), ppNext);
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScGetRoot
*
* PURPOSE: Returns a COM object for the Root the Root node.
*
* PARAMETERS:
* PPNODE ppRoot :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScGetRoot(PPNODE ppRoot)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetRoot"));
sc = ScGetRootNode(ppRoot);
return sc;
}
//+-------------------------------------------------------------------
//
// Member: CScopeTree::ScGetRootNode
//
// Synopsis: Helper that returns a COM object for the Root node.
//
// Arguments: [ppRootNode] - The root node ptr.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScopeTree::ScGetRootNode (PPNODE ppRootNode)
{
DECLARE_SC(sc, _T("CScopeTree::ScGetRootNode"));
sc = ScCheckPointers(ppRootNode);
if (sc)
return sc;
CMTNode* pMTRootNode = GetRoot();
sc = ScCheckPointers(pMTRootNode, E_UNEXPECTED);
if (sc)
return sc;
sc = ScGetNode(pMTRootNode, ppRootNode);
if (sc)
return sc;
return (sc);
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScExpand
*
* PURPOSE: Implements ScopeNameSpace::Expand. Expands the specified node.
*
* PARAMETERS:
* PNODE pNode :
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScExpand(PNODE pNode)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScExpand"));
// check parameters
sc = ScCheckPointers(pNode);
if(sc)
return sc;
// make sure we have a scope node
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(pNode);
if(!pScopeNode)
{
sc = E_INVALIDARG;
return sc;
}
// make sure it's node pointer is good
CMTNode* pMTNode = pScopeNode->GetMTNode();
if(!pMTNode)
{
sc = E_UNEXPECTED;
return sc;
}
if ( !pMTNode->WasExpandedAtLeastOnce() )
{
sc = pMTNode->Expand();
if (sc)
return sc;
}
return sc;
}
SC
CScopeTree::ScGetNode(CMTNode *pMTNode, PPNODE ppOut)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetNode"));
sc = ScCheckPointers(pMTNode, ppOut);
if(sc)
return sc;
*ppOut = NULL;
CMapMTNodeToMMCNode::iterator it = m_mapMTNodeToMMCNode.find(pMTNode);
if (it == m_mapMTNodeToMMCNode.end())
{
// not found - got to create one
typedef CComObject<CMMCScopeNode> CScopeNode;
CScopeNode *pScopeNode = NULL;
CScopeNode::CreateInstance(&pScopeNode);
sc = ScCheckPointers(pScopeNode, E_OUTOFMEMORY);
if(sc)
return sc;
// set up the internal pointer.
pScopeNode->m_pMTNode = pMTNode;
m_mapMTNodeToMMCNode.insert(CMapMTNodeToMMCNode::value_type(pMTNode, pScopeNode));
*ppOut = pScopeNode;
}
else
{
#ifdef DBG
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(it->second);
// just doublecheck the pointers
ASSERT(pScopeNode && pScopeNode->GetMTNode() == pMTNode);
#endif // DBG
*ppOut = it->second;
}
(*ppOut)->AddRef(); // addref the object for the client.
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScGetNode
*
* PURPOSE: Returns the CMTNode encapsulated by a Node.
*
* PARAMETERS:
* PNODE pNode :
* CMTNode * ppMTNodeOut : The return value.
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC
CScopeTree::ScGetNode(PNODE pNode, CMTNode **ppMTNodeOut)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScGetNode"));
sc = ScCheckPointers(pNode, ppMTNodeOut);
if (sc)
return sc;
// make sure we have a scope node
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(pNode);
if(!pScopeNode)
return (sc =E_FAIL);
*ppMTNodeOut = pScopeNode->GetMTNode();
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetHMTNode
*
* PURPOSE: returns the HMTNode for a node object
*
* PARAMETERS:
* PNODE pNode :
* HMTNODE * phMTNode :
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
HRESULT
CScopeTree::GetHMTNode(PNODE pNode, HMTNODE *phMTNode)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetHMTNode"));
sc = ScCheckPointers(pNode, phMTNode);
if (sc)
return sc.ToHr();
// initialize output
*phMTNode = NULL;
// make sure we have a scope node
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(pNode);
if(!pScopeNode)
{
// Not a valid node - that's expected. Do not assert nor trace
return E_FAIL;
}
CMTNode *pMTNode = pScopeNode->GetMTNode();
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
if (sc)
return sc.ToHr();
*phMTNode = CMTNode::ToHandle(pMTNode);
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetNodeID
*
* PURPOSE: returns node id for Node object
*
* PARAMETERS:
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
HRESULT CScopeTree::GetNodeID(PNODE pNode, MTNODEID *pID)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetNodeID"));
sc = ScCheckPointers(pNode, pID);
if (sc)
return sc.ToHr();
// make sure we have a scope node
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(pNode);
if(!pScopeNode)
{
// Not a valid node - that's expected. Do not assert nor trace
return E_FAIL;
}
CMTNode *pMTNode = pScopeNode->GetMTNode();
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
if (sc)
return sc.ToHr();
*pID = pMTNode->GetID();
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::GetNode
*
* PURPOSE: returns Node object referencing the specified node id
*
* PARAMETERS:
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
HRESULT CScopeTree::GetMMCNode(HMTNODE hMTNode, PPNODE ppNode)
{
DECLARE_SC(sc, TEXT("CScopeTree::GetMMCNode"));
// parameter checking
sc = ScCheckPointers((LPVOID)hMTNode);
if (sc)
return sc.ToHr();
// get the node
sc = ScGetNode(CMTNode::FromHandle(hMTNode), ppNode);
if (sc)
return sc.ToHr();
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CCScopeTree::ScUnadviseMTNode
*
* PURPOSE: informs Node objects about MTNode going down
*
* PARAMETERS:
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC CScopeTree::ScUnadviseMTNode(CMTNode* pMTNode)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScUnadviseMTNode"));
sc = ScCheckPointers(pMTNode);
if (sc)
return sc;
CMapMTNodeToMMCNode::iterator it = m_mapMTNodeToMMCNode.find(pMTNode);
// need to tell the com object [if we have one] this is the end of MTNode
if (it != m_mapMTNodeToMMCNode.end())
{
// make sure we have a scope node
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(it->second);
sc = ScCheckPointers(pScopeNode, E_UNEXPECTED);
if (sc)
return sc;
ASSERT(pScopeNode->GetMTNode() == pMTNode);
// can forget about the object from now on
pScopeNode->ResetMTNode();
m_mapMTNodeToMMCNode.erase(it);
}
return sc;
}
/*+-------------------------------------------------------------------------*
*
* CScopeTree::ScUnadviseMMCScopeNode
*
* PURPOSE: informs Scope tree about Node object about to be destroyed
*
* PARAMETERS:
*
* RETURNS:
* SC
*
*+-------------------------------------------------------------------------*/
SC CScopeTree::ScUnadviseMMCScopeNode(PNODE pNode)
{
DECLARE_SC(sc, TEXT("CScopeTree::ScUnadviseMMCScopeNode"));
sc = ScCheckPointers(pNode);
if (sc)
return sc;
CMMCScopeNode *pScopeNode = dynamic_cast<CMMCScopeNode *>(pNode);
sc = ScCheckPointers(pScopeNode, E_UNEXPECTED);
if (sc)
return sc;
CMTNode* pMTNode = pScopeNode->GetMTNode();
if (!pMTNode)
{
// orphan entry - ignore
#ifdef DBG
// to detect leaks in keeping the registry
CMapMTNodeToMMCNode::iterator it = m_mapMTNodeToMMCNode.begin();
while (it != m_mapMTNodeToMMCNode.end())
{
ASSERT(it->second != pNode);
++it;
}
#endif
return sc;
}
CMapMTNodeToMMCNode::iterator it = m_mapMTNodeToMMCNode.find(pMTNode);
// need to tell the com object [i.e. itself] this is the end of relationship with MTNode
if (it == m_mapMTNodeToMMCNode.end())
return sc = E_UNEXPECTED;
// make sure we really talking to itself
ASSERT(pScopeNode->GetMTNode() == pMTNode);
// can forget about the MTNode from now on
pScopeNode->ResetMTNode();
m_mapMTNodeToMMCNode.erase(it);
return sc;
}
/***************************************************************************\
*
* METHOD: CScopeTree::IsSnapinInUse
*
* PURPOSE: checks if snapin is in use by MMC.
* (check is done by examining snapin cache)
*
* PARAMETERS:
* REFCLSID refClsidSnapIn - [in] - snapin to examine
* PBOOL pbInUse - [out] - verification result
*
* RETURNS:
* SC - result code
*
\***************************************************************************/
STDMETHODIMP CScopeTree::IsSnapinInUse(/*[in]*/ REFCLSID refClsidSnapIn, /*[out]*/ PBOOL pbInUse)
{
DECLARE_SC(sc, TEXT("CScopeTree::IsSnapinInUse"));
// parameter check
sc = ScCheckPointers(pbInUse);
if (sc)
return sc.ToHr();
// out parameter initialization
*pbInUse = FALSE;
// getting the cache
CSnapInsCache* pCache = theApp.GetSnapInsCache();
sc = ScCheckPointers(pCache, E_UNEXPECTED);
if (sc)
return sc.ToHr();
// assume it exists
*pbInUse = TRUE;
// looup snapin
CSnapInPtr spSnapIn;
sc = pCache->ScFindSnapIn(refClsidSnapIn, &spSnapIn);
if(sc)
{
// if failed to find - assume one does not exist
*pbInUse = FALSE;
// no trace if not found
sc.Clear();
}
return sc.ToHr();
}
//+-------------------------------------------------------------------
//
// Member: CScopeTree::ScSetHelpCollectionInvalid
//
// Synopsis: Inform the document that help collection is invalid
//
// Arguments:
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CScopeTree::ScSetHelpCollectionInvalid ()
{
DECLARE_SC(sc, _T("CScopeTree::ScSetHelpCollectionInvalid"));
sc = ScCheckPointers(m_pConsoleData, m_pConsoleData->m_pConsoleDocument, E_UNEXPECTED);
if (sc)
return sc;
sc = m_pConsoleData->m_pConsoleDocument->ScSetHelpCollectionInvalid();
return (sc);
}