4341 lines
122 KiB
C++
4341 lines
122 KiB
C++
//____________________________________________________________________________
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: Node.cpp
|
|
//
|
|
// Contents:
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 9/16/1996 RaviR Created
|
|
//
|
|
//____________________________________________________________________________
|
|
|
|
#include "stdafx.h"
|
|
#include "macros.h"
|
|
#include "strings.h"
|
|
#include "ndmgr.h"
|
|
#include "regutil.h"
|
|
#include "taskenum.h"
|
|
#include "nodemgr.h"
|
|
#include "multisel.h"
|
|
#include "rsltitem.h"
|
|
#include "colwidth.h"
|
|
#include "viewpers.h"
|
|
#include "tasks.h"
|
|
#include "conview.h"
|
|
#include "columninfo.h"
|
|
#include "util.h" // for CoTaskDupString
|
|
#include "mmcprotocol.h"
|
|
#include "nodemgrdebug.h"
|
|
#include "copypast.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* class CConsoleTaskpadViewExtension
|
|
*
|
|
*
|
|
* PURPOSE: Implements console taskpads as a view extension
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
class CConsoleTaskpadViewExtension
|
|
{
|
|
public:
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* ScGetViews
|
|
*
|
|
* PURPOSE: Adds all console taskpad views to the view extension callback.
|
|
*
|
|
* PARAMETERS:
|
|
* CNode * pNode :
|
|
* LPVIEWEXTENSIONCALLBACK pViewExtensionCallback :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
static SC ScGetViews(CNode *pNode, LPVIEWEXTENSIONCALLBACK pViewExtensionCallback)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CConsoleTaskpadViewExtension::ScGetViews"));
|
|
|
|
CScopeTree* pScopeTree = CScopeTree::GetScopeTree();
|
|
|
|
sc = ScCheckPointers(pNode, pViewExtensionCallback, pScopeTree, E_FAIL);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// get a filtered list of taskpads that apply to this node.
|
|
CConsoleTaskpadFilteredList filteredList;
|
|
|
|
sc = pScopeTree->GetConsoleTaskpadList()->ScGetTaskpadList(pNode, filteredList);
|
|
if(sc)
|
|
return sc;
|
|
|
|
for(CConsoleTaskpadFilteredList::iterator iter = filteredList.begin(); iter!= filteredList.end(); ++iter)
|
|
{
|
|
CConsoleTaskpad *pConsoleTaskpad = *iter;
|
|
sc = ScAddViewForTaskpad(pConsoleTaskpad, pViewExtensionCallback);
|
|
if(sc)
|
|
return sc;
|
|
}
|
|
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* ScGetTaskpadViewExtension
|
|
*
|
|
* Returns S_OK if the given CLSID matches the CLSID of any taskpad view
|
|
* extension for the given node, S_FALSE or error otherwise.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
static SC ScGetViewExtensionTaskpad (CNode* pNode, const CLSID& clsid, CConsoleTaskpad*& pConsoleTaskpad)
|
|
{
|
|
DECLARE_SC (sc, _T("CConsoleTaskpadViewExtension::ScGetTaskpadViewExtension"));
|
|
|
|
/*
|
|
* initialize output
|
|
*/
|
|
pConsoleTaskpad = NULL;
|
|
|
|
/*
|
|
* check input
|
|
*/
|
|
sc = ScCheckPointers (pNode);
|
|
if(sc)
|
|
return sc;
|
|
|
|
CScopeTree* pScopeTree = CScopeTree::GetScopeTree();
|
|
sc = ScCheckPointers (pScopeTree, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
// get a filtered list of taskpads that apply to this node.
|
|
CConsoleTaskpadFilteredList filteredList;
|
|
|
|
sc = pScopeTree->GetConsoleTaskpadList()->ScGetTaskpadList(pNode, filteredList);
|
|
if(sc)
|
|
return sc;
|
|
|
|
for(CConsoleTaskpadFilteredList::iterator iter = filteredList.begin(); iter!= filteredList.end(); ++iter)
|
|
{
|
|
CConsoleTaskpad* pTempConsoleTaskpad = *iter;
|
|
sc = ScCheckPointers (pTempConsoleTaskpad, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
/*
|
|
* if the CLSID matches the ID of this taskpad, CLSID refers to
|
|
* a taskpad view extension
|
|
*/
|
|
if (clsid == pTempConsoleTaskpad->GetID())
|
|
{
|
|
pConsoleTaskpad = pTempConsoleTaskpad;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (sc);
|
|
}
|
|
|
|
private:
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* ScAddViewForTaskpad
|
|
*
|
|
* PURPOSE: Adds a view based on a console taskpad to the view extension
|
|
* callback.
|
|
*
|
|
* PARAMETERS:
|
|
* CConsoleTaskpad * pConsoleTaskpad :
|
|
* LPVIEWEXTENSIONCALLBACK pViewExtensionCallback :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
static SC ScAddViewForTaskpad(CConsoleTaskpad *pConsoleTaskpad, LPVIEWEXTENSIONCALLBACK pViewExtensionCallback)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CConsoleTaskpadViewExtension::ScAddViewForTaskpad"));
|
|
|
|
// validate inputs
|
|
sc = ScCheckPointers(pConsoleTaskpad, pViewExtensionCallback);
|
|
if(sc)
|
|
return sc;
|
|
|
|
MMC_EXT_VIEW_DATA extViewData = {0};
|
|
|
|
// get the string form of the taskpad ID.
|
|
CCoTaskMemPtr<WCHAR> spszTaskpadID;
|
|
sc = StringFromCLSID (pConsoleTaskpad->GetID(), &spszTaskpadID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
std::wstring strTaskpad = _W(MMC_PROTOCOL_SCHEMA_NAME) _W(":");
|
|
strTaskpad += spszTaskpadID;
|
|
|
|
extViewData.pszURL = strTaskpad.c_str();
|
|
|
|
extViewData.bReplacesDefaultView = pConsoleTaskpad->FReplacesDefaultView() ? TRUE : FALSE; // convert from bool to BOOL
|
|
extViewData.viewID = pConsoleTaskpad->GetID(); // set the GUID identifier of the view
|
|
|
|
USES_CONVERSION;
|
|
tstring strName = pConsoleTaskpad->GetName();
|
|
extViewData.pszViewTitle = T2COLE(strName.data()); // set the title of the view
|
|
|
|
if(!extViewData.pszViewTitle)
|
|
return (sc = E_OUTOFMEMORY).ToHr();
|
|
|
|
sc = pViewExtensionCallback->AddView(&extViewData);
|
|
|
|
return sc;
|
|
}
|
|
|
|
};
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CComponent
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CComponent);
|
|
|
|
void CComponent::Construct(CSnapIn * pSnapIn, CComponent* pComponent)
|
|
{
|
|
ASSERT(pSnapIn);
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CComponent);
|
|
|
|
m_spSnapIn = pSnapIn;
|
|
m_ComponentID = -1;
|
|
m_bIComponentInitialized = false;
|
|
|
|
if (pComponent)
|
|
{
|
|
ASSERT(pComponent->m_spIComponent != NULL);
|
|
ASSERT(pComponent->m_spIFrame != NULL);
|
|
|
|
m_spIComponent = pComponent->m_spIComponent;
|
|
m_spIFrame = pComponent->m_spIFrame;
|
|
m_spIRsltImageList = pComponent->m_spIRsltImageList;
|
|
|
|
m_ComponentID = pComponent->GetComponentID();
|
|
}
|
|
}
|
|
|
|
CComponent::~CComponent()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CComponent::~CComponent"));
|
|
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CComponent);
|
|
|
|
if (m_spIFrame)
|
|
{
|
|
sc = m_spIFrame->SetHeader(NULL);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
}
|
|
|
|
if (m_spIComponent)
|
|
{
|
|
sc = m_spIComponent->Destroy(NULL);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
}
|
|
}
|
|
|
|
HRESULT CComponent::Init(IComponentData* pIComponentData, HMTNODE hMTNode,
|
|
HNODE lNode,
|
|
COMPONENTID nComponentID, int viewID)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CComponent::Init"));
|
|
|
|
ASSERT(hMTNode != 0);
|
|
ASSERT(lNode != 0);
|
|
|
|
sc = ScCheckPointers( pIComponentData, E_POINTER );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
do
|
|
{
|
|
sc = pIComponentData->CreateComponent(&m_spIComponent);
|
|
if (sc)
|
|
break;
|
|
|
|
// recheck the pointers
|
|
sc = ScCheckPointers( m_spIComponent, E_UNEXPECTED );
|
|
if (sc)
|
|
break;
|
|
|
|
// Create an IFrame for this IComponent
|
|
#if _MSC_VER>=1100
|
|
sc = m_spIFrame.CreateInstance(CLSID_NodeInit, NULL, MMC_CLSCTX_INPROC);
|
|
#else
|
|
sc = m_spIFrame.CreateInstance(CLSID_NodeInit, MMC_CLSCTX_INPROC);
|
|
#endif
|
|
if (sc)
|
|
break;
|
|
|
|
// recheck the pointer
|
|
sc = ScCheckPointers( m_spIFrame, E_UNEXPECTED );
|
|
if (sc)
|
|
break;
|
|
|
|
Debug_SetNodeInitSnapinName(m_spSnapIn, m_spIFrame.GetInterfacePtr());
|
|
|
|
// Cache the IComponent in the NodeInit object
|
|
sc = m_spIFrame->SetComponent(m_spIComponent);
|
|
if (sc)
|
|
break;
|
|
|
|
// recheck the pointer
|
|
sc = ScCheckPointers( m_spSnapIn, E_UNEXPECTED );
|
|
if (sc)
|
|
break;
|
|
|
|
// Create scope image list
|
|
sc = m_spIFrame->CreateScopeImageList(m_spSnapIn->GetSnapInCLSID());
|
|
if (sc)
|
|
break;
|
|
|
|
sc = m_spIFrame->SetNode(hMTNode, lNode);
|
|
if (sc)
|
|
break;
|
|
|
|
ASSERT(nComponentID == GetComponentID());
|
|
sc = m_spIFrame->SetComponentID(nComponentID);
|
|
if (sc)
|
|
break;
|
|
|
|
// Result Image list is optional
|
|
m_spIRsltImageList = m_spIFrame;
|
|
sc = ScCheckPointers( m_spIRsltImageList, E_FAIL );
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
|
|
// Complete IComponent initialization.
|
|
// Init m_spIComponent with m_spIFrame.
|
|
sc = m_spIComponent->Initialize(m_spIFrame);
|
|
if (sc)
|
|
break;
|
|
|
|
CMTNode* const pMTNode = CMTNode::FromHandle (hMTNode);
|
|
sc = ScCheckPointers( pMTNode, E_UNEXPECTED );
|
|
if (sc)
|
|
break;
|
|
|
|
CMTSnapInNode* const pSnapInNode = pMTNode->GetStaticParent();
|
|
sc = ScCheckPointers( pSnapInNode, E_UNEXPECTED );
|
|
if (sc)
|
|
break;
|
|
|
|
sc = pSnapInNode->ScInitIComponent(this, viewID);
|
|
if (sc)
|
|
break;
|
|
|
|
} while (0);
|
|
|
|
if (sc)
|
|
{
|
|
m_spIComponent = NULL;
|
|
m_spIFrame = NULL;
|
|
m_spIRsltImageList = NULL;
|
|
}
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
inline HRESULT CComponent::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event,
|
|
LONG_PTR arg, LPARAM param)
|
|
{
|
|
ASSERT(m_spIComponent != NULL);
|
|
if (m_spIComponent == NULL)
|
|
return E_FAIL;
|
|
|
|
HRESULT hr = S_OK;
|
|
__try
|
|
{
|
|
hr = m_spIComponent->Notify(lpDataObject, event, arg, param);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
if (m_spSnapIn)
|
|
TraceSnapinException(m_spSnapIn->GetSnapInCLSID(), TEXT("IComponent::Notify"), event);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
SC CComponent::ScQueryDispatch(MMC_COOKIE cookie,
|
|
DATA_OBJECT_TYPES type,
|
|
PPDISPATCH ppSelectedObject)
|
|
{
|
|
DECLARE_SC(sc, _T("CComponent::ScQueryDispatch"));
|
|
sc = ScCheckPointers(m_spIComponent, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IComponent2Ptr spComponent2 = m_spIComponent;
|
|
sc = ScCheckPointers(spComponent2.GetInterfacePtr(), E_NOINTERFACE);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = spComponent2->QueryDispatch(cookie, type, ppSelectedObject);
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CComponent::ScResetConsoleVerbStates
|
|
//
|
|
// Synopsis: Reset the verbstates in the CConsoleVerbImpl (the one
|
|
// snapin is aware of).
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CComponent::ScResetConsoleVerbStates ()
|
|
{
|
|
DECLARE_SC(sc, _T("CComponent::ScResetConsoleVerbStates"));
|
|
|
|
IFramePrivate* pIFP = GetIFramePrivate();
|
|
sc = ScCheckPointers(pIFP, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IConsoleVerbPtr spConsoleVerb;
|
|
sc = pIFP->QueryConsoleVerb(&spConsoleVerb);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(spConsoleVerb, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CConsoleVerbImpl* pCVI = dynamic_cast<CConsoleVerbImpl*>(
|
|
static_cast<IConsoleVerb*>(spConsoleVerb));
|
|
sc = ScCheckPointers(pCVI, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
pCVI->SetDisabledAll();
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CNode
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CNode);
|
|
|
|
CNode::CNode (
|
|
CMTNode* pMTNode,
|
|
CViewData* pViewData,
|
|
bool fRootNode) :
|
|
m_pMTNode (pMTNode),
|
|
m_pViewData (pViewData),
|
|
m_hri (0),
|
|
m_dwFlags (0),
|
|
m_pPrimaryComponent (NULL),
|
|
m_bInitComponents (TRUE),
|
|
m_fRootNode (fRootNode),
|
|
m_fStaticNode (false)
|
|
{
|
|
CommonConstruct();
|
|
}
|
|
|
|
CNode::CNode (
|
|
CMTNode* pMTNode,
|
|
CViewData* pViewData,
|
|
bool fRootNode,
|
|
bool fStaticNode) :
|
|
m_pMTNode (pMTNode),
|
|
m_pViewData (pViewData),
|
|
m_hri (0),
|
|
m_dwFlags (0),
|
|
m_pPrimaryComponent (NULL),
|
|
m_bInitComponents (TRUE),
|
|
m_fRootNode (fRootNode),
|
|
m_fStaticNode (fStaticNode)
|
|
{
|
|
CommonConstruct();
|
|
}
|
|
|
|
CNode::CNode(const CNode& other) :
|
|
m_pMTNode (other.m_pMTNode),
|
|
m_pViewData (other.m_pViewData),
|
|
m_hri (other.m_hri),
|
|
m_dwFlags (other.m_dwFlags),
|
|
m_pPrimaryComponent (other.m_pPrimaryComponent),
|
|
m_bInitComponents (other.m_bInitComponents),
|
|
m_fRootNode (other.m_fRootNode),
|
|
m_fStaticNode (other.m_fStaticNode)
|
|
{
|
|
CommonConstruct();
|
|
}
|
|
|
|
|
|
void CNode::CommonConstruct ()
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CNode);
|
|
|
|
ASSERT (m_pMTNode != NULL);
|
|
m_pMTNode->AddRef();
|
|
}
|
|
|
|
|
|
CNode::~CNode()
|
|
{
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CNode);
|
|
|
|
CDataObjectCleanup::ScUnadviseNode( this );
|
|
|
|
/*
|
|
* if this is a non-static root node, delete the static
|
|
* parent node that was created for us in CMTNode::GetNode
|
|
*/
|
|
if (IsRootNode() && !IsStaticNode())
|
|
delete GetStaticParent();
|
|
|
|
ASSERT (m_pMTNode != NULL);
|
|
m_pMTNode->Release();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CNode::FromResultItem
|
|
*
|
|
* Converts a CResultItem to the CNode it references. This should only
|
|
* be called for CResultItems that represent scope items.
|
|
*
|
|
* This function is out-of-line to eliminate coupling between node.h and
|
|
* rsltitem.h.
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
CNode* CNode::FromResultItem (CResultItem* pri)
|
|
{
|
|
CNode* pNode = NULL;
|
|
|
|
if (pri != NULL)
|
|
{
|
|
/*
|
|
* only call for scope items
|
|
*/
|
|
ASSERT (pri->IsScopeItem());
|
|
|
|
if (pri->IsScopeItem())
|
|
pNode = CNode::FromHandle (pri->GetScopeNode());
|
|
}
|
|
|
|
return (pNode);
|
|
}
|
|
|
|
HRESULT
|
|
CNode::OnExpand(bool fExpand)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (fExpand == FALSE)
|
|
{
|
|
return (WasExpandedAtLeastOnce() == TRUE) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
if (WasExpandedAtLeastOnce() == TRUE)
|
|
return S_FALSE;
|
|
|
|
CMTNode* pMTNode = GetMTNode();
|
|
|
|
if (pMTNode->WasExpandedAtLeastOnce() == FALSE)
|
|
hr = pMTNode->Expand();
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CNode::ResetControlbars(BOOL bSelect, SELECTIONINFO* pSelInfo)
|
|
{
|
|
ASSERT(pSelInfo != NULL);
|
|
|
|
CViewData* pVD = GetViewData();
|
|
ASSERT(pVD != NULL);
|
|
if (!pVD)
|
|
return;
|
|
|
|
// Reset controlbars
|
|
CControlbarsCache* pCtrlbarsCache =
|
|
dynamic_cast<CControlbarsCache*>(GetControlbarsCache());
|
|
ASSERT(pCtrlbarsCache != NULL);
|
|
|
|
if (pCtrlbarsCache != NULL)
|
|
{
|
|
if (pSelInfo->m_bScope == TRUE)
|
|
pCtrlbarsCache->OnScopeSelChange(this, bSelect);
|
|
else if (pSelInfo->m_bBackground == FALSE)
|
|
pCtrlbarsCache->OnResultSelChange(this, pSelInfo->m_lCookie,
|
|
bSelect);
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScInitializeVerbs
|
|
//
|
|
// Synopsis: Selection has changed so initialize the verbs for given
|
|
// selection information.
|
|
//
|
|
// Arguments: [bSelect] - [in] Select or Deselect of an item.
|
|
// [pSelInfo] - [in] SELECTIONINFO ptr.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScInitializeVerbs (bool bSelect, SELECTIONINFO* pSelInfo)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScInitializeVerbs"));
|
|
sc = ScCheckPointers(pSelInfo);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CVerbSet *pVerbSet = dynamic_cast<CVerbSet*>(pViewData->GetVerbSet());
|
|
sc = ScCheckPointers(pVerbSet, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = pVerbSet->ScInitialize(this, pSelInfo->m_bScope, bSelect,
|
|
pSelInfo->m_bBackground, pSelInfo->m_lCookie);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
HRESULT CNode::GetDispInfo(LV_ITEMW* plvi)
|
|
{
|
|
ASSERT(plvi != NULL);
|
|
|
|
if (plvi->iSubItem == 0)
|
|
{
|
|
if (plvi->mask & LVIF_IMAGE)
|
|
{
|
|
plvi->iImage = GetResultImage();
|
|
ASSERT (plvi->iImage != -1);
|
|
if (plvi->iImage == -1)
|
|
plvi->iImage = 0;
|
|
}
|
|
|
|
if (plvi->mask & LVIF_TEXT)
|
|
{
|
|
tstring strName = GetDisplayName();
|
|
|
|
if (!strName.empty())
|
|
{
|
|
USES_CONVERSION;
|
|
wcsncpy (plvi->pszText, T2CW (strName.data()), plvi->cchTextMax);
|
|
}
|
|
else
|
|
plvi->pszText[0] = 0;
|
|
}
|
|
}
|
|
else if ((plvi->mask & LVIF_TEXT) && (plvi->cchTextMax > 0))
|
|
{
|
|
plvi->pszText[0] = 0;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: ScGetDataObject
|
|
//
|
|
// Synopsis: Given scope/result and cookie (lParam, if it is result item),
|
|
// get the dataobject of the item.
|
|
//
|
|
// Arguments:
|
|
// [bScopePane] - [in] Scope or Result.
|
|
// [lResultItemCookie] - [in] If Result pane is selected the item param.
|
|
// [bScopeItem] - [out] Is the dataobject returned for scope or result item.
|
|
// The scope item can be in result pane.
|
|
// [ppDataObject] - [out] The data-object (return val)
|
|
// [ppCComponent] - [out] NULL def parameter. The CComponent of the item. In case
|
|
// of multiselection, the items may belong to more than one
|
|
// component so a NULL is returned.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetDataObject(bool bScopePane, LPARAM lResultItemCookie, bool& bScopeItem,
|
|
LPDATAOBJECT* ppDataObject, CComponent **ppCComponent /*= NULL*/)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScGetDataObject"));
|
|
IDataObjectPtr spDataObject;
|
|
CComponent *pCC = NULL;
|
|
|
|
if (ppDataObject == NULL)
|
|
return (sc = E_POINTER);
|
|
|
|
*ppDataObject = NULL; // init
|
|
if (ppCComponent)
|
|
*ppCComponent = NULL;
|
|
|
|
bScopeItem = bScopePane;
|
|
|
|
// In MMC1.0 when result pane background is selected, for any
|
|
// toolbar operation we pass the dataobject of scope selected item.
|
|
// The following code is added for this compatibility.
|
|
if (lResultItemCookie == LVDATA_BACKGROUND) // =>Result background has focus
|
|
{
|
|
bScopeItem = TRUE;
|
|
}
|
|
|
|
if (bScopeItem) // => Scope pane has focus
|
|
{
|
|
CMTNode* pMTNode = GetMTNode();
|
|
if (NULL == pMTNode)
|
|
return (sc = E_UNEXPECTED);
|
|
sc = pMTNode->QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
pCC = GetPrimaryComponent();
|
|
}
|
|
else if (lResultItemCookie == LVDATA_CUSTOMOCX) // => Custom OCX has focus
|
|
{
|
|
*ppDataObject = DOBJ_CUSTOMOCX;
|
|
pCC = GetPrimaryComponent();
|
|
}
|
|
else if (lResultItemCookie == LVDATA_CUSTOMWEB) // => Web has focus
|
|
{
|
|
*ppDataObject = DOBJ_CUSTOMWEB;
|
|
pCC = GetPrimaryComponent();
|
|
}
|
|
else if (lResultItemCookie == LVDATA_MULTISELECT) // => multi selection
|
|
{
|
|
// Do not calculate CComponent for multisel dataobject as there are multiple
|
|
// items and they can be from different snapins (so different components).
|
|
CViewData* pVD = GetViewData();
|
|
if (NULL == pVD)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
CMultiSelection* pMS = pVD->GetMultiSelection();
|
|
if (NULL == pMS)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
sc = pMS->GetMultiSelDataObject(ppDataObject);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
else // result item has focus
|
|
{
|
|
CViewData* pVD = GetViewData();
|
|
if (NULL == pVD)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
if (! pVD->IsVirtualList())
|
|
{
|
|
CResultItem* pri = CResultItem::FromHandle (lResultItemCookie);
|
|
|
|
if (pri != NULL)
|
|
{
|
|
bScopeItem = pri->IsScopeItem();
|
|
lResultItemCookie = pri->GetSnapinData();
|
|
|
|
if (! bScopeItem)
|
|
pCC = GetComponent(pri->GetOwnerID());
|
|
}
|
|
}
|
|
else
|
|
pCC = GetPrimaryComponent();
|
|
|
|
if (bScopeItem)
|
|
{
|
|
CNode* pNode = CNode::FromHandle((HNODE) lResultItemCookie);
|
|
CMTNode* pMTNode = pNode ? pNode->GetMTNode() : NULL;
|
|
|
|
if (NULL == pMTNode)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
sc = pMTNode->QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
pCC = pNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
if (NULL == pCC)
|
|
return (sc = E_UNEXPECTED);
|
|
sc = pCC->QueryDataObject(lResultItemCookie, CCT_RESULT, &spDataObject);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
}
|
|
|
|
// if required, get the component of this node
|
|
if (ppCComponent)
|
|
{
|
|
*ppCComponent = pCC;
|
|
sc = ScCheckPointers( *ppCComponent, E_UNEXPECTED );
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
if (SUCCEEDED(sc.ToHr()) && *ppDataObject == NULL)
|
|
*ppDataObject = spDataObject.Detach();
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScGetDropTargetDataObject
|
|
//
|
|
// Synopsis: Given the context get the data object that allows the
|
|
// to be drop target (allows paste).
|
|
//
|
|
// In MMC1.2 the drop target is always scope node. In MMC2.0
|
|
// it can be any non-virtual (??) result item. If the snapin
|
|
// has RVTI_LIST_OPTIONS_ALLOWPASTE set, then if the item selected
|
|
// is in result pane then data object corresponds to result item
|
|
// else it is scope item.
|
|
//
|
|
// Arguments:
|
|
// [bScopePane] - Scope or Result.
|
|
// [lResultItemCookie] - If Result pane is selected the item param.
|
|
// [ppDataObject] - The data-object (return val)
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetDropTargetDataObject(bool bScopePane, LPARAM lResultItemCookie, LPDATAOBJECT *ppDataObject)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScGetDropTargetDataObject"));
|
|
sc = ScCheckPointers(ppDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
*ppDataObject = NULL;
|
|
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (pViewData->GetListOptions() & RVTI_LIST_OPTIONS_ALLOWPASTE)
|
|
{
|
|
bool bScopeItem;
|
|
// MMC2.0 use the given context.
|
|
sc = ScGetDataObject(bScopePane, lResultItemCookie, bScopeItem, ppDataObject);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
// MMC1.2 Always scope node.
|
|
sc = QueryDataObject(CCT_SCOPE, ppDataObject);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNode::ScGetPropertyFromINodeProperties
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* BOOL bForScopeItem :
|
|
* LPARAM resultItemParam :
|
|
* BSTR bstrPropertyName :
|
|
* PBSTR pbstrPropertyValue :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CNode::ScGetPropertyFromINodeProperties(LPDATAOBJECT pDataObject, BOOL bForScopeItem, LPARAM resultItemParam, BSTR bstrPropertyName, PBSTR pbstrPropertyValue)
|
|
{
|
|
//DECLARE_SC(sc, TEXT("CNode::ScGetPropertyFromINodeProperties"));
|
|
SC sc; // do not use DECLARE_SC here - want to silently ignore errors
|
|
|
|
sc = ScCheckPointers(pDataObject, bstrPropertyName, pbstrPropertyValue);
|
|
if(sc)
|
|
return sc;
|
|
|
|
if(bForScopeItem)
|
|
{
|
|
// get the MTNode
|
|
CMTNode * pMTNode = GetMTNode();
|
|
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// ask MTNode to get it
|
|
sc = pMTNode->ScGetPropertyFromINodeProperties(pDataObject, bstrPropertyName, pbstrPropertyValue);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// done!
|
|
return sc;
|
|
}
|
|
|
|
// for result item.
|
|
|
|
CComponent *pComponent = GetPrimaryComponent();
|
|
|
|
sc = ScCheckPointers(pComponent);
|
|
if(sc)
|
|
{
|
|
SC scRet = sc; // returns but does not trace the error
|
|
sc.Clear();
|
|
return scRet;
|
|
}
|
|
|
|
// get the IComponent and QI for INodeProperties
|
|
INodePropertiesPtr spNodeProperties = pComponent->GetIComponent();
|
|
|
|
// at this point we should have a valid interface if it is supported
|
|
sc = ScCheckPointers(spNodeProperties, E_NOINTERFACE);
|
|
if(sc)
|
|
return sc;
|
|
|
|
sc = spNodeProperties->GetProperty(pDataObject, bstrPropertyName, pbstrPropertyValue);
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNode::ScExecuteShellCommand
|
|
*
|
|
* PURPOSE: Executes a shell command with the specified parameters in the
|
|
* specified directory with the correct window size
|
|
*
|
|
* PARAMETERS:
|
|
* BSTR Command :
|
|
* BSTR Directory :
|
|
* BSTR Parameters :
|
|
* BSTR WindowState :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CNode::ScExecuteShellCommand(BSTR Command, BSTR Directory, BSTR Parameters, BSTR WindowState)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScExecuteShellCommand"));
|
|
|
|
sc = ScCheckPointers(Command, Directory, Parameters, WindowState);
|
|
if(sc)
|
|
return sc;
|
|
|
|
USES_CONVERSION;
|
|
|
|
CStr strParameters = W2T(Parameters);
|
|
CStr strWindowState= W2T(WindowState);
|
|
|
|
if(strWindowState.GetLength()==0)
|
|
strWindowState= XML_ENUM_WINDOW_STATE_RESTORED; // normal
|
|
|
|
SHELLEXECUTEINFO sei;
|
|
ZeroMemory (&sei, sizeof(sei));
|
|
|
|
sei.cbSize = sizeof(sei);
|
|
sei.lpFile = W2T(Command);
|
|
sei.lpParameters = strParameters;
|
|
sei.lpDirectory = W2T(Directory);
|
|
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_DOENVSUBST;
|
|
|
|
sei.nShow = (strWindowState == XML_ENUM_WINDOW_STATE_MAXIMIZED) ? SW_SHOWMAXIMIZED :
|
|
(strWindowState == XML_ENUM_WINDOW_STATE_MINIMIZED) ? SW_SHOWMINIMIZED :
|
|
SW_SHOWNORMAL ;
|
|
|
|
if (ShellExecuteEx(&sei))
|
|
CloseHandle (sei.hProcess);
|
|
else
|
|
sc = ScFromWin32((GetLastError ()));
|
|
|
|
return sc;
|
|
}
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class COCX
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(COCX);
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class COCXNode
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(COCXNode);
|
|
|
|
|
|
HRESULT CNode::InitComponents()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::InitComponents"));
|
|
|
|
if (m_bInitComponents == FALSE)
|
|
return S_OK;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Initialize the component.
|
|
|
|
CMTNode * pMTNode = GetMTNode();
|
|
if (pMTNode == NULL)
|
|
return (E_UNEXPECTED);
|
|
|
|
// Ensure the master node is initialized.
|
|
if (!pMTNode->IsInitialized())
|
|
hr = pMTNode->Init();
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CMTSnapInNode* pMTSnapInNode = pMTNode->GetStaticParent();
|
|
if (pMTSnapInNode == NULL)
|
|
return (E_UNEXPECTED);
|
|
|
|
HMTNODE hMTNode = CMTNode::ToHandle(pMTSnapInNode);
|
|
HNODE hNode = CNode::ToHandle(GetStaticParent());
|
|
|
|
CSnapIn* pSnapIn = pMTNode->GetPrimarySnapIn();
|
|
if (pSnapIn == NULL)
|
|
return (E_UNEXPECTED);
|
|
|
|
CComponentData* pCCD = pMTSnapInNode->GetComponentData(pSnapIn->GetSnapInCLSID());
|
|
if (pCCD == NULL)
|
|
return E_FAIL;
|
|
|
|
if (m_pPrimaryComponent == NULL)
|
|
m_pPrimaryComponent = pMTSnapInNode->GetComponent(GetViewID(),
|
|
pCCD->GetComponentID(), pSnapIn);
|
|
|
|
if(m_pPrimaryComponent == NULL)
|
|
return E_UNEXPECTED;
|
|
|
|
ASSERT(m_pPrimaryComponent != NULL);
|
|
|
|
//
|
|
// Init PRIMARY Component.
|
|
//
|
|
|
|
if (!m_pPrimaryComponent->IsInitialized())
|
|
{
|
|
ASSERT(pCCD->GetComponentID() == m_pPrimaryComponent->GetComponentID());
|
|
|
|
hr = m_pPrimaryComponent->Init(pCCD->GetIComponentData(), hMTNode, hNode,
|
|
pCCD->GetComponentID(), GetViewID());
|
|
|
|
// Abort if PRIMARY Component fails to init.
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
m_bInitComponents = FALSE;
|
|
|
|
//
|
|
// Now initalize the extension components. (create them if necessary)
|
|
//
|
|
|
|
// Get the node-type of this node
|
|
GUID guidNodeType;
|
|
//hr = pCCD->GetNodeType(pMTNode->GetUserParam(), &guidNodeType);
|
|
hr = pMTNode->GetNodeType(&guidNodeType);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
LPCLSID pDynExtCLSID;
|
|
int cDynExt = pMTNode->GetDynExtCLSID(&pDynExtCLSID);
|
|
|
|
CExtensionsIterator it;
|
|
// TODO: try to use the easier form of it.ScInitialize()
|
|
sc = it.ScInitialize(pSnapIn, guidNodeType, g_szNameSpace, pDynExtCLSID, cDynExt);
|
|
if(sc)
|
|
return S_FALSE;
|
|
|
|
BOOL fProblem = FALSE;
|
|
|
|
for (; it.IsEnd() == FALSE; it.Advance())
|
|
{
|
|
pCCD = pMTSnapInNode->GetComponentData(it.GetCLSID());
|
|
if (pCCD == NULL)
|
|
continue;
|
|
|
|
CComponent* pCC = pMTSnapInNode->GetComponent(GetViewID(),
|
|
pCCD->GetComponentID(), pCCD->GetSnapIn());
|
|
|
|
if (pCC->IsInitialized() == TRUE)
|
|
continue;
|
|
|
|
hr = pCC->Init(pCCD->GetIComponentData(), hMTNode, hNode,
|
|
pCCD->GetComponentID(), GetViewID());
|
|
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
fProblem = TRUE; // Continue even on error.
|
|
}
|
|
|
|
if (fProblem == TRUE)
|
|
{
|
|
// TODO: Put up an error message.
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNode::OnInitOCX
|
|
*
|
|
* PURPOSE: Sends the MMCN_INITOCX notification when an OCX is created.
|
|
*
|
|
* PARAMETERS:
|
|
* IUnknown* pUnk :
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CNode::OnInitOCX(IUnknown* pUnk)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::OnInitOCX"));
|
|
|
|
IDataObjectPtr spdtobj;
|
|
sc = QueryDataObject(CCT_SCOPE, &spdtobj);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
CComponent* pCC = GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pCC->Notify(spdtobj, MMCN_INITOCX, 0, reinterpret_cast<LPARAM>(pUnk));
|
|
sc.Clear(); // must ignore errors here - Disk management returns E_UNEXPECTED.!
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
HRESULT CNode::OnCacheHint(int nStartIndex, int nEndIndex)
|
|
{
|
|
CComponent* pCC = GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
if (pCC == NULL)
|
|
return E_FAIL;
|
|
|
|
IResultOwnerDataPtr spIResultOwnerData = pCC->GetIComponent();
|
|
if (spIResultOwnerData == NULL)
|
|
return S_FALSE;
|
|
|
|
return spIResultOwnerData->CacheHint(nStartIndex, nEndIndex);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::ScInitializeViewExtension
|
|
*
|
|
* PURPOSE: Sets callback representing view extension
|
|
*
|
|
* PARAMETERS:
|
|
* const CLSID& clsid - [in] view extension CLSID
|
|
* CViewData *pViewData - [in] view data
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::ScInitializeViewExtension(const CLSID& clsid, CViewData *pViewData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScInitializeViewExtension"));
|
|
|
|
sc = ScCheckPointers(pViewData);
|
|
if (sc)
|
|
return sc;
|
|
|
|
/*
|
|
* Get the CConsoleTaskpad that goes with it this view extension.
|
|
* If this is an ordinary (i.e. not taskpad) view extension,
|
|
* ScGetViewExtensionTaskpad will set pConsoleTaskpad to NULL.
|
|
*/
|
|
CConsoleTaskpad* pConsoleTaskpad = NULL;
|
|
sc = CConsoleTaskpadViewExtension::ScGetViewExtensionTaskpad (this, clsid, pConsoleTaskpad);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
typedef CComObject<CConsoleTaskCallbackImpl> t_ViewExtensionCallbackImpl;
|
|
t_ViewExtensionCallbackImpl* pViewExtensionCallbackImpl = NULL;
|
|
sc = t_ViewExtensionCallbackImpl::CreateInstance(&pViewExtensionCallbackImpl);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// recheck pointer
|
|
sc = ScCheckPointers(pViewExtensionCallbackImpl, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
pViewData->m_spTaskCallback = pViewExtensionCallbackImpl; // this addrefs/releases the object.
|
|
|
|
/*
|
|
* If this is a taskpad, initialize the view extension callback as
|
|
* a taskpad view extension. Otherwise initialize it as an ordinary
|
|
* view extension.
|
|
*/
|
|
if (pConsoleTaskpad != NULL)
|
|
{
|
|
sc = pViewExtensionCallbackImpl->ScInitialize (pConsoleTaskpad,
|
|
CScopeTree::GetScopeTree(),
|
|
this);
|
|
}
|
|
else
|
|
sc = pViewExtensionCallbackImpl->ScInitialize(clsid);
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNode::ScSetViewExtension
|
|
*
|
|
* PURPOSE: Forces a display of the given view extension.
|
|
*
|
|
* PARAMETERS:
|
|
* GUID * pGuidViewId : [IN]: The view extension to display.
|
|
* bool bUseDefaultTaskpad : [IN}
|
|
* bool bSetViewSettingDirty : [IN] (See below notes)
|
|
*
|
|
* Note:
|
|
* The view-extension-ID comes from
|
|
*
|
|
* 1. Viewsetting if one exists.
|
|
* 2. Given by CONUI when user changes tab for different taskpad.
|
|
* 3. There are cases in which a new view-extension installed (after the console
|
|
* file was created) that will be default. (This will be calculated in this method).
|
|
*
|
|
* In cases 1 & 3 viewsetting should not be made dirty.
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CNode::ScSetViewExtension(GUID *pGuidViewId, bool bUseDefaultTaskpad, bool bSetViewSettingDirty)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScSetViewExtension"));
|
|
|
|
CViewData * pViewData = GetViewData();
|
|
|
|
sc = ScCheckPointers(pGuidViewId, pViewData);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// collect the view extensions
|
|
CViewExtCollection vecExtensions;
|
|
CViewExtInsertIterator itExtensions(vecExtensions, vecExtensions.begin());
|
|
sc = ScGetViewExtensions(itExtensions);
|
|
if (sc)
|
|
sc.Trace_();
|
|
|
|
if ( bUseDefaultTaskpad )
|
|
{
|
|
// setup proper taskpad (tab to be selected)
|
|
CViewExtCollection::iterator it = vecExtensions.begin();
|
|
if (it != vecExtensions.end())
|
|
*pGuidViewId = it->viewID; // first one if such exist
|
|
else
|
|
*pGuidViewId = GUID_NULL; // default
|
|
}
|
|
else // locate the extension we need to select
|
|
{
|
|
// see if the extension really exist
|
|
CViewExtCollection::iterator it = vecExtensions.begin();
|
|
bool bDefaultIsReplaced = false;
|
|
while (it != vecExtensions.end() && !IsEqualGUID(*pGuidViewId, it->viewID) )
|
|
{
|
|
bDefaultIsReplaced = bDefaultIsReplaced || it->bReplacesDefaultView;
|
|
++it;
|
|
}
|
|
|
|
// found it?
|
|
bool bFound = (it != vecExtensions.end());
|
|
// one more chance - we were looking for default and one will be added!
|
|
bFound = bFound || ( IsEqualGUID( *pGuidViewId, GUID_NULL ) && !bDefaultIsReplaced );
|
|
|
|
if ( !bFound )
|
|
{
|
|
sc = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (sc) // extension missing! need to find the substitute
|
|
{
|
|
sc.Clear(); // ignore error
|
|
|
|
// default to first extension or NORMAL view here
|
|
CViewExtCollection::iterator it = vecExtensions.begin();
|
|
if (it != vecExtensions.end())
|
|
*pGuidViewId = it->viewID; // first available
|
|
else
|
|
*pGuidViewId = GUID_NULL; // "normal" if it's the only choice
|
|
}
|
|
|
|
// set the view extension if one really exist
|
|
if (*pGuidViewId != GUID_NULL)
|
|
{
|
|
sc = ScInitializeViewExtension(*pGuidViewId, GetViewData());
|
|
if (sc)
|
|
sc.TraceAndClear(); // ignore and proceed
|
|
}
|
|
else
|
|
{
|
|
pViewData->m_spTaskCallback = NULL;
|
|
}
|
|
|
|
sc = ScSetTaskpadID(*pGuidViewId, bSetViewSettingDirty);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: ScGetResultPane
|
|
//
|
|
// Synopsis: Get the result pane data from snapin or persisted data.
|
|
//
|
|
// Arguments: [strResultPane] - Result pane name (If it is OCX/WEB)
|
|
// [pViewOptions] - View options.
|
|
// [pGuidTaskpadID] - If there is a task-pad the ID.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
// History: 04-29-1999 AnandhaG Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC
|
|
CNode::ScGetResultPane(CResultViewType &rvt, GUID *pGuidTaskpadID)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScGetResultPane"));
|
|
sc = ScCheckPointers(pGuidTaskpadID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CComponent *pComponent = GetPrimaryComponent();
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pComponent, pViewData, E_UNEXPECTED);
|
|
if(sc)
|
|
return sc;
|
|
|
|
IComponent* pIComponent = pComponent->GetIComponent();
|
|
sc = ScCheckPointers(pIComponent, E_FAIL);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// 1. Setup any persisted/default console taskpads or view extensions.
|
|
sc = ScSetupTaskpad(pGuidTaskpadID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// 2. Get the persisted CResultViewType information.
|
|
sc = ScGetResultViewType(rvt);
|
|
if (sc)
|
|
return sc;
|
|
bool bResultViewDataIsPersisted = (sc == S_OK);
|
|
|
|
bool bSnapinChangingView = pViewData->IsSnapinChangingView();
|
|
CResultViewType rvtOriginal;
|
|
CStr strResultPane = _T(""); // init
|
|
|
|
// 3. If there is persisted result-view-type data then ask the snapin if it
|
|
// wants to restore the result-view with this data. If snapin is changing
|
|
// its view (by re-selection of node) then dont ask this question.
|
|
if (!bSnapinChangingView && bResultViewDataIsPersisted )
|
|
{
|
|
// 3.a) Ask snapin if it wants to restore the result-view with persisted data.
|
|
sc = ScRestoreResultView(rvt);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (S_OK == sc.ToHr()) // snapin accepted the resultviewtype settings so return.
|
|
return sc;
|
|
|
|
// 3.b) Snapin refused the persisted CResultViewType data so...
|
|
|
|
// cache the data to see if we need to modify the settings
|
|
rvtOriginal = rvt;
|
|
// Throw away the data as it is not accepted by snapin.
|
|
sc = rvt.ScReset();
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
// 4. Ask the snapin for result-view-type data.
|
|
IComponent2Ptr spIComponent2 = pIComponent;
|
|
if(spIComponent2 != NULL)
|
|
{
|
|
// should be able to move all this to a separate function.
|
|
RESULT_VIEW_TYPE_INFO rvti;
|
|
ZeroMemory(&rvti, sizeof(rvti));
|
|
|
|
// the snapin supports IComponent2. Use it to get the result view type.
|
|
sc = spIComponent2->GetResultViewType2(GetUserParam(), &rvti);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// at this point, we have a valid RESULT_VIEW_TYPE_INFO structure. Initialize the contents into rvt, which zeros out the structure
|
|
// and releases all the allocated strings
|
|
sc = rvt.ScInitialize(rvti);
|
|
if(sc)
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
// the snapin does not support IComponent2. Use IComponent to
|
|
// get the result view type from the snapin.
|
|
LPOLESTR pszView = NULL;
|
|
long lViewOptions = 0;
|
|
|
|
sc = pIComponent->GetResultViewType(GetUserParam(), &pszView, &lViewOptions);
|
|
if(sc)
|
|
return sc;
|
|
|
|
sc = rvt.ScInitialize(pszView, lViewOptions); // this also calls CoTaskMemFree on pszView
|
|
if(sc)
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
* 5. Persist ResultViewType information only if
|
|
* a. Snapin is changing the view OR
|
|
* b. Snapin rejected the persisted view setting (we already
|
|
* made sure it is not changing the view above) and new view setting
|
|
* given is different from original one.
|
|
*/
|
|
|
|
if ( bSnapinChangingView ||
|
|
(bResultViewDataIsPersisted && (rvtOriginal != rvt)) )
|
|
{
|
|
sc = ScSetResultViewType(rvt);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: ScRestoreResultView
|
|
//
|
|
// Synopsis: Restore the result pane from given persisted data.
|
|
//
|
|
// Arguments: [rvt] - CResultViewType data used to restore result pane.
|
|
//
|
|
// Returns: SC, S_OK if successfully restored.
|
|
// S_FALSE if snapin refused to restore.
|
|
//
|
|
// History: 04-29-1999 AnandhaG Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScRestoreResultView(const CResultViewType& rvt)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScRestoreResultView"));
|
|
|
|
CComponent* pComponent = GetPrimaryComponent();
|
|
sc = ScCheckPointers(pComponent, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IComponent2Ptr spIComponent2 = pComponent->GetIComponent();
|
|
if( (spIComponent2 != NULL) && (!rvt.IsMMC12LegacyData()))
|
|
{
|
|
RESULT_VIEW_TYPE_INFO rvti;
|
|
ZeroMemory(&rvti, sizeof(rvti));
|
|
|
|
sc = rvt.ScGetResultViewTypeInfo (rvti);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// the snapin supports IComponent2. Use it to get the result view type.
|
|
sc = spIComponent2->RestoreResultView(GetUserParam(), &rvti);
|
|
if(sc)
|
|
{
|
|
// If snapin returns error, trace it and translate it to S_FALSE (snapin refused to restore).
|
|
TraceSnapinError(TEXT("Snapin returned error from IComponent2::RestoreResultView"), sc);
|
|
sc = S_FALSE;
|
|
return sc;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// the snapin does not support IComponent2. Use IComponent to
|
|
// to restore the result view.
|
|
LPCOLESTR pszView = NULL;
|
|
long lViewOptions = 0;
|
|
|
|
sc = rvt.ScGetOldTypeViewOptions(&lViewOptions);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IDataObjectPtr spdtobj;
|
|
sc = QueryDataObject(CCT_SCOPE, &spdtobj);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Notify MMC of persisted view being restored.
|
|
MMC_RESTORE_VIEW mrv;
|
|
::ZeroMemory(&mrv, sizeof(mrv));
|
|
mrv.cookie = GetUserParam();
|
|
mrv.dwSize = sizeof(mrv);
|
|
mrv.lViewOptions = lViewOptions;
|
|
|
|
if (rvt.HasOCX())
|
|
{
|
|
pszView = rvt.GetOCX();
|
|
}
|
|
else if (rvt.HasWebBrowser())
|
|
{
|
|
pszView = rvt.GetURL();
|
|
}
|
|
|
|
if (pszView)
|
|
{
|
|
mrv.pViewType = (LPOLESTR)CoTaskMemAlloc( (wcslen(pszView) + 1) * sizeof(OLECHAR) );
|
|
sc = ScCheckPointers(mrv.pViewType, E_OUTOFMEMORY);
|
|
if (sc)
|
|
return sc;
|
|
wcscpy(mrv.pViewType, pszView);
|
|
pszView = NULL; // Dont want to abuse it later.
|
|
}
|
|
|
|
// If the snapin handles this notification we use the persisted
|
|
// data else call GetResultViewType of the snapin.
|
|
BOOL bHandledRestoreView = FALSE;
|
|
|
|
pComponent->Notify(spdtobj, MMCN_RESTORE_VIEW, (LPARAM)&mrv, (LPARAM)&bHandledRestoreView);
|
|
CoTaskMemFree(mrv.pViewType);
|
|
|
|
sc = (bHandledRestoreView) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: ScRestoreViewMode
|
|
//
|
|
// Synopsis: If the view mode is persisted restore it.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScRestoreViewMode()
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScRestoreViewMode"));
|
|
|
|
|
|
ULONG ulViewMode = 0;
|
|
sc = ScGetViewMode(ulViewMode);
|
|
if (sc != S_OK) // data not found or some error.
|
|
return sc;
|
|
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// tell conui to change the list mode.
|
|
CConsoleView* pConsoleView = pViewData->GetConsoleView();
|
|
sc = ScCheckPointers(pConsoleView, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = pConsoleView->ScChangeViewMode (ulViewMode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNode::ScSetupTaskpad
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* PARAMETERS:
|
|
* GUID * pTaskpadID : [OUT]: The guid of the taskpad, else GUID_NULL
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CNode::ScSetupTaskpad(GUID *pGuidTaskpadID)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::SetupTaskpad"));
|
|
sc = ScCheckPointers(pGuidTaskpadID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*pGuidTaskpadID = GUID_NULL;
|
|
|
|
// Get the persisted taskpad id if there is one.
|
|
sc = ScGetTaskpadID(*pGuidTaskpadID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// restore the taskpad if we've got a ViewSettings object.
|
|
// do not use default tab even in case view seting does not have a valid guid
|
|
// it only means the "Default" tab needs to be selected
|
|
// see bug #97001 - MMC does not persist select CTP when user returns to a node
|
|
bool bUseDefaultTaskpad = ( sc == S_FALSE );
|
|
|
|
// See ScSetViewExtension for parameter meaning.
|
|
sc = ScSetViewExtension(pGuidTaskpadID, bUseDefaultTaskpad, /*bSetViewSettingDirty*/ false);
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNode::ShowStandardListView
|
|
*
|
|
* PURPOSE:
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT CNode::ShowStandardListView()
|
|
{
|
|
CComponent* pCC = GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
if (pCC == NULL)
|
|
return E_FAIL;
|
|
|
|
IDataObjectPtr spDataObject = NULL;
|
|
HRESULT hr = QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
IExtendContextMenuPtr spIExtendContextMenu = pCC->GetIComponent();
|
|
if(!spIExtendContextMenu.GetInterfacePtr())
|
|
return S_FALSE;
|
|
|
|
hr = spIExtendContextMenu->Command(MMCC_STANDARD_VIEW_SELECT, spDataObject);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CNode::OnListPad(LONG_PTR arg, LPARAM param)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
IDataObjectPtr spdtobj;
|
|
hr = QueryDataObject(CCT_SCOPE, &spdtobj);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComponent* pCC = GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
hr = pCC->Notify(spdtobj, MMCN_LISTPAD, arg, param);
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CNode::OnGetPrimaryTask(IExtendTaskPad **ppExtendTaskPad)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
IExtendTaskPadPtr spExtendTaskPad = GetPrimaryComponent()->GetIComponent();
|
|
if (spExtendTaskPad == NULL)
|
|
return E_NOINTERFACE;
|
|
|
|
*ppExtendTaskPad = spExtendTaskPad.Detach();
|
|
|
|
return hr;
|
|
}
|
|
|
|
IFramePrivate *
|
|
CNode::GetIFramePrivate()
|
|
{
|
|
CComponent* pCC = GetPrimaryComponent();
|
|
if (pCC == NULL)
|
|
return (NULL);
|
|
|
|
IFramePrivate* pFramePrivate = pCC->GetIFramePrivate();
|
|
|
|
ASSERT (pFramePrivate != NULL);
|
|
return (pFramePrivate);
|
|
}
|
|
|
|
HRESULT
|
|
CNode::GetTaskEnumerator(LPOLESTR pszTaskGroup, IEnumTASK** ppEnumTask)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::GetTaskEnumerator"));
|
|
|
|
ASSERT(pszTaskGroup != NULL);
|
|
ASSERT(ppEnumTask != NULL);
|
|
|
|
if (!pszTaskGroup|| !ppEnumTask)
|
|
return E_INVALIDARG;
|
|
|
|
*ppEnumTask = NULL; // init
|
|
|
|
if (GetPrimaryComponent() == NULL)
|
|
{
|
|
ASSERT(0 && "UNexpected");
|
|
return S_FALSE;
|
|
}
|
|
|
|
CMTNode* pMTNode = GetMTNode();
|
|
ASSERT(pMTNode != NULL);
|
|
|
|
CMTSnapInNode* pMTSnapIn = pMTNode->GetStaticParent();
|
|
ASSERT(pMTSnapIn != NULL);
|
|
|
|
CComponentData* pComponentData = pMTNode->GetPrimaryComponentData();
|
|
ASSERT(pComponentData != NULL);
|
|
|
|
GUID guidNodeType;
|
|
HRESULT hr = pMTNode->GetNodeType(&guidNodeType);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
//
|
|
// Add primary task pad.
|
|
//
|
|
|
|
IExtendTaskPadPtr spExtendTaskPad =
|
|
GetPrimaryComponent()->GetIComponent();
|
|
|
|
if (spExtendTaskPad == NULL)
|
|
return S_FALSE;
|
|
|
|
IDataObjectPtr spDataObject;
|
|
hr = pMTNode->QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
IEnumTASKPtr spEnumTASK;
|
|
hr = spExtendTaskPad->EnumTasks(spDataObject, pszTaskGroup, &spEnumTASK);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CComObject<CTaskEnumerator>* pTaskEnumerator = new CComObject<CTaskEnumerator>;
|
|
ASSERT(pTaskEnumerator != NULL);
|
|
pTaskEnumerator->AddTaskEnumerator(pComponentData->GetCLSID(), spEnumTASK);
|
|
|
|
IEnumTASKPtr spEnumTask = pTaskEnumerator;
|
|
ASSERT(spEnumTask != NULL);
|
|
if (spEnumTask)
|
|
*ppEnumTask = spEnumTask.Detach();
|
|
|
|
//
|
|
// Add extension task pads.
|
|
//
|
|
CArray<GUID,GUID&> DynExtens;
|
|
ExtractDynExtensions(spDataObject, DynExtens);
|
|
|
|
CExtensionsIterator it;
|
|
sc = it.ScInitialize(pComponentData->GetSnapIn(), guidNodeType, g_szTask, DynExtens.GetData(), DynExtens.GetSize());
|
|
if (sc.IsError() || it.IsEnd() == TRUE)
|
|
return S_OK;
|
|
|
|
for (; it.IsEnd() == FALSE; it.Advance())
|
|
{
|
|
CComponentData* pCCD = pMTSnapIn->GetComponentData(it.GetCLSID());
|
|
|
|
if (pCCD == NULL)
|
|
{
|
|
// See if taskpad extension supports IComponentData. If so, we will add the it to
|
|
// the static node's component list and reuse the same instance each time its needed.
|
|
IComponentDataPtr spIComponentData;
|
|
hr = CreateSnapIn(it.GetCLSID(), &spIComponentData, FALSE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CSnapInPtr spSnapIn;
|
|
|
|
// If a dynamic extension, we have to get the snap-in ourselves
|
|
// otherwise the iterator has it
|
|
if (it.IsDynamic())
|
|
{
|
|
CSnapInsCache* const pCache = theApp.GetSnapInsCache();
|
|
ASSERT(pCache != NULL);
|
|
|
|
SC sc = pCache->ScGetSnapIn(it.GetCLSID(), &spSnapIn);
|
|
ASSERT(!sc.IsError());
|
|
|
|
// On failure, continue with other extensions
|
|
if (sc)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
spSnapIn = it.GetSnapIn();
|
|
}
|
|
|
|
ASSERT(spSnapIn != NULL);
|
|
|
|
pCCD = new CComponentData(spSnapIn);
|
|
|
|
if (pCCD != NULL)
|
|
{
|
|
pCCD->SetIComponentData(spIComponentData);
|
|
pMTSnapIn->AddComponentDataToArray(pCCD);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize and load component data if not already done
|
|
if (pCCD != NULL && pCCD->IsInitialized() == FALSE)
|
|
{
|
|
sc = pCCD->Init(CMTNode::ToHandle(pMTSnapIn));
|
|
|
|
if ( !sc.IsError() )
|
|
{
|
|
sc = pMTSnapIn->ScInitIComponentData(pCCD);
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
// On failure, continue with other extensions
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if failed to initialize, remove it from the component data array
|
|
pMTSnapIn->CompressComponentDataArray();
|
|
sc.TraceAndClear();
|
|
// On failure, continue with other extensions
|
|
continue;
|
|
}
|
|
}
|
|
|
|
IExtendTaskPadPtr spExtendTaskPad;
|
|
|
|
if (pCCD)
|
|
{
|
|
CComponent* pCC = pMTSnapIn->GetComponent(GetViewID(),
|
|
pCCD->GetComponentID(), pCCD->GetSnapIn());
|
|
ASSERT(pCC != NULL);
|
|
if (pCC)
|
|
{
|
|
// Ensure the IComponent is initialized.
|
|
if (!pCC->IsInitialized())
|
|
{
|
|
ASSERT(pCCD->GetComponentID() == pCC->GetComponentID());
|
|
|
|
hr = pCC->Init(pCCD->GetIComponentData(),
|
|
CMTNode::ToHandle(pMTSnapIn),
|
|
ToHandle(this),
|
|
pCCD->GetComponentID(),
|
|
GetViewID());
|
|
|
|
// Abort if PRIMARY Component fails to init.
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
|
|
spExtendTaskPad = pCC->GetIComponent();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = spExtendTaskPad.CreateInstance(it.GetCLSID(),
|
|
#if _MSC_VER >= 1100
|
|
NULL,
|
|
#endif
|
|
MMC_CLSCTX_INPROC);
|
|
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
continue;
|
|
}
|
|
|
|
if (spExtendTaskPad != NULL)
|
|
{
|
|
IEnumTASKPtr spEnumTASK;
|
|
HRESULT hr = spExtendTaskPad->EnumTasks(spDataObject, pszTaskGroup,
|
|
&spEnumTASK);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (hr == S_OK)
|
|
pTaskEnumerator->AddTaskEnumerator(it.GetCLSID(), spEnumTASK);
|
|
}
|
|
|
|
} // end for
|
|
|
|
|
|
// Return S_OK rather than hr because a failed extension shouldn't prevent the
|
|
// taskpad from coming up
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CNode::GetListPadInfo(IExtendTaskPad* pExtendTaskPad, LPOLESTR szTaskGroup,
|
|
MMC_ILISTPAD_INFO* pIListPadInfo)
|
|
{
|
|
if ((GetPrimaryComponent() == NULL) )
|
|
{
|
|
ASSERT(0 && "Asking for ListPadInfo on a node that has no snapin");
|
|
return S_FALSE;
|
|
}
|
|
|
|
// get primary snapin's IComponentData...
|
|
CMTNode* pMTNode = GetMTNode();
|
|
ASSERT(pMTNode != NULL);
|
|
CComponentData* pComponentData = pMTNode->GetPrimaryComponentData();
|
|
ASSERT(pComponentData != NULL);
|
|
|
|
// ... so we can get CLSID
|
|
pIListPadInfo->szClsid = NULL;
|
|
HRESULT hr = StringFromCLSID (pComponentData->GetCLSID(), &pIListPadInfo->szClsid);
|
|
ASSERT (pIListPadInfo->szClsid != NULL);
|
|
if (pIListPadInfo->szClsid == NULL) {
|
|
if (hr) return hr;
|
|
else return E_FAIL; // just in case.
|
|
}
|
|
|
|
// finally call taskpad extension for info
|
|
return pExtendTaskPad->GetListPadInfo (szTaskGroup, (MMC_LISTPAD_INFO*)pIListPadInfo);
|
|
}
|
|
|
|
void
|
|
CNode::OnTaskNotify(LONG_PTR arg, LPARAM param)
|
|
{
|
|
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(GetStaticParent());
|
|
ASSERT(pSINode != NULL);
|
|
|
|
IDataObjectPtr spDataObject;
|
|
QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
|
|
IExtendTaskPadPtr spExtendTaskPad;
|
|
CComponent* pCC;
|
|
LPOLESTR pszClsid = reinterpret_cast<LPOLESTR>(arg);
|
|
if (pszClsid[0] == 0)
|
|
{
|
|
pCC = GetPrimaryComponent();
|
|
if (!pCC)
|
|
return;
|
|
spExtendTaskPad = pCC->GetIComponent();
|
|
}
|
|
else
|
|
{
|
|
CLSID clsid;
|
|
HRESULT hr = ::CLSIDFromString(pszClsid, &clsid);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
// try to get IExtendTaskPad from IComponent, first;
|
|
// if that fails, just create using CLSID
|
|
pCC = pSINode->GetComponent(const_cast<const CLSID&>(clsid));
|
|
if (pCC)
|
|
spExtendTaskPad = pCC->GetIComponent();
|
|
if (spExtendTaskPad == NULL)
|
|
hr = spExtendTaskPad.CreateInstance(clsid,
|
|
#if _MSC_VER >= 1100
|
|
NULL,
|
|
#endif
|
|
MMC_CLSCTX_INPROC);
|
|
}
|
|
|
|
ASSERT (spExtendTaskPad != NULL);
|
|
if (spExtendTaskPad != NULL)
|
|
{
|
|
VARIANT** ppvarg = reinterpret_cast<VARIANT**>(param);
|
|
spExtendTaskPad->TaskNotify(spDataObject, ppvarg[0], ppvarg[1]);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CNode::OnScopeSelect(bool bSelect, SELECTIONINFO* pSelInfo)
|
|
{
|
|
DECLARE_SC (sc, _T("CNode::OnScopeSelect"));
|
|
sc = ScCheckPointers(pSelInfo);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
/*
|
|
* Bug 178484: reset the sort parameters when scope selection changes
|
|
*/
|
|
if (bSelect)
|
|
{
|
|
CComponent *pCC = GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
IFramePrivate *pFrame = pCC->GetIFramePrivate();
|
|
sc = ScCheckPointers(pFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
pFrame->ResetSortParameters();
|
|
}
|
|
|
|
if (bSelect == TRUE && WasExpandedAtLeastOnce() == FALSE)
|
|
{
|
|
sc = OnExpand(TRUE);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
ASSERT(IsInitialized() == TRUE);
|
|
|
|
sc = OnSelect(pSelInfo->m_pView, bSelect, pSelInfo->m_bResultPaneIsWeb);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
HRESULT CNode::OnActvate(LONG_PTR lActivate)
|
|
{
|
|
return (DeepNotify (MMCN_ACTIVATE, lActivate, 0));
|
|
}
|
|
|
|
|
|
HRESULT CNode::OnMinimize(LONG_PTR fMinimized)
|
|
{
|
|
return (DeepNotify (MMCN_MINIMIZED, fMinimized, 0));
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: SendShowEvent
|
|
//
|
|
// Synopsis: Send MMCN_SHOW notification to snapin, persist column
|
|
// data if necessary.
|
|
//
|
|
// Arguments: [bSelect] - TRUE if the node is selected.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNode::SendShowEvent(BOOL bSelect)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::SendShowEvent"));
|
|
|
|
CComponent* pCC = m_pPrimaryComponent;
|
|
ASSERT(pCC != NULL);
|
|
|
|
// Get the data object for the node and pass it to the primary snap-in
|
|
// and all the namespace extensions to the node.
|
|
IDataObjectPtr spDataObject;
|
|
HRESULT hr = QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CMTNode* pMTNode = GetMTNode();
|
|
|
|
IFramePrivatePtr spFrame = pCC->GetIFramePrivate();
|
|
sc = ScCheckPointers(spFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
IImageListPrivatePtr spImageList;
|
|
hr = spFrame->QueryResultImageList(reinterpret_cast<LPIMAGELIST*>(&spImageList));
|
|
ASSERT(SUCCEEDED(hr));
|
|
ASSERT(spImageList != NULL);
|
|
|
|
HSCOPEITEM hScopeItem = CMTNode::ToScopeItem(pMTNode);
|
|
|
|
if (bSelect == TRUE)
|
|
{
|
|
hr = pCC->Notify(spDataObject, MMCN_ADD_IMAGES,
|
|
reinterpret_cast<LPARAM>((LPIMAGELIST)spImageList),
|
|
hScopeItem);
|
|
CHECK_HRESULT(hr);
|
|
//if (FAILED(hr))
|
|
// return hr;
|
|
}
|
|
|
|
hr = pCC->Notify(spDataObject, MMCN_SHOW, bSelect, hScopeItem);
|
|
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if (bSelect)
|
|
{
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (pViewData->HasList() || pViewData->HasListPad())
|
|
{
|
|
sc = ScRestoreSortFromPersistedData();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Now try to restore the view mode.
|
|
sc =ScRestoreViewMode();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CNode::DeepNotify(MMC_NOTIFY_TYPE event, LONG_PTR arg, LPARAM param)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::DeepNotify"));
|
|
|
|
CComponent* pCC = m_pPrimaryComponent;
|
|
ASSERT(pCC != NULL);
|
|
if (pCC == NULL)
|
|
return E_UNEXPECTED;
|
|
|
|
// Get the data object for the node and pass it to the primary snap-in
|
|
// and all the namespace extensions to the node.
|
|
IDataObjectPtr spDataObject;
|
|
HRESULT hr = QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = pCC->Notify(spDataObject, event, arg, param);
|
|
CHECK_HRESULT(hr);
|
|
//if (FAILED(hr))
|
|
// return hr;
|
|
|
|
//
|
|
// Notify extensions.
|
|
//
|
|
|
|
CMTNode* pMTNode = GetMTNode();
|
|
|
|
// Get the node-type of this node
|
|
GUID guidNodeType;
|
|
hr = pMTNode->GetNodeType(&guidNodeType);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
LPCLSID pDynExtCLSID;
|
|
int cDynExt = pMTNode->GetDynExtCLSID(&pDynExtCLSID);
|
|
|
|
CExtensionsIterator it;
|
|
sc = it.ScInitialize(pMTNode->GetPrimarySnapIn(), guidNodeType, g_szNameSpace, pDynExtCLSID, cDynExt);
|
|
if (sc)
|
|
return S_FALSE;
|
|
|
|
BOOL fProblem = FALSE;
|
|
CSnapInNode* pSINode = GetStaticParent();
|
|
|
|
for (; it.IsEnd() == FALSE; it.Advance())
|
|
{
|
|
CComponent* pCC = pSINode->GetComponent(it.GetCLSID());
|
|
if (pCC == NULL)
|
|
continue;
|
|
|
|
hr = pCC->Notify(spDataObject, event, arg, param);
|
|
CHECK_HRESULT(hr);
|
|
|
|
// continue even if an error occurs with extension snapins
|
|
if (FAILED(hr))
|
|
fProblem = TRUE;
|
|
}
|
|
|
|
return (fProblem == TRUE) ? S_FALSE : S_OK;
|
|
}
|
|
|
|
HRESULT CNode::OnSelect(LPUNKNOWN lpView, BOOL bSelect,
|
|
BOOL bResultPaneIsWeb)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::OnSelect"));
|
|
|
|
#ifdef DBG
|
|
if (lpView == NULL)
|
|
ASSERT(bSelect == FALSE);
|
|
else
|
|
ASSERT(bSelect == TRUE);
|
|
#endif
|
|
|
|
sc = ScCheckPointers(m_pPrimaryComponent, E_UNEXPECTED);
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
return sc.ToHr();
|
|
}
|
|
|
|
CComponent* pCC = m_pPrimaryComponent;
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
IFramePrivate *pFrame = pCC->GetIFramePrivate();
|
|
sc = ScCheckPointers(pFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// set the correct view in the primary snap-in before it adds items
|
|
if (bSelect == TRUE)
|
|
pFrame->SetResultView(lpView);
|
|
|
|
IDataObjectPtr spDataObject;
|
|
sc = QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CMTNode* pMTNode = GetMTNode();
|
|
LPARAM hScopeItem = CMTNode::ToScopeItem(pMTNode);
|
|
|
|
// Send only the MMCN_SHOW message if result pane is the web view.
|
|
if (bResultPaneIsWeb)
|
|
{
|
|
return pCC->Notify(spDataObject, MMCN_SHOW, bSelect, hScopeItem);
|
|
}
|
|
|
|
// Send necessary events like MMCN_ADD_IMAGES and MMCN_SHOW to snapin
|
|
sc = SendShowEvent(bSelect);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// set the correct view in the primary snap-in after it's notified
|
|
if (bSelect == FALSE)
|
|
pFrame->SetResultView(NULL); //
|
|
// Deal with extension ssnap-ins
|
|
//
|
|
|
|
// Get the node-type of this node
|
|
GUID guidNodeType;
|
|
sc = pMTNode->GetNodeType(&guidNodeType);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
LPCLSID pDynExtCLSID;
|
|
int cDynExt = pMTNode->GetDynExtCLSID(&pDynExtCLSID);
|
|
|
|
CExtensionsIterator it;
|
|
sc = it.ScInitialize(pMTNode->GetPrimarySnapIn(), guidNodeType, g_szNameSpace, pDynExtCLSID, cDynExt);
|
|
if (sc)
|
|
return S_FALSE;
|
|
|
|
BOOL fProblem = FALSE;
|
|
CSnapInNode* pSINode = GetStaticParent();
|
|
|
|
for (; it.IsEnd() == FALSE; it.Advance())
|
|
{
|
|
CComponent* pCCExtnSnapin = pSINode->GetComponent(it.GetCLSID());
|
|
if (pCCExtnSnapin == NULL)
|
|
continue;
|
|
|
|
IFramePrivate *pFrameExtnSnapin = pCCExtnSnapin->GetIFramePrivate();
|
|
sc = ScCheckPointers(pFrameExtnSnapin, E_UNEXPECTED);
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
continue;
|
|
}
|
|
|
|
// set the correct view in the snap-in before it adds items
|
|
if (bSelect == FALSE)
|
|
{
|
|
pFrameExtnSnapin->SetResultView(NULL);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
pFrameExtnSnapin->SetResultView(lpView);
|
|
|
|
IImageListPrivatePtr spImageList;
|
|
sc = pCCExtnSnapin->GetIFramePrivate()->QueryResultImageList(
|
|
reinterpret_cast<LPIMAGELIST*>(&spImageList));
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
fProblem = TRUE;
|
|
continue;
|
|
}
|
|
|
|
sc = ScCheckPointers(spImageList, E_UNEXPECTED);
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
fProblem = TRUE;
|
|
continue;
|
|
}
|
|
|
|
SC scNoTrace = pCCExtnSnapin->Notify(spDataObject, MMCN_ADD_IMAGES,
|
|
reinterpret_cast<LPARAM>((LPIMAGELIST)spImageList),
|
|
hScopeItem);
|
|
if (scNoTrace)
|
|
{
|
|
TraceSnapinError(TEXT("Snapin returned error from IComponent::Notify MMCN_ADD_IMAGES"), scNoTrace);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (fProblem == TRUE) ? S_FALSE : S_OK;
|
|
}
|
|
|
|
void CNode::Reset()
|
|
{
|
|
m_pPrimaryComponent = NULL;
|
|
m_bInitComponents = TRUE;
|
|
}
|
|
|
|
HRESULT CNode::GetDispInfoForListItem(LV_ITEMW* plvi)
|
|
{
|
|
ASSERT(plvi != NULL);
|
|
|
|
RESULTDATAITEM rdi;
|
|
ZeroMemory(&rdi, sizeof(rdi));
|
|
|
|
if (plvi->mask & LVIF_TEXT)
|
|
{
|
|
ASSERT (!IsBadWritePtr (plvi->pszText, plvi->cchTextMax * sizeof (TCHAR)));
|
|
rdi.mask |= RDI_STR;
|
|
}
|
|
|
|
if (plvi->mask & LVIF_IMAGE)
|
|
rdi.mask |= RDI_IMAGE;
|
|
|
|
if (plvi->mask & LVIF_STATE)
|
|
rdi.mask |= RDI_STATE;
|
|
|
|
rdi.nCol = plvi->iSubItem;
|
|
|
|
|
|
CComponent* pCC = NULL;
|
|
|
|
// if virtual list
|
|
if (GetViewData()->IsVirtualList())
|
|
{
|
|
pCC = GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
|
|
// all we can pass is the item index
|
|
rdi.nIndex = plvi->iItem;
|
|
|
|
// no default for virtual lists
|
|
rdi.nImage = MMCLV_NOICON;
|
|
}
|
|
else
|
|
{
|
|
CResultItem* pri = CResultItem::FromHandle (plvi->lParam);
|
|
|
|
if (pri != NULL)
|
|
{
|
|
if (pri->IsScopeItem()) // Folder
|
|
{
|
|
// convert to real type
|
|
CNode* pNodeSubFldr = CNode::FromResultItem (pri);
|
|
ASSERT(IsBadReadPtr(pNodeSubFldr, sizeof(CNode)) == FALSE);
|
|
|
|
if (pNodeSubFldr->IsStaticNode() == TRUE) // Static folders
|
|
{
|
|
return pNodeSubFldr->GetDispInfo(plvi);
|
|
}
|
|
else // Enumerated folders
|
|
{
|
|
// Remap the LParam information.
|
|
rdi.lParam = pNodeSubFldr->GetUserParam();
|
|
rdi.bScopeItem = TRUE;
|
|
|
|
pCC = pNodeSubFldr->GetPrimaryComponent();
|
|
rdi.nImage = pNodeSubFldr->GetResultImage();
|
|
}
|
|
}
|
|
else // Leaf item
|
|
{
|
|
// Remap the LParam information.
|
|
rdi.nImage = pri->GetImageIndex();
|
|
rdi.lParam = pri->GetSnapinData();
|
|
pCC = GetPrimaryComponent();
|
|
ASSERT(GetComponent(pri->GetOwnerID()) == GetPrimaryComponent());
|
|
ASSERT(pCC != NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT hr = pCC->GetDisplayInfo(&rdi);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (rdi.mask & RDI_IMAGE)
|
|
{
|
|
if (rdi.nImage == MMCLV_NOICON)
|
|
{
|
|
plvi->iImage = rdi.bScopeItem ? eStockImage_Folder : eStockImage_File;
|
|
}
|
|
else
|
|
{
|
|
IImageListPrivate *pIL = pCC->GetIImageListPrivate();
|
|
HRESULT hr2 = pIL->MapRsltImage(pCC->GetComponentID(), rdi.nImage,
|
|
&(plvi->iImage));
|
|
if (FAILED(hr2))
|
|
{
|
|
Dbg(DEB_USER1, "can't map image provided by snapin. Using default image.\n");
|
|
plvi->iImage = rdi.bScopeItem ? eStockImage_Folder : eStockImage_File;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Move all other info from rdi into lviItem
|
|
if (rdi.mask & RDI_STR)
|
|
{
|
|
if (!IsBadStringPtrW (rdi.str, plvi->cchTextMax))
|
|
{
|
|
wcsncpy (plvi->pszText, rdi.str, plvi->cchTextMax);
|
|
|
|
// always terminate the string!
|
|
// see bug #416888 (ntraid9) 6/15/2001
|
|
if ( plvi->cchTextMax != 0 )
|
|
plvi->pszText[ plvi->cchTextMax - 1 ] = 0;
|
|
}
|
|
else if (plvi->cchTextMax > 0)
|
|
plvi->pszText[0] = 0;
|
|
}
|
|
|
|
if (rdi.mask & RDI_STATE)
|
|
plvi->state = rdi.nState;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScSaveSortData
|
|
//
|
|
// Synopsis: Save the given sort data for persistence.
|
|
//
|
|
// Arguments: [nCol] - sort column.
|
|
// [dwOptions] - sort options.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScSaveSortData (int nCol, DWORD dwOptions)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScSaveSortData"));
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CLSID guidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = ScGetSnapinAndColumnDataID(guidSnapin, columnID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CColumnSortInfo colSortInfo;
|
|
colSortInfo.m_nCol = nCol;
|
|
colSortInfo.m_dwSortOptions = dwOptions;
|
|
colSortInfo.m_lpUserParam = NULL;
|
|
|
|
sc = pViewData->ScSaveColumnSortData(guidSnapin, *pColID, colSortInfo);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Column data when saved includes the width/order data (column info list) and sort data.
|
|
// The width/order data should always be saved regardless of whether sort data is
|
|
// persisted or not. So save the width/order data.
|
|
CColumnInfoList columnInfoList;
|
|
TStringVector strColNames; // unused
|
|
|
|
// get the current data
|
|
sc = ScGetCurrentColumnData( columnInfoList, strColNames );
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = pViewData->ScSaveColumnInfoList(guidSnapin, *pColID, columnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: OnColumnClicked
|
|
//
|
|
// Synopsis: Ask snapin to sort.
|
|
//
|
|
// Arguments: [nCol] - Column to be sorted.
|
|
//
|
|
// Note: When column is clicked sort options and user param
|
|
// are unknown. So we set them to 0 (zero). In InternalSort
|
|
// the sort option is computed.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// History: RaviR Created
|
|
// 07-27-1999 AnandhaG renamed OnSort to OnColumnClicked
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNode::OnColumnClicked(LONG_PTR nCol)
|
|
{
|
|
CComponent* pComponent = GetPrimaryComponent();
|
|
ASSERT(pComponent != NULL);
|
|
if (NULL == pComponent)
|
|
return E_FAIL;
|
|
|
|
IResultDataPrivatePtr pResult = pComponent->GetIFramePrivate();
|
|
ASSERT(pResult != NULL);
|
|
if (NULL == pResult)
|
|
return E_FAIL;
|
|
|
|
HRESULT hr = pResult->InternalSort( nCol, 0, NULL,
|
|
TRUE /*column header clicked*/);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
BOOL bAscending = TRUE;
|
|
hr = pResult->GetSortDirection(&bAscending);
|
|
if (hr == S_OK)
|
|
hr = ScSaveSortData(nCol, bAscending ? 0 : RSI_DESCENDING).ToHr();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: RestoreSort
|
|
//
|
|
// Synopsis: Sort the list view with persisted data.
|
|
// Restore the sort with saved column # and
|
|
// sort-options (User param is NULL as this
|
|
// is user initiated MMCN_COLUMN_CLICK)*/
|
|
//
|
|
// Arguments: [nCol] - Column to be sorted.
|
|
// [dwSortOptions] - Sortoptions, ascend/descend...
|
|
//
|
|
// Note: Unlike OnColumnClicked this method wont set columns dirty
|
|
// after successful sort.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNode::RestoreSort(INT nCol, DWORD dwSortOptions)
|
|
{
|
|
CComponent* pComponent = GetPrimaryComponent();
|
|
ASSERT(pComponent != NULL);
|
|
if (NULL == pComponent)
|
|
return E_FAIL;
|
|
|
|
IResultDataPrivatePtr pResult = pComponent->GetIFramePrivate();
|
|
ASSERT(pResult != NULL);
|
|
if (NULL == pResult)
|
|
return E_FAIL;
|
|
|
|
HRESULT hr = pResult->InternalSort( nCol, dwSortOptions,
|
|
NULL /*NULL user param as this is user initiated*/,
|
|
FALSE /* Let us not send MMCN_COLUMN_CLICK*/);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScRestoreSortFromPersistedData
|
|
//
|
|
// Synopsis: Get persisted sort data if any and apply it to list-view.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScRestoreSortFromPersistedData ()
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScRestoreSortFromPersistedData"));
|
|
CViewData *pViewData = GetViewData();
|
|
|
|
if (! pViewData->HasList() && ! pViewData->HasListPad() )
|
|
return (sc = S_FALSE); // OCX gets MMCN_SHOW which may try to restore sort so this is no failure.
|
|
|
|
// To get CColumnSetData first get the column-id & snapin guid.
|
|
CLSID guidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = ScGetSnapinAndColumnDataID(guidSnapin, columnID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Get persisted data.
|
|
CColumnSetData columnSetData;
|
|
BOOL bRet = pViewData->RetrieveColumnData(guidSnapin, *pColID, columnSetData);
|
|
|
|
if (!bRet)
|
|
return (sc = S_FALSE);
|
|
|
|
CColumnInfoList* pColInfoList = columnSetData.get_ColumnInfoList();
|
|
if (!pColInfoList)
|
|
return (sc = S_FALSE);
|
|
|
|
IFramePrivatePtr spFrame = GetIFramePrivate();
|
|
sc = ScCheckPointers(spFrame, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// First check if the number of columns inserted are same as the
|
|
// number that is persisted. If not remove the persisted data.
|
|
IHeaderCtrlPrivatePtr spHeader = spFrame;
|
|
sc = ScCheckPointers(spHeader, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
int cColumns = 0;
|
|
sc = spHeader->GetColumnCount(&cColumns);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// If the persisted columns and number of columns inserted
|
|
// do not match remove the persisted data.
|
|
if (pColInfoList->size() != cColumns)
|
|
{
|
|
pViewData->DeleteColumnData(guidSnapin, *pColID);
|
|
return sc;
|
|
}
|
|
|
|
// Set sorting column, order
|
|
CColumnSortList* pSortList = columnSetData.get_ColumnSortList();
|
|
|
|
if (pSortList && ( pSortList->size() > 0))
|
|
{
|
|
CColumnSortList::iterator itSortInfo = pSortList->begin();
|
|
|
|
// Restore the sort with saved column # and
|
|
// sort-options (User param is NULL as this
|
|
// is user initiated MMCN_COLUMN_CLICK)*/
|
|
RestoreSort(itSortInfo->getColumn(), itSortInfo->getSortOptions());
|
|
}
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::ScGetCurrentColumnData
|
|
*
|
|
* PURPOSE: collects current column data to collections passed as args
|
|
* [ initially code used to be in OnColumns method ]
|
|
*
|
|
* PARAMETERS:
|
|
* CColumnInfoList& columnInfoList
|
|
* TStringVector& strColNames
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::ScGetCurrentColumnData( CColumnInfoList& columnInfoList, TStringVector& strColNames)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScGetCurrentColumnData"));
|
|
columnInfoList.clear();
|
|
strColNames.clear();
|
|
|
|
IHeaderCtrlPrivatePtr spHeader = GetIFramePrivate();
|
|
sc = ScCheckPointers(spHeader, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = spHeader->GetColumnInfoList(&columnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
int cColumns = columnInfoList.size();
|
|
|
|
USES_CONVERSION;
|
|
|
|
for (int i = 0; i < cColumns; i++)
|
|
{
|
|
CCoTaskMemPtr<OLECHAR> spColumnText;
|
|
|
|
sc = spHeader->GetColumnText(i, &spColumnText);
|
|
if (sc)
|
|
return sc;
|
|
|
|
strColNames.push_back(OLE2T(spColumnText));
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::ScSetUpdatedColumnData
|
|
*
|
|
* PURPOSE: updates column by data specified in collections passed as args
|
|
* [ initially code used to be in OnColumns method ]
|
|
*
|
|
* PARAMETERS:
|
|
* CColumnInfoList& oldColumnInfoList - column data befor the change
|
|
* CColumnInfoList& newColumnInfoList - updated column data
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::ScSetUpdatedColumnData( CColumnInfoList& oldColumnInfoList, CColumnInfoList& newColumnInfoList)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScSetUpdatedColumnData"));
|
|
|
|
CColumnInfoList::iterator itColInfo1, itColInfo2;
|
|
|
|
// Check if there is any change in visible/hidden columns.
|
|
// If so send MMCN_COLUMNS_CHANGE notification
|
|
for (itColInfo1 = newColumnInfoList.begin(); itColInfo1 != newColumnInfoList.end(); ++itColInfo1)
|
|
{
|
|
// Get the same column from old list.
|
|
itColInfo2 = find_if(oldColumnInfoList.begin(), oldColumnInfoList.end(),
|
|
bind2nd( ColPosCompare(), itColInfo1->GetColIndex()) );
|
|
|
|
if (itColInfo2 == oldColumnInfoList.end())
|
|
return sc = E_UNEXPECTED;
|
|
|
|
// Compare the hidden flag.
|
|
if ( itColInfo2->IsColHidden() != itColInfo1->IsColHidden() )
|
|
{
|
|
// Send MMCN_COLUMNS_CHANGED notification
|
|
sc = OnColumnsChange(newColumnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
break; // done anyway
|
|
}
|
|
}
|
|
|
|
sc = ScSaveColumnInfoList(newColumnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IHeaderCtrlPrivatePtr spHeader = GetIFramePrivate();
|
|
sc = ScCheckPointers(spHeader, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = spHeader->ModifyColumns(newColumnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScRestoreSortFromPersistedData();
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: OnColumns
|
|
//
|
|
// Synopsis: Display Columns customization dialog and if necessary
|
|
// apply changes made by the user.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
void CNode::OnColumns()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::OnColumns"));
|
|
|
|
// first - get the columns
|
|
CColumnInfoList columnInfoList;
|
|
TStringVector strColNames;
|
|
|
|
// 1. get the current data
|
|
sc = ScGetCurrentColumnData( columnInfoList, strColNames );
|
|
if (sc)
|
|
return;
|
|
|
|
// 2. Cache the column data.
|
|
CColumnInfoList columnInfoListOld = columnInfoList;
|
|
|
|
// 3. get the default column settings.
|
|
CViewData *pViewData = GetViewData();
|
|
IHeaderCtrlPrivatePtr spHeader = GetIFramePrivate();
|
|
sc = ScCheckPointers(pViewData, spHeader, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
CColumnInfoList defaultColumnInfoList;
|
|
sc = spHeader->GetDefaultColumnInfoList(defaultColumnInfoList);
|
|
if (sc)
|
|
return;
|
|
|
|
// 5. display the dialog
|
|
CColumnsDlg dlg(&columnInfoList, &strColNames, defaultColumnInfoList);
|
|
INT_PTR nRet = dlg.DoModal();
|
|
|
|
if (nRet == -1)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
return;
|
|
}
|
|
|
|
if (nRet == IDOK)
|
|
{
|
|
// update columns by modified data
|
|
sc = ScSetUpdatedColumnData( columnInfoListOld, columnInfoList );
|
|
if (sc)
|
|
return;
|
|
}
|
|
|
|
// If reset is true then throw away present persisted column data
|
|
// and apply the default settings.
|
|
if (nRet == IDC_RESTORE_DEFAULT_COLUMNS)
|
|
{
|
|
// To get CColumnSetData first get the column-id & snapin guid.
|
|
CLSID guidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = ScGetSnapinAndColumnDataID(guidSnapin, columnID);
|
|
if (sc)
|
|
return;
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return;
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
pViewData->DeleteColumnData(guidSnapin, *pColID);
|
|
|
|
sc = spHeader->ModifyColumns(defaultColumnInfoList);
|
|
if (sc)
|
|
return;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::ScShowColumn
|
|
*
|
|
* PURPOSE: shows/hides column. notifies snapin on action
|
|
*
|
|
* PARAMETERS:
|
|
* int iColIndex - index of column to change
|
|
* bool bVisible - show/hide flag
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::ScShowColumn(int iColIndex, bool bShow)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScShowColumn"));
|
|
|
|
// first - get the current column data
|
|
CColumnInfoList columnInfoList;
|
|
TStringVector strColNames;
|
|
|
|
sc = ScGetCurrentColumnData( columnInfoList, strColNames );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Save the column data.
|
|
CColumnInfoList columnInfoListOld = columnInfoList;
|
|
|
|
|
|
// find the column and change its status
|
|
CColumnInfoList::iterator itColInfo = find_if(columnInfoList.begin(), columnInfoList.end(),
|
|
bind2nd( ColPosCompare(), iColIndex) );
|
|
|
|
// check if we did find the column
|
|
if (itColInfo == columnInfoList.end())
|
|
return sc = E_INVALIDARG; // assume it's not a valid index
|
|
|
|
// now modify the column status acording to parameters
|
|
if (bShow)
|
|
{
|
|
itColInfo->SetColHidden(false);
|
|
// move column to the end
|
|
columnInfoList.splice(columnInfoList.end(), columnInfoList, itColInfo);
|
|
}
|
|
else
|
|
{
|
|
itColInfo->SetColHidden();
|
|
}
|
|
|
|
// update columns by modified data
|
|
sc = ScSetUpdatedColumnData( columnInfoListOld, columnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::ScGetSortColumn
|
|
*
|
|
* PURPOSE: return currently used sort column
|
|
*
|
|
* PARAMETERS:
|
|
* int *piSortCol - sort column index [retval]
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::ScGetSortColumn(int *piSortCol)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScGetSortColumn"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers(piSortCol);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// retrieve IResultDataPrivate interface
|
|
CComponent* pComponent = GetPrimaryComponent();
|
|
sc = ScCheckPointers(pComponent, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IResultDataPrivatePtr pResult = pComponent->GetIFramePrivate();
|
|
sc = ScCheckPointers(pResult, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// forward the call to IResultDataPrivate
|
|
sc = pResult->GetSortColumn(piSortCol);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::ScSetSortColumn
|
|
*
|
|
* PURPOSE: sorts result data by specified column
|
|
* [uses private result data interface to implement]
|
|
*
|
|
* PARAMETERS:
|
|
* int iSortCol - index of column to sort by
|
|
* bool bAscending - sorting order
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::ScSetSortColumn(int iSortCol, bool bAscending)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScSetSortColumn"));
|
|
|
|
// retrieve IResultDataPrivate interface
|
|
CComponent* pComponent = GetPrimaryComponent();
|
|
sc = ScCheckPointers(pComponent, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IResultDataPrivatePtr pResult = pComponent->GetIFramePrivate();
|
|
sc = ScCheckPointers(pResult, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
DWORD dwSortOptions = bAscending ? 0 : RSI_DESCENDING;
|
|
|
|
// forward the call to IResultDataPrivate
|
|
sc = pResult->InternalSort( iSortCol, dwSortOptions, NULL, FALSE );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// If sort went thru - save.
|
|
if (sc == SC(S_OK))
|
|
sc = ScSaveSortData(iSortCol, dwSortOptions);
|
|
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: OnColumnsChange
|
|
//
|
|
// Synopsis: Send MMCN_COLUMNS_CHANGE notification to snapin.
|
|
//
|
|
// Arguments: [colInfoList] - Columns data.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNode::OnColumnsChange(CColumnInfoList& colInfoList)
|
|
{
|
|
CComponent* pCC = m_pPrimaryComponent;
|
|
ASSERT(pCC != NULL);
|
|
|
|
// Get the data object for the node and pass it to the primary snap-in
|
|
// and all the namespace extensions to the node.
|
|
IDataObjectPtr spDataObject;
|
|
HRESULT hr = QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
int nVisibleColumns = 0;
|
|
|
|
// Count the number of columns that are visible.
|
|
CColumnInfoList::iterator itColInfo;
|
|
for (itColInfo = colInfoList.begin(); itColInfo != colInfoList.end();
|
|
++itColInfo)
|
|
{
|
|
if (! itColInfo->IsColHidden())
|
|
nVisibleColumns++;
|
|
}
|
|
|
|
int size = sizeof(MMC_VISIBLE_COLUMNS) + nVisibleColumns * sizeof(INT);
|
|
HGLOBAL hGlobal = ::GlobalAlloc(GPTR, size);
|
|
if (! hGlobal)
|
|
return E_OUTOFMEMORY;
|
|
|
|
MMC_VISIBLE_COLUMNS* pColData = reinterpret_cast<MMC_VISIBLE_COLUMNS*>(hGlobal);
|
|
pColData->nVisibleColumns = nVisibleColumns;
|
|
|
|
// Get the list of visible columns into MMC_VISIBLE_COLUMNS struct.
|
|
int i = 0;
|
|
for (itColInfo = colInfoList.begin(); itColInfo != colInfoList.end();
|
|
++itColInfo)
|
|
{
|
|
if (! itColInfo->IsColHidden())
|
|
pColData->rgVisibleCols[i++] = itColInfo->GetColIndex();
|
|
}
|
|
|
|
LPARAM lParam = reinterpret_cast<LPARAM>(pColData);
|
|
hr = pCC->Notify(spDataObject, MMCN_COLUMNS_CHANGED, 0, lParam);
|
|
|
|
::GlobalFree(hGlobal);
|
|
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: ScSaveColumnInfoList
|
|
//
|
|
// Synopsis: Save the column data in internal data structures.
|
|
//
|
|
// Arguments: [colInfoList] - Columns data.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScSaveColumnInfoList(CColumnInfoList& columnInfoList)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScSaveColumnInfoList"));
|
|
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CLSID clsidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = ScGetSnapinAndColumnDataID(clsidSnapin, columnID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = pViewData->ScSaveColumnInfoList(clsidSnapin, *pColID, columnInfoList);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: ScGetSnapinAndColumnDataID
|
|
//
|
|
// Synopsis: Returns the snapin guid & column-id in CXMLAutoBinary for this node.
|
|
//
|
|
// Arguments: [snapinGuid] - [out], snapin guid.
|
|
// [columnID] - [out], column-id in CXMLAutoBinary.
|
|
//
|
|
// Note: Pass in a CXMLAutoBinary object, will return column id in that object.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetSnapinAndColumnDataID(GUID& snapinGuid, CXMLAutoBinary& columnID)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::ScGetSnapinAndColumnDataID"));
|
|
|
|
// Get Snapin Guid
|
|
snapinGuid = GetPrimarySnapInCLSID();
|
|
|
|
columnID.ScFree(); // clear any data.
|
|
|
|
IDataObjectPtr spDataObject;
|
|
sc = QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
HGLOBAL hGlobal;
|
|
sc = ExtractColumnConfigID(spDataObject, hGlobal);
|
|
|
|
if (! sc.IsError())
|
|
{
|
|
int cbSize = GlobalSize(hGlobal);
|
|
if (0 == cbSize)
|
|
return sc.FromLastError();
|
|
|
|
columnID.Attach(hGlobal, cbSize);
|
|
}
|
|
else
|
|
{
|
|
// Let us use the NodeTypeGUID as the Column Data Identifier
|
|
CLSID clsidColID;
|
|
sc = GetNodeType(&clsidColID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
int cbSize = sizeof(SColumnSetID) + sizeof(CLSID) - 1;
|
|
sc = columnID.ScAlloc(cbSize, true);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
pColID->cBytes = sizeof(CLSID);
|
|
pColID->dwFlags = 0;
|
|
|
|
CopyMemory(pColID->id, (BYTE*)&clsidColID, pColID->cBytes);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* class CViewExtensionCallback
|
|
*
|
|
*
|
|
* PURPOSE: Implements IViewExtensionCallback
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
class CViewExtensionCallback :
|
|
public CComObjectRoot,
|
|
public IViewExtensionCallback
|
|
{
|
|
|
|
public:
|
|
typedef CViewExtensionCallback ThisClass;
|
|
|
|
BEGIN_COM_MAP(ThisClass)
|
|
COM_INTERFACE_ENTRY(IViewExtensionCallback)
|
|
END_COM_MAP()
|
|
|
|
DECLARE_NOT_AGGREGATABLE(ThisClass)
|
|
|
|
IMPLEMENTS_SNAPIN_NAME_FOR_DEBUG()
|
|
|
|
CViewExtensionCallback() : m_pItExt(NULL) {}
|
|
|
|
SC ScInitialize(CViewExtInsertIterator & itExt)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CViewExtensionCallback::ScInitialize"));
|
|
m_pItExt = &itExt;
|
|
return sc;
|
|
}
|
|
|
|
SC ScDeinitialize()
|
|
{
|
|
DECLARE_SC (sc, _T("CViewExtensionCallback::ScDeinitialize"));
|
|
m_pItExt = NULL;
|
|
return (sc);
|
|
}
|
|
|
|
|
|
public:
|
|
STDMETHODIMP AddView(PMMC_EXT_VIEW_DATA pExtViewData) {return ScAddView(pExtViewData).ToHr();}
|
|
|
|
private:
|
|
|
|
SC ScAddView(PMMC_EXT_VIEW_DATA pExtViewData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CViewExtensionCallback::ScAddView"));
|
|
|
|
sc = ScCheckPointers(pExtViewData, pExtViewData->pszURL, pExtViewData->pszViewTitle);
|
|
if(sc)
|
|
return sc; // TODO add snapin error
|
|
|
|
sc = ScCheckPointers(m_pItExt, E_UNEXPECTED);
|
|
if(sc)
|
|
return sc; // TODO add snapin error, e.g. "IExtendViewCallback::AddView called outside of IExtendView::GetViews"
|
|
|
|
/*
|
|
* prep the input to IConsoleView::ScAddViewExtension
|
|
*/
|
|
CViewExtensionData ved;
|
|
ved.strURL = pExtViewData->pszURL;
|
|
ved.strName = pExtViewData->pszViewTitle;
|
|
ved.viewID = pExtViewData->viewID;
|
|
ved.bReplacesDefaultView = pExtViewData->bReplacesDefaultView;
|
|
|
|
/*
|
|
* std::basic_string's can't assign from NULL, so we have to check first
|
|
*/
|
|
if (pExtViewData->pszTooltipText)
|
|
ved.strTooltip = pExtViewData->pszTooltipText;
|
|
|
|
/*
|
|
* validate output: URL and title are required, tooltip is optional
|
|
*/
|
|
if (ved.strURL.empty())
|
|
{
|
|
TraceSnapinError(TEXT("Invalid parameter to IViewExtensionCallback::AddView (empty URL)"), E_INVALIDARG);
|
|
return (sc = E_INVALIDARG);
|
|
}
|
|
|
|
if (ved.strName.empty())
|
|
{
|
|
TraceSnapinError(TEXT("Invalid parameter to IViewExtensionCallback::AddView (empty title)"), E_INVALIDARG);
|
|
return (sc = E_INVALIDARG);
|
|
}
|
|
|
|
/*
|
|
* add the extension to the view
|
|
*/
|
|
*(*m_pItExt)++ = ved;
|
|
|
|
return sc;
|
|
}
|
|
|
|
private:
|
|
CViewExtInsertIterator *m_pItExt;
|
|
|
|
};
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
* CNode::ScGetViewExtensions
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
SC CNode::ScGetViewExtensions (CViewExtInsertIterator itExt)
|
|
{
|
|
DECLARE_SC (sc, _T("CNode::ScGetViewExtensions"));
|
|
|
|
IDataObjectPtr spDataObject;
|
|
bool bScopeItem ;
|
|
sc = ScGetDataObject(/*bScopePane*/ true, NULL /*lResultItemCookie*/, bScopeItem, &spDataObject);
|
|
if(sc)
|
|
return sc;
|
|
|
|
CSnapIn* pSnapIn = GetPrimarySnapIn();
|
|
sc = ScCheckPointers (pSnapIn, E_FAIL);
|
|
if (sc)
|
|
return (sc);
|
|
|
|
CArray<GUID, GUID&> DynExtens;
|
|
ExtractDynExtensions(spDataObject, DynExtens);
|
|
|
|
GUID guidNodeType;
|
|
sc = ::ExtractObjectTypeGUID(spDataObject, &guidNodeType);
|
|
if(sc)
|
|
return sc;
|
|
|
|
CExtensionsIterator it;
|
|
sc = it.ScInitialize(pSnapIn, guidNodeType, g_szView, DynExtens.GetData(), DynExtens.GetSize());
|
|
if(sc)
|
|
return sc;
|
|
|
|
typedef CComObject<CViewExtensionCallback> t_ViewExtensionCallback;
|
|
|
|
t_ViewExtensionCallback *pViewExtensionCallback = NULL;
|
|
sc = t_ViewExtensionCallback::CreateInstance(&pViewExtensionCallback);
|
|
if(sc)
|
|
return sc;
|
|
|
|
if(NULL == pViewExtensionCallback)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
sc = pViewExtensionCallback->ScInitialize(itExt);
|
|
if(sc)
|
|
return sc;
|
|
|
|
IViewExtensionCallbackPtr spViewExtensionCallback = pViewExtensionCallback;
|
|
|
|
// add all the console taskpads first
|
|
sc = CConsoleTaskpadViewExtension::ScGetViews(this, spViewExtensionCallback);
|
|
if(sc)
|
|
return sc;
|
|
|
|
for (; !it.IsEnd(); it.Advance())
|
|
{
|
|
// any errors in this block should just go on to the next snap-in. Can't let one snap-in
|
|
// hose all the others.
|
|
|
|
/*
|
|
* create the extension
|
|
*/
|
|
IExtendViewPtr spExtendView;
|
|
sc = spExtendView.CreateInstance(it.GetCLSID(), NULL, MMC_CLSCTX_INPROC);
|
|
if(sc)
|
|
{
|
|
#ifdef DBG
|
|
USES_CONVERSION;
|
|
tstring strMsg = _T("Failed to create snapin ");
|
|
CCoTaskMemPtr<WCHAR> spszCLSID;
|
|
if (SUCCEEDED (StringFromCLSID (it.GetCLSID(), &spszCLSID)))
|
|
strMsg += W2T(spszCLSID);
|
|
TraceSnapinError(strMsg.data(), sc);
|
|
#endif
|
|
sc.Clear();
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* get the view extension data from the extension
|
|
*/
|
|
sc = spExtendView->GetViews(spDataObject, spViewExtensionCallback);
|
|
if(sc)
|
|
{
|
|
TraceSnapinError(TEXT("Snapin returned error on call to IExtendView::GetView"), sc);
|
|
sc.Clear();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* View extensions aren't supposed to hold onto IExtendViewCallback,
|
|
* but buggy view extensions might. This will neuter the callback
|
|
* so buggy view extensions won't reference stale data.
|
|
*/
|
|
sc = pViewExtensionCallback->ScDeinitialize();
|
|
if (sc)
|
|
return (sc);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
/*******************************************************\
|
|
| helper function to avoid too many stack allocations
|
|
\*******************************************************/
|
|
static std::wstring T2W_ForLoop(const tstring& str)
|
|
{
|
|
#if defined(_UNICODE)
|
|
return str;
|
|
#else
|
|
USES_CONVERSION;
|
|
return A2CW(str.c_str());
|
|
#endif
|
|
}
|
|
|
|
/***************************************************************************\
|
|
|
|
|
| Implementation of subclass CNode::CDataObjectCleanup
|
|
| Responsible for data object clenup
|
|
|
|
|
| Cleanup works by these rules:
|
|
|
|
|
| 1. Data object created for cut , copy or dragdrop registers every node added to it
|
|
| 2. Nodes are registered in the static multimap, mapping node to the data object it belongs to.
|
|
| 3. Node destructor checks the map and triggers cleanup for all affected data objects.
|
|
| 4. Data Object cleanup is: a) unregistering its nodes,
|
|
| b) release contained data objects
|
|
| b) entering invalid state (allowing only removal of cut objects to succeed)
|
|
| c) revoking itself from clipboard if it is on the clipboard.
|
|
| It will not do any of following: a) release references to IComponents as long as is alive
|
|
| b) prevent MMCN_CUTORMOVE to be send by invoking RemoveCutItems()
|
|
|
|
|
\***************************************************************************/
|
|
|
|
|
|
// declare static variable
|
|
CNode::CDataObjectCleanup::CMapOfNodes CNode::CDataObjectCleanup::s_mapOfNodes;
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::CDataObjectCleanup::ScRegisterNode
|
|
*
|
|
* PURPOSE: registers node to trigger clipboard clenup on destructor
|
|
*
|
|
* PARAMETERS:
|
|
* CNode *pNode [in] - node to register
|
|
* CMMCClipBoardDataObject *pObject [in] - data object to remove from clipboard
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::CDataObjectCleanup::ScRegisterNode(CNode *pNode, CMMCClipBoardDataObject *pObject)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::CClipboardClenup::ScRegisterNode"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers( pNode, pObject );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// add to the multimap
|
|
s_mapOfNodes.insert( CMapOfNodes::value_type( pNode, pObject ) );
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::CDataObjectCleanup::ScUnadviseDataObject
|
|
*
|
|
* PURPOSE: Removes nodes-'clenup triggers' kept for the object
|
|
*
|
|
* PARAMETERS:
|
|
* CMMCClipBoardDataObject *pObject [in] object going away
|
|
* bool bForceDataObjectCleanup [in] whether need to ask DO to clenup / unregister itself
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::CDataObjectCleanup::ScUnadviseDataObject(CMMCClipBoardDataObject *pObject, bool bForceDataObjectCleanup /*= true*/)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::CDataObjectCleanup::ScUnadviseDataObject"));
|
|
|
|
// remove all nodes associated with the data object
|
|
CMapOfNodes::iterator it = s_mapOfNodes.begin();
|
|
while ( it != s_mapOfNodes.end() )
|
|
{
|
|
// remove or skip the entry
|
|
if ( it->second == pObject )
|
|
it = s_mapOfNodes.erase( it );
|
|
else
|
|
++it;
|
|
}
|
|
|
|
// invalidate data object when required
|
|
if ( bForceDataObjectCleanup )
|
|
{
|
|
sc = pObject->ScInvalidate();
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNode::CDataObjectCleanup::ScUnadviseNode
|
|
*
|
|
* PURPOSE: Does data object claenup triggered by the node
|
|
*
|
|
* PARAMETERS:
|
|
* CNode *pNode [in] - node initiating cleanup
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
SC CNode::CDataObjectCleanup::ScUnadviseNode(CNode *pNode)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNode::CClipboardClenup::ScUnadviseNode"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// find the node in the map
|
|
CMapOfNodes::iterator it;
|
|
while ( s_mapOfNodes.end() != ( it = s_mapOfNodes.find(pNode) ) )
|
|
{
|
|
// one node triggers clenup for whole data object
|
|
sc = ScUnadviseDataObject( it->second );
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CSnapInNode
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapInNode);
|
|
|
|
CSnapInNode::CSnapInNode(
|
|
CMTSnapInNode* pMTNode,
|
|
CViewData* pViewData,
|
|
bool fRootNode)
|
|
: CNode(pMTNode, pViewData, fRootNode, true)
|
|
{
|
|
m_spData.CreateInstance();
|
|
|
|
ASSERT(pMTNode != NULL);
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapInNode);
|
|
|
|
pMTNode->AddNode(this);
|
|
}
|
|
|
|
CSnapInNode::CSnapInNode(const CSnapInNode& other) :
|
|
CNode (other),
|
|
m_spData (other.m_spData)
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapInNode);
|
|
}
|
|
|
|
void CSnapInNode::Reset()
|
|
{
|
|
m_spData->Reset();
|
|
ResetFlags();
|
|
CNode::Reset();
|
|
}
|
|
|
|
CSnapInNode::~CSnapInNode()
|
|
{
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapInNode);
|
|
|
|
CMTSnapInNode* pMTSINode = dynamic_cast<CMTSnapInNode*>(GetMTNode());
|
|
ASSERT(pMTSINode != NULL);
|
|
|
|
if (pMTSINode)
|
|
pMTSINode->RemoveNode(this);
|
|
}
|
|
|
|
void CSnapInNode::AddComponentToArray(CComponent* pCC)
|
|
{
|
|
ASSERT((pCC->GetComponentID() >= GetComponentArray().size()) ||
|
|
(GetComponentArray().size() > 0) &&
|
|
(GetComponentArray()[pCC->GetComponentID()] == NULL));
|
|
|
|
if (pCC->GetComponentID() >= GetComponentArray().size())
|
|
GetComponentArray().resize(pCC->GetComponentID() + 1);
|
|
|
|
GetComponentArray()[pCC->GetComponentID()] = pCC;
|
|
}
|
|
|
|
CComponent* CSnapInNode::CreateComponent(CSnapIn* pSnapIn, int nID)
|
|
{
|
|
ASSERT(pSnapIn != NULL);
|
|
|
|
CComponent* pCC = new CComponent(pSnapIn);
|
|
if ( pCC != NULL )
|
|
{
|
|
pCC->SetComponentID(nID);
|
|
AddComponentToArray(pCC);
|
|
}
|
|
return pCC;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSnapInNode::GetResultImage
|
|
//
|
|
// Synopsis: Get the image-index in result-image list for this node.
|
|
//
|
|
// Note: The CSnapInNode member ImageListPrivate is not set all
|
|
// the time (if the window is rooted at snapin node), so
|
|
// set it temporarily when we need the icon index.
|
|
// The member is set while adding sub-folders
|
|
// The only other case this will affect is when called for
|
|
// the image index for static snapin nodes displayed in result-pane.
|
|
// But when static snapin nodes are displayed in result-pane the
|
|
// AddSubFolders added it so the imagelist is already set.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Image index for this item in result-pane.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
UINT CSnapInNode::GetResultImage()
|
|
{
|
|
IImageListPrivate *pImageList = GetImageList();
|
|
|
|
if (!pImageList)
|
|
{
|
|
CComponent *pCC = GetPrimaryComponent();
|
|
if (pCC)
|
|
pImageList = pCC->GetIImageListPrivate();
|
|
}
|
|
|
|
CMTSnapInNode* pMTSnapInNode = dynamic_cast<CMTSnapInNode*>(GetMTNode());
|
|
|
|
if (pMTSnapInNode)
|
|
return pMTSnapInNode->GetResultImage ((CNode*)this, pImageList);
|
|
|
|
return CNode::GetResultImage();
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CSnapInNode::GetControl
|
|
*
|
|
* PURPOSE: Given the CLSID of the OCX, see if we have stored this
|
|
* OCX, if so return the OCXWrapper's IUnknown ptr.
|
|
*
|
|
* PARAMETERS:
|
|
* CLSID clsid: class-id of the OCX.
|
|
*
|
|
* RETURNS:
|
|
* LPUNKNOWN of wrapper OCX.
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
LPUNKNOWN CSnapInNode::GetControl(CLSID& clsid)
|
|
{
|
|
for (int i=0; i <= GetOCXArray().GetUpperBound(); i++)
|
|
{
|
|
if (GetOCXArray()[i].IsControlCLSID(clsid) == TRUE)
|
|
return GetOCXArray()[i].GetControlUnknown();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CSnapInNode::SetControl
|
|
*
|
|
* PURPOSE: Given the CLSID of the OCX and of the wrapper.
|
|
*
|
|
* PARAMETERS:
|
|
* CLSID clsid : of a OCX.
|
|
* IUnknown *pUnknown: of OCX wrapper.
|
|
*
|
|
* RETURNS:
|
|
* void
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
void CSnapInNode::SetControl(CLSID& clsid, IUnknown* pUnknown)
|
|
{
|
|
// check for slot in cache
|
|
int iLast = GetOCXArray().GetUpperBound();
|
|
for (int i=0; i <= iLast; i++)
|
|
{
|
|
if (GetOCXArray()[i].IsControlCLSID(clsid) == TRUE)
|
|
break;
|
|
}
|
|
|
|
// if not in cache, add one more entry
|
|
if (i > iLast)
|
|
GetOCXArray().SetSize(i + 1);
|
|
|
|
GetOCXArray()[i].SetControl(clsid, pUnknown);
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CSnapInNode::GetControl
|
|
*
|
|
* PURPOSE: Given the IUnknown of the OCX, see if we have stored this
|
|
* OCX, if so return the OCXWrapper's IUnknown ptr.
|
|
*
|
|
* PARAMETERS:
|
|
* IUnknown *pUnkOCX : of a OCX.
|
|
*
|
|
* RETURNS:
|
|
* LPUNKNOWN of wrapper OCX.
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
LPUNKNOWN CSnapInNode::GetControl(LPUNKNOWN pUnkOCX)
|
|
{
|
|
for (int i=0; i <= GetOCXArray().GetUpperBound(); i++)
|
|
{
|
|
// Compare IUnknowns.
|
|
if (GetOCXArray()[i].IsSameOCXIUnknowns(pUnkOCX) == TRUE)
|
|
return GetOCXArray()[i].GetControlUnknown();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CSnapInNode::SetControl
|
|
*
|
|
* PURPOSE: Given the IUnknown of the OCX and of the wrapper.
|
|
*
|
|
* PARAMETERS:
|
|
* IUnknown *pUnkOCX : of a OCX.
|
|
* IUnknown *pUnknown: of OCX wrapper.
|
|
*
|
|
* RETURNS:
|
|
* void
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
void CSnapInNode::SetControl(LPUNKNOWN pUnkOCX, IUnknown* pUnknown)
|
|
{
|
|
// check for slot in cache
|
|
int iLast = GetOCXArray().GetUpperBound();
|
|
for (int i=0; i <= iLast; i++)
|
|
{
|
|
if (GetOCXArray()[i].IsSameOCXIUnknowns(pUnkOCX) == TRUE)
|
|
break; // found the OCX, so replace with given OCXwrapper.
|
|
}
|
|
|
|
// if not in cache, add one more entry
|
|
if (i > iLast)
|
|
GetOCXArray().SetSize(i + 1);
|
|
|
|
GetOCXArray()[i].SetControl(pUnkOCX, pUnknown);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScGetConsoleTaskpad
|
|
//
|
|
// Synopsis: Get the console taskpad identified by given GUID for this node.
|
|
//
|
|
// Arguments: [guidTaskpad] - [in param]
|
|
// [ppTaskpad] - [out param]
|
|
//
|
|
// Returns: SC, S_FALSE if none exists
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetConsoleTaskpad (const GUID& guidTaskpad, CConsoleTaskpad **ppTaskpad)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScGetConsoleTaskpad"));
|
|
sc = ScCheckPointers(ppTaskpad);
|
|
if (sc)
|
|
return sc;
|
|
|
|
*ppTaskpad = NULL;
|
|
|
|
CScopeTree* pScopeTree = CScopeTree::GetScopeTree();
|
|
sc = ScCheckPointers(pScopeTree, E_UNEXPECTED);
|
|
if(sc)
|
|
return sc;
|
|
|
|
CConsoleTaskpadList *pConsoleTaskpadList = pScopeTree->GetConsoleTaskpadList();
|
|
sc = ScCheckPointers(pConsoleTaskpadList, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// get a filtered list of taskpads that apply to this node.
|
|
CConsoleTaskpadFilteredList filteredList;
|
|
|
|
sc = pConsoleTaskpadList->ScGetTaskpadList(this, filteredList);
|
|
if(sc)
|
|
return sc;
|
|
|
|
for(CConsoleTaskpadFilteredList::iterator iter = filteredList.begin(); iter!= filteredList.end(); ++iter)
|
|
{
|
|
CConsoleTaskpad *pTaskpad = *iter;
|
|
sc = ScCheckPointers(pTaskpad, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (pTaskpad->GetID() == guidTaskpad)
|
|
{
|
|
*ppTaskpad = pTaskpad;
|
|
return sc; // found
|
|
}
|
|
}
|
|
|
|
return (sc = S_FALSE); // not found
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* There is only one CViewSettingsPersistor object per document.
|
|
*
|
|
* The object stored as static variable inside CNode as CNode needs
|
|
* to access this object frequently.
|
|
*
|
|
* The Document needs to initialize/save the object by loading/savind
|
|
* from/to console file. It calls below ScQueryViewSettingsPersistor.
|
|
*
|
|
* The object is created with first call to ScQueryViewSettingsPersistor.
|
|
* The object is destroyed when DocumentClosed event is received.
|
|
*
|
|
*************************************************************************/
|
|
CComObject<CViewSettingsPersistor>* CNode::m_pViewSettingsPersistor = NULL;
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScQueryViewSettingsPersistor
|
|
//
|
|
// Synopsis: Static method to get IPersistStream to load CViewSettingsPersistor
|
|
// object from old style console file.
|
|
//
|
|
// If the CViewSettingsObject is not created then create one.
|
|
//
|
|
// Arguments: [ppStream] - [out]
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScQueryViewSettingsPersistor (IPersistStream **ppStream)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScQueryViewSettingsPersistor"));
|
|
sc = ScCheckPointers(ppStream);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Create new CViewSettingsPersistor if none exists
|
|
if (NULL == m_pViewSettingsPersistor)
|
|
{
|
|
sc = CComObject<CViewSettingsPersistor>::CreateInstance (&m_pViewSettingsPersistor);
|
|
if (sc)
|
|
goto ObjectCreationFailed;
|
|
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, E_UNEXPECTED);
|
|
if (sc)
|
|
goto ObjectCreationFailed;
|
|
|
|
m_pViewSettingsPersistor->AddRef();
|
|
}
|
|
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, E_UNEXPECTED);
|
|
if (sc)
|
|
goto ObjectCreationFailed;
|
|
|
|
*ppStream = static_cast<IPersistStream*>(m_pViewSettingsPersistor);
|
|
if (NULL == *ppStream)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
(*ppStream)->AddRef();
|
|
|
|
Cleanup:
|
|
return (sc);
|
|
|
|
ObjectCreationFailed:
|
|
CStr strMsg;
|
|
strMsg.LoadString(GetStringModule(), IDS_ViewSettingCouldNotBePersisted);
|
|
::MessageBox(NULL, strMsg, NULL, MB_OK|MB_SYSTEMMODAL);
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScQueryViewSettingsPersistor
|
|
//
|
|
// Synopsis: Static method to get CXMLObject to load or save
|
|
// CViewSettingsPersistor object from XML console file.
|
|
//
|
|
// If the CViewSettingsObject is not created then create one.
|
|
//
|
|
// Arguments: [ppXMLObject] - [out]
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScQueryViewSettingsPersistor (CXMLObject **ppXMLObject)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScQueryViewSettingsPersistor"));
|
|
sc = ScCheckPointers(ppXMLObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Create new CViewSettingsPersistor if none exists
|
|
if (NULL == m_pViewSettingsPersistor) // Create new one
|
|
{
|
|
sc = CComObject<CViewSettingsPersistor>::CreateInstance (&m_pViewSettingsPersistor);
|
|
if (sc)
|
|
goto ObjectCreationFailed;
|
|
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, E_UNEXPECTED);
|
|
if (sc)
|
|
goto ObjectCreationFailed;
|
|
|
|
m_pViewSettingsPersistor->AddRef();
|
|
}
|
|
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, E_UNEXPECTED);
|
|
if (sc)
|
|
goto ObjectCreationFailed;
|
|
|
|
*ppXMLObject = static_cast<CXMLObject*>(m_pViewSettingsPersistor);
|
|
if (NULL == *ppXMLObject)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
Cleanup:
|
|
return (sc);
|
|
|
|
ObjectCreationFailed:
|
|
CStr strMsg;
|
|
strMsg.LoadString(GetStringModule(), IDS_ViewSettingCouldNotBePersisted);
|
|
::MessageBox(NULL, strMsg, NULL, MB_OK|MB_SYSTEMMODAL);
|
|
goto Cleanup;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScDeleteViewSettings
|
|
//
|
|
// Synopsis: Delete the CViewSettings object for given view-id as the
|
|
// view is being closed.
|
|
//
|
|
// Arguments: [nViewID] -
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScDeleteViewSettings (int nViewID)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScDeleteViewSettings"));
|
|
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScDeleteDataOfView(nViewID);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScOnDocumentClosing
|
|
//
|
|
// Synopsis: The document is closing, destroy any document related
|
|
// objects like CViewSettingsPersistor.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScOnDocumentClosing ()
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScOnDocumentClosing"));
|
|
|
|
if (m_pViewSettingsPersistor)
|
|
{
|
|
m_pViewSettingsPersistor->Release();
|
|
m_pViewSettingsPersistor = NULL;
|
|
}
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScSetFavoriteViewSettings
|
|
//
|
|
// Synopsis: A favorite is selected and it sets viewsettings
|
|
// before re-selecting the node so that after re-selection
|
|
// the new settings are set for the view.
|
|
//
|
|
// Arguments: [nViewID] -
|
|
// [bookmark] -
|
|
// [viewSettings] -
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScSetFavoriteViewSettings (int nViewID, const CBookmark& bookmark,
|
|
const CViewSettings& viewSettings)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScSetFavoriteViewSettings"));
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScSetFavoriteViewSettings (nViewID, bookmark, viewSettings);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScGetViewMode
|
|
//
|
|
// Synopsis: Get the viewmode if any persisted for this node.
|
|
//
|
|
// Arguments: [ulViewMode] - [out]
|
|
//
|
|
// Returns: SC, S_FALSE if none persisted.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetViewMode (ULONG& ulViewMode)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScGetViewMode"));
|
|
|
|
CMTNode *pMTNode = GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CBookmark *pBookmark = pMTNode->GetBookmark();
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, pBookmark, pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScGetViewMode (pViewData->GetViewID(),
|
|
*pBookmark,
|
|
ulViewMode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScSetViewMode
|
|
//
|
|
// Synopsis: Set the viewmode in persisted viewsettings.
|
|
//
|
|
// Arguments: [ulViewMode] - [in]
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScSetViewMode (ULONG ulViewMode)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScSetViewMode"));
|
|
|
|
CMTNode *pMTNode = GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CBookmark *pBookmark = pMTNode->GetBookmark();
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, pBookmark, pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScSetViewMode (pViewData->GetViewID(),
|
|
*pBookmark,
|
|
ulViewMode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScGetResultViewType
|
|
//
|
|
// Synopsis: Get the CResultViewType if any persisted for this node.
|
|
//
|
|
// Arguments: [rvt] - [out]
|
|
//
|
|
// Returns: SC, S_FALSE if none persisted.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetResultViewType (CResultViewType& rvt)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScGetResultViewType"));
|
|
|
|
CMTNode *pMTNode = GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CBookmark *pBookmark = pMTNode->GetBookmark();
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, pBookmark, pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScGetResultViewType (pViewData->GetViewID(),
|
|
*pBookmark,
|
|
rvt);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScSetResultViewType
|
|
//
|
|
// Synopsis: Set the CResultViewType in persisted viewsettings.
|
|
//
|
|
// Arguments: [rvt] - [in]
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScSetResultViewType (const CResultViewType& rvt)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScSetResultViewType"));
|
|
|
|
CMTNode *pMTNode = GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CBookmark *pBookmark = pMTNode->GetBookmark();
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, pBookmark, pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScSetResultViewType (pViewData->GetViewID(),
|
|
*pBookmark,
|
|
rvt);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScGetTaskpadID
|
|
//
|
|
// Synopsis: Get the taskpad-id if any persisted for this node.
|
|
// First see if there are any node-specific taskpad-id
|
|
// else get the node-type-specific setting if one exists.
|
|
//
|
|
// Arguments: [rvt] - [out]
|
|
//
|
|
// Returns: SC, S_FALSE if none persisted.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScGetTaskpadID (GUID& guidTaskpad)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScGetTaskpadID"));
|
|
|
|
CMTNode *pMTNode = GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CViewData *pViewData = GetViewData();
|
|
CBookmark *pBookmark = pMTNode->GetBookmark();
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, pViewData, pBookmark, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// 1. Try to get node-specific taskpad-id
|
|
sc = m_pViewSettingsPersistor->ScGetTaskpadID (pViewData->GetViewID(),
|
|
*pBookmark,
|
|
guidTaskpad);
|
|
if (sc == S_OK)
|
|
return sc;
|
|
|
|
// 2. Try to get nodetype specific taskpad-id.
|
|
GUID guidNodeType;
|
|
sc = pMTNode->GetNodeType(&guidNodeType);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScGetTaskpadID(pViewData->GetViewID(),
|
|
guidNodeType,
|
|
guidTaskpad);
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNode::ScSetTaskpadID
|
|
//
|
|
// Synopsis: Set the taskpad-id in persisted viewsettings. Also see if
|
|
// the taskpad is node-specific or nodetype-specific and persist
|
|
// accordingly.
|
|
//
|
|
// Arguments: [guidTaskpad] - [in]
|
|
// [bSetDirty] - [in], set the console file dirty.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNode::ScSetTaskpadID (const GUID& guidTaskpad, bool bSetDirty)
|
|
{
|
|
DECLARE_SC(sc, _T("CNode::ScSetTaskpadID"));
|
|
|
|
CMTNode *pMTNode = GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CViewData *pViewData = GetViewData();
|
|
sc = ScCheckPointers(m_pViewSettingsPersistor, pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Need to know if this task-pad is nodespecific or not.
|
|
bool bNodeSpecific = false;
|
|
CConsoleTaskpad *pTaskpad = NULL;
|
|
sc = ScGetConsoleTaskpad (guidTaskpad, &pTaskpad);
|
|
|
|
if (sc == S_OK) // S_OK if taskpad exists
|
|
{
|
|
sc = ScCheckPointers(pTaskpad, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
bNodeSpecific = pTaskpad->IsNodeSpecific();
|
|
}
|
|
// else it may be viewextension or normal view (which are nodetype-specific).
|
|
|
|
CBookmark *pBookmark = pMTNode->GetBookmark();
|
|
sc = ScCheckPointers(pBookmark, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (bNodeSpecific)
|
|
{
|
|
// Per node taskpad
|
|
sc = m_pViewSettingsPersistor->ScSetTaskpadID (pViewData->GetViewID(),
|
|
*pBookmark,
|
|
guidTaskpad,
|
|
bSetDirty);
|
|
}
|
|
else
|
|
{
|
|
// Per nodetype taskpad.
|
|
GUID guidNodeType;
|
|
sc = pMTNode->GetNodeType(&guidNodeType);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = m_pViewSettingsPersistor->ScSetTaskpadID(pViewData->GetViewID(),
|
|
guidNodeType,
|
|
*pBookmark,
|
|
guidTaskpad,
|
|
bSetDirty);
|
|
}
|
|
|
|
if (sc)
|
|
return sc;
|
|
|
|
return (sc);
|
|
}
|
|
|