windows-nt/Source/XPSP1/NT/admin/activec/nodemgr/ctrlbar.cpp
2020-09-26 16:20:57 +08:00

1394 lines
37 KiB
C++

//____________________________________________________________________________
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: ctrlbar.cpp
//
// Contents:
//
// Classes:
//
// Functions:
//
// History:
//____________________________________________________________________________
//
#include "stdafx.h"
#include "menubtn.h"
#include "viewdata.h"
#include "amcmsgid.h"
#include "regutil.h"
#include "commctrl.h"
#include "multisel.h"
#include "rsltitem.h"
#include "conview.h"
#include "util.h"
#include "nodemgrdebug.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Snapin name needed for debug information.
inline void Debug_SetControlbarSnapinName(const CLSID& clsidSnapin, CControlbar* pControlbar)
{
#ifdef DBG
tstring tszSnapinName;
bool bRet = GetSnapinNameFromCLSID(clsidSnapin, tszSnapinName);
if (bRet)
pControlbar->SetSnapinName(tszSnapinName.data());
#endif
}
//////////////////////////////////////////////////////////////////////////////
// IControlbar implementation
DEBUG_DECLARE_INSTANCE_COUNTER(CControlbar);
CControlbar::CControlbar()
: m_pCache(NULL)
{
TRACE(_T("CControlbar::CControlbar()\n"));
DEBUG_INCREMENT_INSTANCE_COUNTER(CControlbar);
m_pMenuButton=NULL;
m_ToolbarsList.clear();
#ifdef DBG
dbg_cRef = 0;
#endif
}
CControlbar::~CControlbar()
{
DECLARE_SC(sc, _T("CControlbar::~CControlbar"));
DEBUG_DECREMENT_INSTANCE_COUNTER(CControlbar);
// Remove the toolbars & menubuttons references.
sc = ScCleanup();
// sc dtor will trace error if there is one.
// release reference prior to m_ToolbarsList destruction
// The destructor of CToolbar will try to remove itself from the list!
m_spExtendControlbar = NULL;
}
//+-------------------------------------------------------------------
//
// Member: Create
//
// Synopsis: Create a toolbar or menubutton object
//
// Arguments:
// [nType] - Type of object to be created (Toolbar or Menubutton).
// [pExtendControlbar] - IExtendControlbar associated with this IControlbar.
// [ppUnknown] - IUnknown* of the object created.
//
// Returns: HR
//
//--------------------------------------------------------------------
STDMETHODIMP CControlbar::Create(MMC_CONTROL_TYPE nType,
LPEXTENDCONTROLBAR pExtendControlbar,
LPUNKNOWN* ppUnknown)
{
DECLARE_SC_FOR_PUBLIC_INTERFACE(sc, _T("IControlbar::Create"));
if (ppUnknown == NULL || pExtendControlbar == NULL)
{
sc = E_INVALIDARG;
TraceSnapinError(_T("Invalid Arguments"), sc);
return sc.ToHr();
}
*ppUnknown = NULL;
switch (nType)
{
case TOOLBAR:
sc = ScCreateToolbar(pExtendControlbar, ppUnknown);
break;
case MENUBUTTON:
sc = ScCreateMenuButton(pExtendControlbar, ppUnknown);
break;
default:
sc = E_NOTIMPL;
break;
}
if (sc)
return sc.ToHr();
return (sc.ToHr());
}
HRESULT CControlbar::ControlbarNotify(MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
{
ASSERT(m_spExtendControlbar != NULL);
if (m_spExtendControlbar == NULL)
return E_FAIL;
HRESULT hr;
// Deactivate if theming (fusion or V6 common-control) context before calling snapins.
ULONG_PTR ulpCookie;
if (! MmcDownlevelActivateActCtx(NULL, &ulpCookie))
return E_FAIL;
__try
{
hr = m_spExtendControlbar->ControlbarNotify(event, arg, param);
MmcDownlevelDeactivateActCtx(0, ulpCookie);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
hr = E_FAIL;
TraceSnapinException(m_clsidSnapin, TEXT("IExtendControlbar::ControlbarNotify"), event);
MmcDownlevelDeactivateActCtx(0, ulpCookie);
}
return hr;
}
//+-------------------------------------------------------------------
//
// Member: Attach
//
// Synopsis: Attach given toolbar or menubutton object
//
// Arguments:
// [nType] - Toolbar or Menubutton.
// [lpUnknown] - IUnknown* of the object to be attached.
//
// Returns: HR
//
//--------------------------------------------------------------------
STDMETHODIMP CControlbar::Attach(MMC_CONTROL_TYPE nType, LPUNKNOWN lpUnknown)
{
DECLARE_SC_FOR_PUBLIC_INTERFACE(sc, _T("IControlbar::Attach"));
if (lpUnknown == NULL)
{
sc = E_INVALIDARG;
TraceSnapinError(_T("Invalid Arguments"), sc);
return sc.ToHr();
}
switch (nType)
{
case TOOLBAR:
sc = ScAttachToolbar(lpUnknown);
break;
case MENUBUTTON:
sc = ScAttachMenuButtons(lpUnknown);
break;
case COMBOBOXBAR:
sc = E_NOTIMPL;
break;
}
if (sc)
return sc.ToHr();
return (sc.ToHr());
}
//+-------------------------------------------------------------------
//
// Member: Detach
//
// Synopsis: Detach given toolbar or menubutton object
//
// Arguments: [lpUnknown] - IUnknown* of the object to be detached
//
// Returns: HR
//
//--------------------------------------------------------------------
STDMETHODIMP CControlbar::Detach(LPUNKNOWN lpUnknown)
{
DECLARE_SC_FOR_PUBLIC_INTERFACE(sc, _T("IControlbar::Detach"));
if (lpUnknown == NULL)
{
sc = E_INVALIDARG;
TraceSnapinError(_T("Invalid Arguments"), sc);
return sc.ToHr();
}
// Is it a toolbar
IToolbarPtr spToolbar = lpUnknown;
if (spToolbar != NULL)
{
sc = ScDetachToolbar(spToolbar);
return sc.ToHr();
}
// Is it a menu button
IMenuButtonPtr spMenuButton = lpUnknown;
if (spMenuButton != NULL)
{
sc = ScDetachMenuButton(spMenuButton);
return sc.ToHr();
}
// The passed lpUnknown is neither toolbar nor menubutton.
// The Snapin has passed invalid object.
sc = E_INVALIDARG;
TraceSnapinError(_T("lpUnknown passed is neither toolbar nor menubutton"), sc);
return sc.ToHr();
}
//+-------------------------------------------------------------------
//
// Member: ScDetachToolbar
//
// Synopsis: Detach given toolbar object
//
// Arguments: [lpToolbar] - IToolbar* of the object to be detached
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScDetachToolbar(LPTOOLBAR lpToolbar)
{
DECLARE_SC(sc, _T("CControlbar::SCDetachToolbar"));
if (NULL == lpToolbar)
return (sc = E_UNEXPECTED);
// Get the CToolbar object.
CToolbar* pToolbar = dynamic_cast<CToolbar*>(lpToolbar);
if (NULL == pToolbar)
return (sc = E_UNEXPECTED);
// Get the CMMCToolbarIntf interface.
CMMCToolbarIntf* pToolbarIntf = pToolbar->GetMMCToolbarIntf();
if (NULL == pToolbarIntf)
return (sc = E_UNEXPECTED);
// Detach the toolbar from UI.
sc = pToolbarIntf->ScDetach(pToolbar);
if (sc)
return sc;
// Remove the CControlbar reference.
pToolbar->SetControlbar(NULL);
// Remove the reference to the toolbar.
m_ToolbarsList.remove(pToolbar);
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScDetachMenuButton
//
// Synopsis: Detach given toolbar or menubutton object
//
// Arguments: [lpUnknown] - IUnknown* of the object to be detached
//
// Returns: HR
//
//--------------------------------------------------------------------
SC CControlbar::ScDetachMenuButton(LPMENUBUTTON lpMenuButton)
{
DECLARE_SC(sc, _T("CControlbar::ScDetachMenuButton"));
if (NULL == lpMenuButton)
return (sc = E_UNEXPECTED);
CMenuButton* pMenuButton = dynamic_cast<CMenuButton*>(lpMenuButton);
if (NULL == pMenuButton)
return (sc = E_UNEXPECTED);
sc = pMenuButton->ScDetach();
if (sc)
return sc;
// If this is same as the cached menubutton object
// then remove the (cached) ref.
if (m_pMenuButton == pMenuButton)
m_pMenuButton = NULL;
else
{
// The IControlbar implementation is supposed to
// have only one CMenuButton obj. How come it is
// not same as one we have cached.
sc = E_UNEXPECTED;
}
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScCreateToolbar
//
// Synopsis: Create a toolbar for the given snapin (IExtendControlbar).
//
// Arguments: [pExtendControlbar] - IExtendControlbar of the snapin.
// [ppUnknown] - IUnknown* (IToolbar) of created toolbar.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScCreateToolbar(LPEXTENDCONTROLBAR pExtendControlbar,
LPUNKNOWN* ppUnknown)
{
DECLARE_SC(sc, _T("CControlbar::ScCreateToolbar"));
if ( (NULL == pExtendControlbar) ||
(NULL == ppUnknown) )
return (sc = E_INVALIDARG);
ASSERT(m_spExtendControlbar == NULL ||
m_spExtendControlbar == pExtendControlbar);
// Create the new CToolbar object.
CComObject<CToolbar>* pToolbar = NULL;
sc = CComObject<CToolbar>::CreateInstance(&pToolbar);
if (sc)
return sc;
if (NULL == pToolbar)
return (sc = E_FAIL);
sc = pToolbar->QueryInterface(IID_IToolbar,
reinterpret_cast<void**>(ppUnknown));
if (sc)
return sc;
CMMCToolbarIntf* pToolbarIntf = NULL;
// Get the toolbars mgr.
CAMCViewToolbarsMgr* pAMCViewToolbarsMgr = GetAMCViewToolbarsMgr();
if (NULL == pAMCViewToolbarsMgr)
{
sc = E_UNEXPECTED;
goto ToolbarUICreateError;
}
// Ask it to create the toolbar UI.
sc = pAMCViewToolbarsMgr->ScCreateToolBar(&pToolbarIntf);
if (sc)
goto ToolbarUICreateError;
// Let the IToolbar imp be aware of toolbar UI interface.
pToolbar->SetMMCToolbarIntf(pToolbarIntf);
Cleanup:
return(sc);
ToolbarUICreateError:
// Destroy the CToolbar object created.
if (*ppUnknown)
(*ppUnknown)->Release();
*ppUnknown = NULL;
goto Cleanup;
}
//+-------------------------------------------------------------------
//
// Member: ScCreateMenuButton
//
// Synopsis: Create a menu button object.
//
// Arguments: [pExtendControlbar] - IExtendControlbar of the snapin
// that is creating MenuButton object.
// [ppUnknown] - IUnknown if MenuButton object.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScCreateMenuButton(LPEXTENDCONTROLBAR pExtendControlbar,
LPUNKNOWN* ppUnknown)
{
DECLARE_SC(sc, _T("CControlbar::ScCreateMenuButton"));
if ( (NULL == pExtendControlbar) ||
(NULL == ppUnknown) )
return (sc = E_INVALIDARG);
ASSERT(m_spExtendControlbar == NULL ||
m_spExtendControlbar == pExtendControlbar);
// Create the new IMenuButton object
CComObject<CMenuButton>* pMenuButton;
sc = CComObject<CMenuButton>::CreateInstance(&pMenuButton);
if (sc)
return sc;
if (NULL == pMenuButton)
return (sc = E_FAIL);
sc = pMenuButton->QueryInterface(IID_IMenuButton,
reinterpret_cast<void**>(ppUnknown));
if (sc)
return sc;
pMenuButton->SetControlbar(this);
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScNotifySnapinOfToolBtnClick
//
// Synopsis: Notify the snapin about a tool button is click.
//
// Arguments: [hNode] - Node that owns result pane.
// [bScopePane] - Scope or Result.
// [lResultItemCookie] - If Result pane is selected the item param.
// [nID] - Command ID of the tool button clicked.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScNotifySnapinOfToolBtnClick(HNODE hNode, bool bScopePane,
LPARAM lResultItemCookie,
UINT nID)
{
DECLARE_SC(sc, _T("CControlbar::ScNotifySnapinOfToolBtnClick"));
LPDATAOBJECT pDataObject = NULL;
CNode* pNode = CNode::FromHandle(hNode);
if (NULL == pNode)
return (sc = E_UNEXPECTED);
bool bScopeItem = bScopePane;
// Get the data object of the currently selected item.
sc = pNode->ScGetDataObject(bScopePane, lResultItemCookie, bScopeItem, &pDataObject);
if (sc)
return sc;
ASSERT(m_spExtendControlbar != NULL);
// Notify the snapin
sc = ControlbarNotify(MMCN_BTN_CLICK, reinterpret_cast<LPARAM>(pDataObject),
static_cast<LPARAM>(nID));
// Release the dataobject if it is not special dataobject.
RELEASE_DATAOBJECT(pDataObject);
if (sc)
return sc;
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScNotifySnapinOfMenuBtnClick
//
// Synopsis: Notify the snapin about a menu button is click.
//
// Arguments: [hNode] - Node that owns result pane.
// [bScopePane] - Scope or Result.
// [lResultItemCookie] - If Result pane is selected the item param.
// [lpmenuButtonData] - MENUBUTTONDATA
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScNotifySnapinOfMenuBtnClick(HNODE hNode, bool bScopePane,
LPARAM lResultItemCookie,
LPMENUBUTTONDATA lpmenuButtonData)
{
DECLARE_SC(sc, _T("CControlbar::ScNotifySnapinOfMenuBtnClick"));
LPDATAOBJECT pDataObject = NULL;
CNode* pNode = CNode::FromHandle(hNode);
if (NULL == pNode)
return (sc = E_UNEXPECTED);
bool bScopeItem = bScopePane;
// Get the data object of the currently selected item.
sc = pNode->ScGetDataObject(bScopePane, lResultItemCookie, bScopeItem, &pDataObject);
if (sc)
return sc;
ASSERT(m_spExtendControlbar != NULL);
// Notify the snapin
sc = ControlbarNotify(MMCN_MENU_BTNCLICK, reinterpret_cast<LPARAM>(pDataObject),
reinterpret_cast<LPARAM>(lpmenuButtonData));
// Release the dataobject if it is not special dataobject.
RELEASE_DATAOBJECT(pDataObject);
if (sc)
return sc;
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScAttachToolbar
//
// Synopsis: Attach given toolbar object
//
// Arguments: [lpUnknown] - IUnknown* of the object to be attached
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScAttachToolbar(LPUNKNOWN lpUnknown)
{
DECLARE_SC(sc, _T("CControlbar::ScAttachToolbar"));
ASSERT(NULL != lpUnknown);
IToolbarPtr spToolbar = lpUnknown;
if (NULL == spToolbar)
return (sc = E_UNEXPECTED);
// Get the toolbar object (IToolbar implementation).
CToolbar* pToolbarC = dynamic_cast<CToolbar*>(spToolbar.GetInterfacePtr());
if (NULL == pToolbarC)
return (sc = E_UNEXPECTED);
// Get the toolbar UI interface.
CMMCToolbarIntf* pToolbarIntf = pToolbarC->GetMMCToolbarIntf();
if (NULL == pToolbarIntf)
return (sc = E_UNEXPECTED);
// Attach the toolbar.
sc = pToolbarIntf->ScAttach(pToolbarC);
if (sc)
return sc;
// Make the CToolbar aware of this IControlbar.
pToolbarC->SetControlbar(this);
// Add this CToolbar to our list of toolbars.
ToolbarsList::iterator itToolbar = std::find(m_ToolbarsList.begin(), m_ToolbarsList.end(), pToolbarC);
if (m_ToolbarsList.end() == itToolbar)
{
m_ToolbarsList.push_back(pToolbarC);
}
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScAttachMenuButtons
//
// Synopsis: Attach a menu button object.
//
// Arguments: [lpUnknown] - IUnknown if MenuButton object.
//
// Returns: HRESULT
//
// Note: Only one CMenuButton object per Controlbar/snapin.
// Snapins can create many menu buttons using a
// single CMenuButton object.
//--------------------------------------------------------------------
SC CControlbar::ScAttachMenuButtons(LPUNKNOWN lpUnknown)
{
DECLARE_SC(sc, _T("CControlbar::ScAttachMenuButtons"));
ASSERT(NULL != lpUnknown);
CMenuButton* pMenuButton = dynamic_cast<CMenuButton*>(lpUnknown);
if (pMenuButton == NULL)
return (sc = E_INVALIDARG);
if (m_pMenuButton == pMenuButton)
{
// Already attached.
sc = S_FALSE;
TraceNodeMgrLegacy(_T("The menubutton is already attached"), sc);
return sc;
}
else if (m_pMenuButton != NULL)
{
// There is already a CMenuButton object attached by this
// Controlbar (Snapin). Detach that before attaching this
// CMenuButton Object (See the note above).
sc = m_pMenuButton->ScDetach();
if (sc)
return sc;
}
// Cache the ref to CMenuButton object.
// Used when selection moves away from the snapin.
// MMC has to remove the menubutton put by this snapin.
m_pMenuButton = pMenuButton;
if (pMenuButton->GetControlbar() != this)
pMenuButton->SetControlbar(this);
sc = pMenuButton->ScAttach();
if (sc)
return sc;
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScCleanup
//
// Synopsis: Remove all the toolbars and menu buttons owned
// by this controlbar.
//
// Arguments: None
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScCleanup()
{
DECLARE_SC(sc, _T("CControlbar::ScCleanup"));
ASSERT(m_spExtendControlbar != NULL);
if (m_spExtendControlbar != NULL)
m_spExtendControlbar->SetControlbar(NULL);
sc = ScDetachToolbars();
if (sc)
return sc;
// If there is a menu button, detach (remove it
// from the UI).
if (m_pMenuButton)
{
sc = m_pMenuButton->ScDetach();
m_pMenuButton = NULL;
}
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScDetachToolbars
//
// Synopsis: Detach all the toolbars.
//
// Arguments: None.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScDetachToolbars()
{
DECLARE_SC(sc, _T("CControlbar::ScDetachToolbars"));
ToolbarsList::iterator itToolbar = m_ToolbarsList.begin();
while (itToolbar != m_ToolbarsList.end())
{
CToolbar* pToolbar = (*itToolbar);
if (NULL == pToolbar)
return (sc = E_UNEXPECTED);
CMMCToolbarIntf* pToolbarIntf = pToolbar->GetMMCToolbarIntf();
if (NULL == pToolbarIntf)
return (sc = E_UNEXPECTED);
// Detach the toolbar UI.
sc = pToolbarIntf->ScDetach(pToolbar);
if (sc)
return sc;
// Detach the controlbar from toolbar.
pToolbar->SetControlbar(NULL);
// Remove the toolbar reference from the list.
itToolbar = m_ToolbarsList.erase(itToolbar);
}
return (sc);
}
//+-------------------------------------------------------------------
//
// Member: ScShowToolbars
//
// Synopsis: Show/Hide all the toolbars.
//
// Arguments: [bool] - Show or Hide.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CControlbar::ScShowToolbars(bool bShow)
{
DECLARE_SC(sc, _T("CControlbar::ScShowToolbars"));
ToolbarsList::iterator itToolbar = m_ToolbarsList.begin();
for (; itToolbar != m_ToolbarsList.end(); ++itToolbar)
{
CToolbar* pToolbar = (*itToolbar);
if (NULL == pToolbar)
return (sc = E_UNEXPECTED);
CMMCToolbarIntf* pToolbarIntf = pToolbar->GetMMCToolbarIntf();
if (NULL == pToolbarIntf)
return (sc = E_UNEXPECTED);
sc = pToolbarIntf->ScShow(pToolbar, bShow);
if (sc)
return sc;
}
return sc;
}
CViewData* CControlbar::GetViewData()
{
ASSERT(m_pCache != NULL);
return m_pCache->GetViewData();
}
///////////////////////////////////////////////////////////////////////////
//
// CSelData implementation
//
DEBUG_DECLARE_INSTANCE_COUNTER(CSelData);
//+-------------------------------------------------------------------
//
// Member: ScReset
//
// Synopsis: Init all the data members.
//
// Arguments: None
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSelData::ScReset()
{
DECLARE_SC(sc, _T("CSelData::ScReset"));
if (m_pCtrlbarPrimary != NULL)
{
sc = ScDestroyPrimaryCtrlbar();
if (sc)
return sc;
}
sc = ScDestroyExtensionCtrlbars();
if (sc)
return sc;
m_bScopeSel = false;
m_bSelect = false;
m_pNodeScope = NULL;
m_pMS = NULL;
m_pCtrlbarPrimary = NULL;
m_lCookie = -1;
m_pCompPrimary = NULL;
m_spDataObject = NULL;
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScShowToolbars
//
// Synopsis: Show/Hide primary & extension toolbars.
//
// Arguments: [bool] - Show/Hide.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSelData::ScShowToolbars(bool bShow)
{
DECLARE_SC(sc, _T("CSelData::ScShowToolbars"));
if (m_pCtrlbarPrimary != NULL)
{
sc = m_pCtrlbarPrimary->ScShowToolbars(bShow);
if (sc)
return sc;
}
POSITION pos = m_listExtCBs.GetHeadPosition();
bool bReturn = true;
while (pos != NULL)
{
CControlbar* pControlbar = m_listExtCBs.GetNext(pos);
if (pControlbar)
{
sc = pControlbar->ScShowToolbars(bShow);
if (sc)
return sc;
}
}
return sc;
}
CControlbar* CSelData::GetControlbar(const CLSID& clsidSnapin)
{
POSITION pos = m_listExtCBs.GetHeadPosition();
while (pos)
{
CControlbar* pControlbar = m_listExtCBs.GetNext(pos);
if (pControlbar && pControlbar->IsSameSnapin(clsidSnapin) == TRUE)
return pControlbar;
}
return NULL;
}
//+-------------------------------------------------------------------
//
// Member: ScDestroyPrimaryCtrlbar
//
// Synopsis: Ask primary controlbar to release its toolbar/menubutton
// ref and cleanup our reference to the controlbar.
//
// Arguments: None
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSelData::ScDestroyPrimaryCtrlbar()
{
DECLARE_SC(sc, _T("CSelData::ScDestroyPrimaryCtrlbar"));
if (NULL == m_pCtrlbarPrimary)
return (sc = E_UNEXPECTED);
sc = m_pCtrlbarPrimary->ScCleanup();
if (sc)
return sc;
/*
* In CreateControlbar we had a ref on IControlbar
* (detaching smart ptr). Let us now undo that ref.
*/
m_pCtrlbarPrimary->Release();
m_pCtrlbarPrimary = NULL;
return sc;
}
//+-------------------------------------------------------------------
//
// Member: ScDestroyExtensionCtrlbars
//
// Synopsis: Ask extension controlbars to release their toolbar/menubutton
// ref and cleanup our reference to the controlbars.
//
// Arguments: None
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSelData::ScDestroyExtensionCtrlbars()
{
DECLARE_SC(sc, _T("CSelData::ScDestroyExtensionCtrlbars"));
POSITION pos = m_listExtCBs.GetHeadPosition();
while (pos != NULL)
{
CControlbar* pControlbar = m_listExtCBs.GetNext(pos);
if (pControlbar)
{
sc = pControlbar->ScCleanup();
if (sc)
return sc;
/*
* In CreateControlbar we had a ref on IControlbar
* (detaching smart ptr). Let us now undo that ref.
*/
pControlbar->Release();
}
}
m_listExtCBs.RemoveAll();
return sc;
}
///////////////////////////////////////////////////////////////////////////
//
// CControlbarsCache implementation
//
DEBUG_DECLARE_INSTANCE_COUNTER(CControlbarsCache);
void CControlbarsCache::SetViewData(CViewData* pViewData)
{
ASSERT(pViewData != 0);
m_pViewData = pViewData;
}
CViewData* CControlbarsCache::GetViewData()
{
ASSERT(m_pViewData != NULL);
return m_pViewData;
}
CControlbar* CControlbarsCache::CreateControlbar(IExtendControlbarPtr& spECB,
const CLSID& clsidSnapin)
{
DECLARE_SC(sc, _T("CControlbarsCache::CreateControlbar"));
CComObject<CControlbar>* pControlbar;
sc = CComObject<CControlbar>::CreateInstance(&pControlbar);
if (sc)
return NULL;
IControlbarPtr spControlbar = pControlbar;
if (NULL == spControlbar)
{
ASSERT(NULL != pControlbar); // QI fails but object is created how?
sc = E_UNEXPECTED;
return NULL;
}
pControlbar->SetCache(this);
pControlbar->SetExtendControlbar(spECB, clsidSnapin);
sc = spECB->SetControlbar(spControlbar);
if (sc)
return NULL; // spControlbar smart ptr (object will be destroyed).
// Snapin must return S_OK to be valid
if (S_OK == sc.ToHr())
{
// Detach, thus hold a ref count on the Controlbar object
// CSelData holds this reference & releases the ref in
// ScDestroyPrimaryCtrlbar() or ScDestroyExtensionCtrlbars().
spControlbar.Detach();
// This is for debug info.
Debug_SetControlbarSnapinName(clsidSnapin, pControlbar);
return pControlbar;
}
return NULL;
}
HRESULT
CControlbarsCache::OnMultiSelect(
CNode* pNodeScope,
CMultiSelection* pMultiSelection,
IDataObject* pDOMultiSel,
BOOL bSelect)
{
ASSERT(pNodeScope != NULL);
ASSERT(pMultiSelection != NULL);
ASSERT(pDOMultiSel != NULL);
if (pNodeScope == NULL || pMultiSelection == NULL || pDOMultiSel == NULL)
return E_FAIL;
CSelData selData(false, (bool)bSelect);
selData.m_pMS = pMultiSelection;
if (selData == m_SelData)
return S_FALSE;
if (!bSelect)
return _OnDeSelect(selData);
selData.m_pCompPrimary = pMultiSelection->GetPrimarySnapinComponent();
CList<GUID, GUID&> extnSnapins;
HRESULT hr = pMultiSelection->GetExtensionSnapins(g_szToolbar, extnSnapins);
CHECK_HRESULT(hr);
selData.m_spDataObject.Attach(pDOMultiSel, TRUE);
return _ProcessSelection(selData, extnSnapins);
}
HRESULT
CControlbarsCache::OnResultSelChange(
CNode* pNode,
MMC_COOKIE cookie,
BOOL bSelected)
{
DECLARE_SC(sc, TEXT("CControlbarsCache::OnResultSelChange"));
sc = ScCheckPointers (pNode);
if (sc)
return (sc.ToHr());
CSelData selData(false, (bool)bSelected);
selData.m_lCookie = cookie;
if (selData == m_SelData)
return (sc = S_FALSE).ToHr();
if (!bSelected)
{
sc = _OnDeSelect(selData);
return sc.ToHr();
}
IDataObjectPtr spDataObject = NULL;
CComponent* pCCResultItem = NULL;
CList<CLSID, CLSID&> extnSnapins;
BOOL bListPadItem = GetViewData()->HasListPad() && !IS_SPECIAL_LVDATA(cookie);
if (GetViewData()->IsVirtualList())
{
pCCResultItem = pNode->GetPrimaryComponent();
sc = ScCheckPointers(pCCResultItem, E_UNEXPECTED);
if (sc)
return sc.ToHr();
sc = pCCResultItem->QueryDataObject(cookie, CCT_RESULT, &spDataObject);
if (sc)
return sc.ToHr();
}
else if ( (GetViewData()->HasOCX()) || (GetViewData()->HasWebBrowser() && !bListPadItem) )
{
selData.m_pCompPrimary = pNode->GetPrimaryComponent();
sc = _ProcessSelection(selData, extnSnapins);
return sc.ToHr();
}
else
{
CResultItem* pri = CResultItem::FromHandle(cookie);
sc = ScCheckPointers(pri, E_UNEXPECTED);
if (sc)
return sc.ToHr();
if (pri->IsScopeItem())
{
// Get the data object from IComponentData
pNode = CNode::FromResultItem (pri);
sc = ScCheckPointers(pNode, E_UNEXPECTED);
if (sc)
return sc.ToHr();
if (pNode->IsInitialized() == FALSE)
{
sc = pNode->InitComponents();
if (sc)
return sc.ToHr();
}
pCCResultItem = pNode->GetPrimaryComponent();
sc = pNode->QueryDataObject(CCT_SCOPE, &spDataObject);
if (sc)
return sc.ToHr();
}
else // Must be a leaf item inserted by a snapin
{
pCCResultItem = pNode->GetComponent(pri->GetOwnerID());
sc = ScCheckPointers(pCCResultItem, E_UNEXPECTED);
if (sc)
return sc.ToHr();
sc = pCCResultItem->QueryDataObject(pri->GetSnapinData(), CCT_RESULT,
&spDataObject);
if (sc)
return sc.ToHr();
}
}
// Create extension snapin list
if (spDataObject != NULL)
{
ASSERT(pCCResultItem != NULL);
GUID guidObjType;
sc = ::ExtractObjectTypeGUID(spDataObject, &guidObjType);
if (sc)
return sc.ToHr();
CSnapIn* pSnapIn = pNode->GetPrimarySnapIn();
CMTNode* pmtNode = pNode->GetMTNode();
sc = ScCheckPointers(pmtNode, E_UNEXPECTED);
if (sc)
return sc.ToHr();
CArray<GUID, GUID&> DynExtens;
ExtractDynExtensions(spDataObject, DynExtens);
CExtensionsIterator it;
sc = it.ScInitialize(pSnapIn, guidObjType, g_szToolbar, DynExtens.GetData(), DynExtens.GetSize());
if (!sc.IsError())
{
for (; !it.IsEnd(); it.Advance())
{
extnSnapins.AddHead(const_cast<GUID&>(it.GetCLSID()));
}
}
selData.m_pCompPrimary = pCCResultItem;
selData.m_spDataObject.Attach(spDataObject.Detach());
}
// Finally process selection
sc = _ProcessSelection(selData, extnSnapins);
if (sc)
return sc.ToHr();
return sc.ToHr();
}
HRESULT CControlbarsCache::OnScopeSelChange(CNode* pNode, BOOL bSelected)
{
DECLARE_SC(sc, TEXT("CControlbarsCache::OnScopeSelChange"));
CSelData selData(true, (bool)bSelected);
selData.m_pNodeScope = pNode;
if (selData == m_SelData)
return S_FALSE;
if (!bSelected)
return _OnDeSelect(selData);
HRESULT hr = S_OK;
IDataObjectPtr spDataObject;
CComponent* pCCPrimary = NULL;
CList<CLSID, CLSID&> extnSnapins;
hr = pNode->QueryDataObject(CCT_SCOPE, &spDataObject);
if (FAILED(hr))
return hr;
pCCPrimary = pNode->GetPrimaryComponent();
GUID guidObjType;
hr = ::ExtractObjectTypeGUID(spDataObject, &guidObjType);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
CSnapIn* pSnapIn = pNode->GetPrimarySnapIn();
CArray<GUID, GUID&> DynExtens;
ExtractDynExtensions(spDataObject, DynExtens);
CExtensionsIterator it;
sc = it.ScInitialize(pSnapIn, guidObjType, g_szToolbar, DynExtens.GetData(), DynExtens.GetSize());
if (!sc.IsError())
{
for (; it.IsEnd() == FALSE; it.Advance())
{
extnSnapins.AddHead(const_cast<GUID&>(it.GetCLSID()));
}
}
// Finally process selection
selData.m_pCompPrimary = pCCPrimary;
selData.m_spDataObject.Attach(spDataObject.Detach());
return _ProcessSelection(selData, extnSnapins);
}
HRESULT CControlbarsCache::_OnDeSelect(CSelData& selData)
{
ASSERT(!selData.IsSelect());
if (selData.m_bScopeSel != m_SelData.m_bScopeSel)
return S_FALSE;
if ( (m_SelData.m_pCtrlbarPrimary != NULL &&
m_SelData.m_spDataObject == NULL) &&
(!GetViewData()->HasOCX() ||
!GetViewData()->HasWebBrowser()) &&
m_SelData.IsScope())
{
return E_UNEXPECTED;
}
MMC_NOTIFY_TYPE eNotifyCode = MMCN_SELECT;
LPARAM lDataObject;
if (GetViewData()->IsVirtualList())
{
eNotifyCode = MMCN_DESELECT_ALL;
// Must use NULL data object for MMCN_DESELECT_ALL.
lDataObject = 0;
}
else if ((GetViewData()->HasOCX()) && (!m_SelData.IsScope()))
lDataObject = reinterpret_cast<LPARAM>(DOBJ_CUSTOMOCX);
else if ((GetViewData()->HasWebBrowser()) && (!m_SelData.IsScope()))
{
if (GetViewData()->HasListPad() && m_SelData.m_spDataObject != NULL)
{
lDataObject = reinterpret_cast<LPARAM>(
static_cast<IDataObject*>(m_SelData.m_spDataObject));
}
else
{
lDataObject = reinterpret_cast<LPARAM>(DOBJ_CUSTOMWEB);
}
}
else
{
lDataObject = reinterpret_cast<LPARAM>(
static_cast<IDataObject*>(m_SelData.m_spDataObject));
}
WORD wScope = static_cast<WORD>(m_SelData.IsScope());
LPARAM arg = MAKELONG(wScope, FALSE);
if (m_SelData.m_pCtrlbarPrimary != NULL)
{
m_SelData.m_pCtrlbarPrimary->ControlbarNotify(eNotifyCode, arg,
lDataObject);
}
POSITION pos = m_SelData.m_listExtCBs.GetHeadPosition();
while (pos)
{
CControlbar* pCbar = m_SelData.m_listExtCBs.GetNext(pos);
pCbar->ControlbarNotify(eNotifyCode, arg, lDataObject);
}
m_SelData.m_bSelect = false;
m_SelData.m_spDataObject = NULL; // Release & set to NULL
return S_OK;
}
HRESULT
CControlbarsCache::_ProcessSelection(
CSelData& selData,
CList<CLSID, CLSID&>& extnSnapins)
{
LPARAM lDataObject = reinterpret_cast<LPARAM>(
static_cast<IDataObject*>(selData.m_spDataObject));
if (NULL == lDataObject)
{
if ( (GetViewData()->HasOCX()) && (!selData.IsScope()) )
lDataObject = reinterpret_cast<LPARAM>(DOBJ_CUSTOMOCX);
else if ( (GetViewData()->HasWebBrowser()) && (!selData.IsScope()) )
lDataObject = reinterpret_cast<LPARAM>(DOBJ_CUSTOMWEB);
}
WORD wScope = static_cast<WORD>(selData.IsScope());
long arg = MAKELONG(wScope, TRUE);
m_SelData.m_bScopeSel = selData.m_bScopeSel;
m_SelData.m_bSelect = selData.m_bSelect;
m_SelData.m_pNodeScope = selData.m_pNodeScope;
m_SelData.m_lCookie = selData.m_lCookie;
m_SelData.m_spDataObject.Attach(selData.m_spDataObject.Detach());
// Handle primary controlbar first
if (m_SelData.m_pCompPrimary != selData.m_pCompPrimary)
{
if (m_SelData.m_pCtrlbarPrimary != NULL)
{
// Ask controlbar to destroy its ref & destroy our ref
// to controlbar.
m_SelData.ScDestroyPrimaryCtrlbar();
}
m_SelData.m_pCompPrimary = selData.m_pCompPrimary;
if (m_SelData.m_pCompPrimary != NULL &&
m_SelData.m_pCtrlbarPrimary == NULL)
{
IExtendControlbarPtr spECBPrimary =
m_SelData.m_pCompPrimary->GetIComponent();
if (spECBPrimary != NULL)
{
m_SelData.m_pCtrlbarPrimary =
CreateControlbar(spECBPrimary,
m_SelData.m_pCompPrimary->GetCLSID());
}
}
}
if (m_SelData.m_pCtrlbarPrimary != NULL)
{
m_SelData.m_pCtrlbarPrimary->ControlbarNotify(MMCN_SELECT, arg,
lDataObject);
}
// Handle extension controlbars
CControlbarsList newCBs;
POSITION pos = extnSnapins.GetHeadPosition();
while (pos)
{
CControlbar* pCbar = NULL;
CLSID& clsid = extnSnapins.GetNext(pos);
POSITION pos2 = m_SelData.m_listExtCBs.GetHeadPosition();
POSITION pos2Prev = 0;
while (pos2)
{
pos2Prev = pos2;
pCbar = m_SelData.m_listExtCBs.GetNext(pos2);
ASSERT(pCbar != NULL);
if (pCbar->IsSameSnapin(clsid) == TRUE)
break;
pCbar = NULL;
}
if (pCbar != NULL)
{
ASSERT(pos2Prev != 0);
m_SelData.m_listExtCBs.RemoveAt(pos2Prev);
}
else
{
IExtendControlbarPtr spECB;
HRESULT hr = spECB.CreateInstance(clsid, NULL, MMC_CLSCTX_INPROC);
CHECK_HRESULT(hr);
if (SUCCEEDED(hr))
pCbar = CreateControlbar(spECB, clsid);
}
if (pCbar != NULL)
newCBs.AddHead(pCbar);
}
m_SelData.ScDestroyExtensionCtrlbars();
pos = newCBs.GetHeadPosition();
while (pos)
{
CControlbar* pCbar = newCBs.GetNext(pos);
m_SelData.m_listExtCBs.AddHead(pCbar);
pCbar->ControlbarNotify(MMCN_SELECT, arg, lDataObject);
}
newCBs.RemoveAll();
return S_OK;
}