|
|
//+-------------------------------------------------------------------------
//
// 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"
#include "eventlock.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> { public: 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();
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) { 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()); }
STDMETHODIMP CScopeTree::QueryIterator(IScopeTreeIter** ppIter) { if (ppIter == NULL) return E_POINTER;
CComObject<CScopeTreeIterator>* pObject; CComObject<CScopeTreeIterator>::CreateInstance(&pObject);
return pObject->QueryInterface(IID_IScopeTreeIter, reinterpret_cast<void**>(ppIter)); }
STDMETHODIMP CScopeTree::QueryNodeCallback(INodeCallback** ppNodeCallback) { 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; }
STDMETHODIMP CScopeTree::CreateNode(HMTNODE hMTNode, LONG_PTR lViewData, BOOL fRootNode, HNODE* phNode) { 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; }
HRESULT CScopeTree::CloseView(int viewID) { 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; }
HRESULT CScopeTree::DeleteView(int viewID) { 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; }
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) { 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; }
HRESULT CScopeTree::IsDirty() { /*
* 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(); }
HRESULT CScopeTree::GetFileVersion (IStorage* pstgRoot, int* pnVersion) { 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); }
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) { DECLARE_SC(sc, TEXT("CScopeTree::GetPathString")); sc = ScCheckPointers(hmtnLeaf, ppszPath); if(sc) return sc.ToHr();
CMTNode* pmtnLeaf = CMTNode::FromHandle(hmtnLeaf); CMTNode* pmtnRoot = (hmtnRoot == NULL) ? m_pMTNodeRoot : CMTNode::FromHandle(hmtnRoot);
CStr strPath; _GetPathString(pmtnRoot, pmtnLeaf, strPath);
if (!strPath.IsEmpty()) { int cchPath = strPath.GetLength()+1; *ppszPath = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(cchPath * sizeof(OLECHAR))); if (*ppszPath == NULL) return (sc = E_OUTOFMEMORY).ToHr();
USES_CONVERSION; sc = StringCchCopyW(*ppszPath, cchPath, T2COLE(strPath)); if(sc) return sc.ToHr();
return S_OK; }
return (sc = E_FAIL).ToHr(); }
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) { 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; }
/*+-------------------------------------------------------------------------*
* * 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) { if (pClassID == NULL) return E_INVALIDARG;
*pClassID = CLSID_ScopeTree; return S_OK; }
#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);
/* Determine the node to Insert after */ CMTNode* pInsertAfter = NULL;
if (pSDI->mask & SDI_PREVIOUS) { pInsertAfter = pMTNodeRelative; } else if (pSDI->mask & SDI_NEXT) { pInsertAfter = pMTNodeRelative->Prev(); } else if (pSDI->mask & SDI_FIRST) { pInsertAfter = NULL; } else { pInsertAfter = pMTNodeParent->LastChild(); }
hMTNodePrev = (pInsertAfter==NULL ? (HMTNODE)TVI_FIRST : CMTNode::ToHandle(pInsertAfter));
/* Insert as child after pInsertAfter. If the latter is NULL, insert as
** the first child */ sc = pMTNodeParent->ScInsertChild(pMTNode, pInsertAfter); if(sc) { pMTNode->Release(); return sc; }
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);
*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; } 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) { DECLARE_SC(sc, TEXT("CScopeTree::_DeleteNode"));
//
// Delete from the scope tree.
//
sc = ScCheckPointers(pmtn); if (sc) return;
if (m_pMTNodeRoot == pmtn) { m_pMTNodeRoot->Release(); m_pMTNodeRoot = NULL; return; }
CMTNode* pmtnParent = pmtn->Parent();
sc = (pmtnParent ? sc : E_UNEXPECTED); if(sc) return;
sc = pmtnParent->ScDeleteChild(pmtn); if(sc) return;
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) { 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; // when notifications are suspended MMC & snapins get into the weirld states
// it is safer not to let scripts to be informed about the changes as well.
// this is there to fix windows bugs #474627 & 475801 ( 10/03/2001 )
LockComEventInterface(AppEvents);
// 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;
pmtnTemp->NotifyAddedToTree ();
SViewUpdateInfo vui; pmtnTemp->Parent()->CreatePathList(vui.path); vui.newNode = CMTNode::ToHandle(pmtnTemp); UpdateAllViews(VIEW_UPDATE_ADD, reinterpret_cast<LPARAM>(&vui)); vui.path.RemoveAll();
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; }
//+-------------------------------------------------------------------
//
// Name: ScCreateMTNodeTree
//
// Synopsis: Creates the tree of CMTNodes described by the CNewTreeNode tree
// rooted at pNew. Attaches this subtree by inserting its root as
// the last child of pmtnParent.
//
// Arguments: pNew: [IN]: Non-Null pointer to the root of the describing tree.
// pmtnParent: [IN]: Non-Null pointer to node under which the
// subtree is to be attached
// ppNodeCreated: [OUT]: Non-null pointer to the pointer for the
// subtree to be created.
//
// Returns: SC
//
//--------------------------------------------------------------------
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;
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(); }
if (pNew->m_pChild != NULL) { // Recursively add children
CMTNode* pNodeCreated = NULL; sc = ScCreateMTNodeTree(pNew->m_pChild, pmtnCur, &pNodeCreated); if (sc) goto finally;
sc = ScCheckPointers(pNodeCreated, E_UNEXPECTED); if (sc) goto finally;
}
/* Insert Current Node after the last child. If last child is NULL,
** insert as the first and only child */ sc = pmtnParent->ScInsertChild(pmtnCur, pmtnParent->LastChild()); if(sc) goto finally;
if (pmtnFirst == NULL) { pmtnFirst = pmtnCur; }
pmtnCur = NULL;
pNew = pNew->m_pNext; }
finally:
if (sc) { // error - cleanup before return
if(pmtnFirst) { // Ignore returned status code: Already in error
pmtnParent->ScDeleteTrailingChildren(pmtnFirst); }
if (pmtnCur) { 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) { if (pImageList == NULL) return E_POINTER;
HIMAGELIST* phiml = reinterpret_cast<HIMAGELIST *>(pImageList); *phiml = GetImageList();
return ((*phiml) ? S_OK : E_FAIL); }
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); }
|