mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4554 lines
128 KiB
4554 lines
128 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
|
//
|
|
// File: scopndcb.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "scopndcb.h"
|
|
#include "oncmenu.h"
|
|
#include "util.h"
|
|
#include "amcmsgid.h"
|
|
#include "multisel.h"
|
|
#include "nmutil.h"
|
|
#include "nodemgr.h"
|
|
#include "copypast.h"
|
|
#include "regutil.h"
|
|
#include "taskenum.h"
|
|
#include "nodepath.h"
|
|
#include "rsltitem.h"
|
|
#include "bookmark.h"
|
|
#include "tasks.h"
|
|
#include "viewpers.h"
|
|
#include "colwidth.h"
|
|
#include "conframe.h"
|
|
#include "constatbar.h"
|
|
#include "about.h"
|
|
#include "conview.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Trace Tags
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
#ifdef DBG
|
|
CTraceTag tagNodeCallback(TEXT("NodeCallback"), TEXT("NodeCallback"));
|
|
#endif
|
|
|
|
|
|
void AddSubmenu_CreateNew(IContextMenuProvider* pICMP, BOOL fStaticFolder );
|
|
void AddSubmenu_Task(IContextMenuProvider* pICMP );
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CNodeCallback);
|
|
|
|
#define INVALID_COMPONENTID -9
|
|
|
|
|
|
void DeleteMultiSelData(CNode* pNode)
|
|
{
|
|
ASSERT(pNode != NULL);
|
|
ASSERT(pNode->GetViewData() != NULL);
|
|
CMultiSelection* pMultiSel = pNode->GetViewData()->GetMultiSelection();
|
|
if (pMultiSel != NULL)
|
|
{
|
|
pMultiSel->ReleaseMultiSelDataObject();
|
|
pMultiSel->Release();
|
|
pNode->GetViewData()->SetMultiSelection(NULL);
|
|
}
|
|
}
|
|
|
|
CNodeCallback::CNodeCallback()
|
|
: m_pCScopeTree(NULL), m_pNodeUnderInit(NULL)
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CNodeCallback);
|
|
}
|
|
|
|
CNodeCallback::~CNodeCallback()
|
|
{
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CNodeCallback);
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::Initialize(IScopeTree* pScopeTree)
|
|
{
|
|
MMC_TRY
|
|
|
|
IF_NULL_RETURN_INVALIDARG(pScopeTree);
|
|
|
|
m_pCScopeTree = dynamic_cast<CScopeTree*>(pScopeTree);
|
|
ASSERT(m_pCScopeTree != NULL);
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetImages(HNODE hNode, int* piImage, int* piSelectedImage)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(hNode);
|
|
|
|
MMC_TRY
|
|
|
|
// They should ask for at least one of the images.
|
|
if (piImage == NULL && piSelectedImage == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
if (piImage != NULL)
|
|
*piImage = pNode->GetMTNode()->GetImage();
|
|
|
|
if (piSelectedImage != NULL)
|
|
*piSelectedImage = pNode->GetMTNode()->GetOpenImage();
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetDisplayName(HNODE hNode, tstring& strName)
|
|
{
|
|
DECLARE_SC (sc, _T("CNodeCallback::GetDisplayName"));
|
|
|
|
/*
|
|
* clear out the output string
|
|
*/
|
|
strName.erase();
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers (pNode);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
strName = pNode->GetDisplayName();
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::GetWindowTitle(HNODE hNode, tstring& strTitle)
|
|
{
|
|
DECLARE_SC (sc, _T("CNodeCallback::GetWindowTitle"));
|
|
|
|
/*
|
|
* clear out the output string
|
|
*/
|
|
strTitle.erase();
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers (pNode);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers (pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
IDataObjectPtr spdtobj;
|
|
sc = pCC->QueryDataObject(MMC_WINDOW_COOKIE, CCT_UNINITIALIZED, &spdtobj);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
USES_CONVERSION;
|
|
static CLIPFORMAT cfWindowTitle =
|
|
(CLIPFORMAT) RegisterClipboardFormat(OLE2T(CCF_WINDOW_TITLE));
|
|
|
|
sc = ExtractString(spdtobj, cfWindowTitle, strTitle);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
inline HRESULT CNodeCallback::_InitializeNode(CNode* pNode)
|
|
{
|
|
ASSERT(pNode != NULL);
|
|
|
|
m_pNodeUnderInit = pNode;
|
|
HRESULT hr = pNode->InitComponents();
|
|
m_pNodeUnderInit = NULL;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetResultPane(HNODE hNode, CResultViewType& rvt, GUID *pGuidTaskpadID)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetResultPane"));
|
|
|
|
IF_NULL_RETURN_INVALIDARG(hNode);
|
|
|
|
MMC_TRY
|
|
USES_CONVERSION;
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
ASSERT(pNode != NULL);
|
|
|
|
if (pNode->IsInitialized() == FALSE)
|
|
{
|
|
sc = _InitializeNode(pNode);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
}
|
|
|
|
sc = pNode->ScGetResultPane(rvt, pGuidTaskpadID);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
//
|
|
// 'hNodeSel' is the curreently selected node in the scope pane. 'lDispInfo' is
|
|
// the LV disp info struct.
|
|
STDMETHODIMP CNodeCallback::GetDispInfo(HNODE hNodeSel, LV_ITEMW* plvi)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(hNodeSel, plvi);
|
|
|
|
if (theApp.ProcessingSnapinChanges() == TRUE)
|
|
return E_FAIL;
|
|
|
|
// convert to real types
|
|
CNode* pNodeSel = CNode::FromHandle(hNodeSel);
|
|
|
|
if (IsBadWritePtr (plvi, sizeof(*plvi)))
|
|
return E_INVALIDARG;
|
|
|
|
return pNodeSel->GetDispInfoForListItem(plvi);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::AddCustomFolderImage (HNODE hNode, IImageListPrivate* pImageList)
|
|
{
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
if (pNode) {
|
|
CSnapInNode* pSINode = dynamic_cast<CSnapInNode*>(pNode);
|
|
if (pSINode)
|
|
pSINode->SetResultImageList (pImageList);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetState(HNODE hNode, UINT* pnState)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(hNode, pnState);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
*pnState = pNode->GetMTNode()->GetState();
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::Notify(HNODE hNode, NCLBK_NOTIFY_TYPE event,
|
|
LONG_PTR arg, LPARAM param)
|
|
{
|
|
MMC_TRY
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (hNode == NULL)
|
|
{
|
|
switch (event)
|
|
{
|
|
case NCLBK_CONTEXTMENU:
|
|
// Process further.
|
|
break;
|
|
|
|
case NCLBK_GETHELPDOC:
|
|
return OnGetHelpDoc((HELPDOCINFO*)arg, (LPOLESTR*)param);
|
|
|
|
case NCLBK_UPDATEHELPDOC:
|
|
return OnUpdateHelpDoc((HELPDOCINFO*)arg, (HELPDOCINFO*)param);
|
|
|
|
case NCLBK_DELETEHELPDOC:
|
|
return OnDeleteHelpDoc((HELPDOCINFO*)arg);
|
|
|
|
// When the view is closed and NCLBK_SELECT is sent with HNODE NULL (as
|
|
// there is no selected node) handle this case.
|
|
case NCLBK_SELECT:
|
|
return S_OK;
|
|
|
|
default:
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
if (m_pNodeUnderInit && pNode && (m_pNodeUnderInit == pNode))
|
|
return E_FAIL;
|
|
|
|
// See if snapin-cache is being modified.
|
|
if (theApp.ProcessingSnapinChanges() == TRUE)
|
|
{
|
|
// If it is selection/de-selection of node then do not return error
|
|
// after the modifications are done (for snapin-cache) the node will
|
|
// be selected.
|
|
if ( (event == NCLBK_SELECT) ||
|
|
(event == NCLBK_MULTI_SELECT) )
|
|
return S_OK;
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
switch (event)
|
|
{
|
|
case NCLBK_ACTIVATE:
|
|
hr = OnActvate(pNode, arg);
|
|
break;
|
|
|
|
case NCLBK_CACHEHINT:
|
|
pNode->OnCacheHint(arg, param);
|
|
break;
|
|
|
|
case NCLBK_CLICK:
|
|
ASSERT(0);
|
|
break;
|
|
|
|
case NCLBK_CONTEXTMENU:
|
|
hr = OnContextMenu(pNode, arg, param);
|
|
break;
|
|
|
|
case NCLBK_DBLCLICK:
|
|
hr = OnDblClk(pNode, arg);
|
|
break;
|
|
|
|
case NCLBK_CUT:
|
|
case NCLBK_COPY:
|
|
OnCutCopy(pNode, static_cast<BOOL>(arg), param, (event == NCLBK_CUT));
|
|
break;
|
|
|
|
case NCLBK_DELETE:
|
|
{
|
|
hr = OnDelete(pNode, arg, param);
|
|
|
|
// 5. Purge the snapin cache
|
|
CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache();
|
|
ASSERT(pSnapInCache != NULL);
|
|
if (pSnapInCache != NULL)
|
|
pSnapInCache->Purge();
|
|
}
|
|
break;
|
|
|
|
case NCLBK_EXPAND:
|
|
hr = OnExpand(pNode, arg);
|
|
break;
|
|
|
|
case NCLBK_EXPANDED:
|
|
hr = OnExpanded(pNode);
|
|
break;
|
|
|
|
case NCLBK_GETEXPANDEDVISUALLY:
|
|
hr = (pNode->WasExpandedVisually() == true) ? S_OK : S_FALSE;
|
|
break;
|
|
|
|
case NCLBK_SETEXPANDEDVISUALLY:
|
|
pNode->SetExpandedVisually(static_cast<bool>(arg));
|
|
break;
|
|
|
|
case NCLBK_PROPERTIES:
|
|
hr = OnProperties(pNode, static_cast<BOOL>(arg), param);
|
|
break;
|
|
|
|
case NCLBK_REFRESH:
|
|
hr = OnRefresh(pNode, static_cast<BOOL>(arg), param);
|
|
break;
|
|
|
|
case NCLBK_NEW_TASKPAD_FROM_HERE:
|
|
hr = OnNewTaskpadFromHere(pNode);
|
|
break;
|
|
|
|
case NCLBK_EDIT_TASKPAD:
|
|
hr = OnEditTaskpad(pNode);
|
|
break;
|
|
|
|
case NCLBK_DELETE_TASKPAD:
|
|
hr = OnDeleteTaskpad(pNode);
|
|
break;
|
|
|
|
case NCLBK_PRINT:
|
|
hr = OnPrint(pNode, static_cast<BOOL>(arg), param);
|
|
break;
|
|
|
|
case NCLBK_NEW_NODE_UPDATE:
|
|
hr = OnNewNodeUpdate(pNode, arg);
|
|
break;
|
|
|
|
case NCLBK_RENAME:
|
|
hr = OnRename(pNode, reinterpret_cast<SELECTIONINFO*>(arg),
|
|
reinterpret_cast<LPOLESTR>(param));
|
|
break;
|
|
|
|
case NCLBK_MULTI_SELECT:
|
|
OnMultiSelect(pNode, static_cast<BOOL>(arg));
|
|
break;
|
|
|
|
case NCLBK_SELECT:
|
|
OnSelect(pNode, static_cast<BOOL>(arg),
|
|
reinterpret_cast<SELECTIONINFO*>(param));
|
|
break;
|
|
|
|
case NCLBK_FINDITEM:
|
|
OnFindResultItem(pNode, reinterpret_cast<RESULTFINDINFO*>(arg),
|
|
reinterpret_cast<LRESULT*>(param));
|
|
break;
|
|
|
|
case NCLBK_COLUMN_CLICKED:
|
|
hr = OnColumnClicked(pNode, param);
|
|
break;
|
|
|
|
case NCLBK_CONTEXTHELP:
|
|
hr = OnContextHelp(pNode, static_cast<BOOL>(arg), param);
|
|
break;
|
|
|
|
case NCLBK_SNAPINHELP:
|
|
hr = OnSnapInHelp(pNode, static_cast<BOOL>(arg), param);
|
|
break;
|
|
|
|
case NCLBK_FILTER_CHANGE:
|
|
hr = OnFilterChange(pNode, arg, param);
|
|
break;
|
|
|
|
case NCLBK_FILTERBTN_CLICK:
|
|
hr = OnFilterBtnClick(pNode, arg, reinterpret_cast<LPRECT>(param));
|
|
break;
|
|
|
|
case NCLBK_TASKNOTIFY:
|
|
pNode->OnTaskNotify(arg, param);
|
|
break;
|
|
|
|
case NCLBK_GETPRIMARYTASK:
|
|
hr = OnGetPrimaryTask (pNode, param);
|
|
break;
|
|
|
|
case NCLBK_MINIMIZED:
|
|
hr = OnMinimize (pNode, arg);
|
|
break;
|
|
|
|
case NCLBK_LISTPAD:
|
|
hr = pNode->OnListPad(arg, param);
|
|
break;
|
|
|
|
case NCLBK_WEBCONTEXTMENU:
|
|
pNode->OnWebContextMenu();
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::GetMTNode(HNODE hNode, HMTNODE* phMTNode)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(hNode, phMTNode);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
*phMTNode = CMTNode::ToHandle(pNode->GetMTNode());
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::SetResultItem(HNODE hNode, HRESULTITEM hri)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(hNode);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
pNode->SetResultItem(hri);
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetResultItem(HNODE hNode, HRESULTITEM* phri)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(hNode);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
*phri = pNode->GetResultItem();
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetMTNodeID(HNODE hNode, MTNODEID* pnID)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(pnID);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
*pnID = pNode->GetMTNode()->GetID();
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::IsTargetNodeOf
|
|
*
|
|
* PURPOSE: Is one node a target of another
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNode : The node that contains the target
|
|
* HNODE hTestNode : The alleged target
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
* S_OK - yes
|
|
* S_FALSE - uses a different target node
|
|
* E_FAIL - doesn't use a target node
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
STDMETHODIMP CNodeCallback::IsTargetNodeOf(HNODE hNode, HNODE hTestNode)
|
|
{
|
|
MMC_TRY
|
|
|
|
ASSERT(hNode && hTestNode);
|
|
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
CNode* pTestNode = CNode::FromHandle(hTestNode);
|
|
ASSERT(pNode);
|
|
|
|
return pNode->IsTargetNode(pTestNode);
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::GetPath(HNODE hNode, HNODE hRootNode,
|
|
LPBYTE pbm)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetPath"));
|
|
|
|
sc = ScCheckPointers((PVOID)hNode, (PVOID)hRootNode, pbm);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
CNode* pRootNode = CNode::FromHandle(hRootNode);
|
|
CBookmark* pbmOut = reinterpret_cast<CBookmark *>(pbm);
|
|
|
|
CBookmarkEx bm;
|
|
|
|
sc = bm.ScInitialize(pNode->GetMTNode(), pRootNode->GetMTNode(), true).ToHr();
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// set the out parameter.
|
|
*pbmOut = bm;
|
|
|
|
return sc.ToHr();
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetStaticParentID(HNODE hNode, MTNODEID* pnID)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(hNode, pnID);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
CMTNode* pMTNode = pNode->GetMTNode();
|
|
ASSERT(pMTNode != NULL);
|
|
|
|
while (pMTNode != NULL && pMTNode->IsStaticNode() == FALSE)
|
|
{
|
|
pMTNode = pMTNode->Parent();
|
|
}
|
|
|
|
ASSERT(pMTNode != NULL);
|
|
|
|
if (pMTNode != NULL)
|
|
{
|
|
*pnID = pMTNode->GetID();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
// The path for the node is stored in pphMTNode. The path is an array of
|
|
// HMTNODE's starting from the console root, followed by its child node and
|
|
// continuing in this fashion till the HMTNODE of the root node.
|
|
STDMETHODIMP CNodeCallback::GetMTNodePath(HNODE hNode, HMTNODE** pphMTNode,
|
|
long* plLength)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG3(hNode, pphMTNode, plLength);
|
|
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
CMTNode* pMTNode = pNode->GetMTNode();
|
|
pMTNode = pMTNode->Parent(); // skip this node
|
|
|
|
for (*plLength = 0; pMTNode != NULL; pMTNode = pMTNode->Parent())
|
|
++(*plLength);
|
|
|
|
if (*plLength != 0)
|
|
{
|
|
HMTNODE* phMTNode = (HMTNODE*)CoTaskMemAlloc(sizeof(HMTNODE) *
|
|
(*plLength));
|
|
if (phMTNode == NULL)
|
|
{
|
|
CHECK_HRESULT(E_OUTOFMEMORY);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*pphMTNode = phMTNode;
|
|
|
|
pMTNode = pNode->GetMTNode();
|
|
pMTNode = pMTNode->Parent(); // skip this node
|
|
|
|
phMTNode = phMTNode + (*plLength - 1);
|
|
|
|
for (; pMTNode != NULL; pMTNode = pMTNode->Parent(), --phMTNode)
|
|
*phMTNode = CMTNode::ToHandle(pMTNode);
|
|
|
|
ASSERT(++phMTNode == *pphMTNode);
|
|
}
|
|
else
|
|
{
|
|
pphMTNode = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::GetNodeOwnerID
|
|
*
|
|
* PURPOSE: Get the ID of the snap-in component that owns this node.
|
|
* If not a snap-in owned node, TVOWNED_MAGICWORD is returned.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNode : Node to query
|
|
* COMPONENTID* : ptr to returned ID
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
* S_OK - ID returned
|
|
* E_INVALIDARG -
|
|
* E_FAIL - probably an invalid hNode
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
|
|
/*******************************************************************************
|
|
* >>>>>>>>>>>>>> READ THIS BEFORE USING GetNodeOwnerID <<<<<<<<<<<<<<<<<<<<<<<
|
|
*
|
|
* This method differs from the GetOwnerID method exposed by CNode (and CMTNode)
|
|
* in that it returns a zero ID for snap-in static nodes, indicating that the
|
|
* owner is the snap-in primary component. The CNode method returns
|
|
* TVOWNED_MAGICWORD for snap-in static nodes, inidcating MMC ownership. For
|
|
* most purposes the zero ID is more appropriate and I think the node method
|
|
* should be changed. This requires looking at all uses of the owner ID and
|
|
* verifying nothing will break. rswaney 5/5/99
|
|
*******************************************************************************/
|
|
|
|
STDMETHODIMP CNodeCallback::GetNodeOwnerID(HNODE hNode, COMPONENTID* pOwnerID)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(hNode, pOwnerID);
|
|
|
|
MMC_TRY
|
|
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
if (pNode->IsStaticNode())
|
|
*pOwnerID = 0;
|
|
else
|
|
*pOwnerID = pNode->GetOwnerID();
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::GetNodeCookie(HNODE hNode, MMC_COOKIE* pCookie)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(hNode, pCookie);
|
|
|
|
MMC_TRY
|
|
|
|
// only dynamic nodes have cookies
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
if (!pNode->IsDynamicNode())
|
|
return E_FAIL;
|
|
|
|
*pCookie = pNode->GetUserParam();
|
|
|
|
return S_OK;
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::GetControl
|
|
*
|
|
* PURPOSE: See if there is a OCX with given CLSID for the given node.
|
|
* If so return it.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNode :
|
|
* CLSID clsid :
|
|
* IUnknown ** ppUnkControl :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CNodeCallback::GetControl(HNODE hNode, CLSID clsid, IUnknown **ppUnkControl)
|
|
{
|
|
MMC_TRY
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetControl"));
|
|
|
|
sc = ScCheckPointers((void *)hNode, ppUnkControl);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*ppUnkControl = pNode->GetControl(clsid);
|
|
if(!*ppUnkControl)
|
|
return sc.ToHr();
|
|
|
|
// addref the interface for the client.
|
|
|
|
(*ppUnkControl)->AddRef();
|
|
|
|
return sc.ToHr();
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::SetControl
|
|
*
|
|
* PURPOSE: For the given node & clsid of OCX save the OCX window IUnknown*.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNode :
|
|
* CLSID clsid :
|
|
* IUnknown* pUnknown :
|
|
*
|
|
* RETURNS:
|
|
* STDMETHODIMP
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CNodeCallback::SetControl(HNODE hNode, CLSID clsid, IUnknown* pUnknown)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::SetControl"));
|
|
sc = ScCheckPointers((void*)hNode, pUnknown);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
pNode->SetControl(clsid, pUnknown);
|
|
|
|
return sc.ToHr();
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::GetControl
|
|
//
|
|
// Synopsis: For given node & IUnknown* of OCX get the OCX wrapper if one exists.
|
|
//
|
|
// Arguments: [hNode]
|
|
// [pUnkOCX]
|
|
// [ppUnkControl]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::GetControl (HNODE hNode, LPUNKNOWN pUnkOCX, IUnknown **ppUnkControl)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::GetControl"));
|
|
sc = ScCheckPointers((void*)hNode, pUnkOCX, ppUnkControl);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*ppUnkControl = pNode->GetControl(pUnkOCX);
|
|
if(!*ppUnkControl)
|
|
return sc.ToHr();
|
|
|
|
// addref the interface for the client.
|
|
|
|
(*ppUnkControl)->AddRef();
|
|
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: SetControl
|
|
//
|
|
// Synopsis: For given node & IUnknown of OCX save the IUnknown of
|
|
// OCX wrapper.
|
|
//
|
|
// Arguments: [hNode]
|
|
// [pUnkOCX]
|
|
// [pUnknown]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::SetControl (HNODE hNode, LPUNKNOWN pUnkOCX, IUnknown* pUnknown)
|
|
{
|
|
DECLARE_SC(sc, _T("SetControl"));
|
|
sc = ScCheckPointers((void*) hNode, pUnkOCX, pUnknown);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
pNode->SetControl(pUnkOCX, pUnknown);
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CNodeCallback::InitOCX(HNODE hNode, IUnknown* pUnknown)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::InitOCX"));
|
|
|
|
sc = ScCheckPointers((void *)hNode);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = pNode->OnInitOCX(pUnknown);
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Notify handlers
|
|
|
|
|
|
HRESULT CNodeCallback::OnActvate(CNode* pNode, LONG_PTR arg)
|
|
{
|
|
DECLARE_SC (sc, _T("CNodeCallback::OnActvate"));
|
|
sc = ScCheckPointers (pNode);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
return pNode->OnActvate(arg);
|
|
}
|
|
|
|
|
|
HRESULT CNodeCallback::OnMinimize(CNode* pNode, LONG_PTR arg)
|
|
{
|
|
DECLARE_SC (sc, _T("CNodeCallback::OnMinimize"));
|
|
sc = ScCheckPointers (pNode);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
return pNode->OnMinimize(arg);
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnDelete(CNode* pNode, BOOL bScopePaneSelected, LPARAM lvData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnDelete"));
|
|
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, bScopePaneSelected, lvData,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If result-pane cookie should be valid.
|
|
ASSERT( (bScopeItemSelected) || cookie != LVDATA_ERROR);
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return E_FAIL;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!bScopeItemSelected)
|
|
{
|
|
CMultiSelection* pMultiSel = pSelectedNode->GetViewData()->GetMultiSelection();
|
|
if (pMultiSel != NULL)
|
|
{
|
|
ASSERT(lvData == LVDATA_MULTISELECT);
|
|
pMultiSel->ScVerbInvoked(MMC_VERB_DELETE);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(lvData != LVDATA_MULTISELECT);
|
|
|
|
CComponent* pCC = pSelectedNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
|
|
if (pCC != NULL)
|
|
{
|
|
if (IS_SPECIAL_LVDATA(lvData))
|
|
{
|
|
LPDATAOBJECT pdobj = (lvData == LVDATA_CUSTOMOCX) ?
|
|
DOBJ_CUSTOMOCX : DOBJ_CUSTOMWEB;
|
|
|
|
hr = pCC->Notify(pdobj, MMCN_DELETE, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
else
|
|
{
|
|
IDataObjectPtr spdtobj;
|
|
hr = pCC->QueryDataObject(cookie, CCT_RESULT, &spdtobj);
|
|
|
|
ASSERT( NULL != pCC->GetIComponent() );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pCC->Notify(spdtobj, MMCN_DELETE, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CMTNode* pMTNode = pSelectedNode->GetMTNode();
|
|
if (pMTNode->Parent() == NULL)
|
|
return S_FALSE;
|
|
|
|
if (pSelectedNode->IsStaticNode() == TRUE) // All static nodes can be deleted
|
|
{
|
|
ASSERT(m_pCScopeTree != NULL);
|
|
|
|
if (pMTNode->DoDelete(pSelectedNode->GetViewData()->GetMainFrame()) == false)
|
|
return S_FALSE;
|
|
|
|
// Delete storage
|
|
hr = pMTNode->DestroyElements();
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
// Delete the node.
|
|
m_pCScopeTree->DeleteNode(pMTNode);
|
|
|
|
}
|
|
else // Tell the snapin that put up the dynamic node to delete.
|
|
{
|
|
CComponentData* pCD = pMTNode->GetPrimaryComponentData();
|
|
ASSERT(pCD != NULL);
|
|
|
|
IDataObjectPtr spDataObject;
|
|
hr = pCD->QueryDataObject(pMTNode->GetUserParam(), CCT_SCOPE, &spDataObject);
|
|
CHECK_HRESULT(hr);
|
|
|
|
ASSERT( NULL != pCD->GetIComponentData() );
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = pCD->Notify(spDataObject, MMCN_DELETE, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnFindResultItem(CNode* pNode, RESULTFINDINFO* pFindInfo, LRESULT* pResult)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG3(pNode, pFindInfo, pResult);
|
|
|
|
// init result to -1 (item not found)
|
|
*pResult = -1;
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
if (pCC == NULL)
|
|
return E_FAIL;
|
|
|
|
IResultOwnerDataPtr spIResultOwnerData = pCC->GetIComponent();
|
|
if (spIResultOwnerData == NULL)
|
|
return S_FALSE;
|
|
|
|
return spIResultOwnerData->FindItem(pFindInfo, reinterpret_cast<int*>(pResult));
|
|
}
|
|
|
|
|
|
|
|
HRESULT CNodeCallback::OnRename(CNode* pNode, SELECTIONINFO *pSelInfo,
|
|
LPOLESTR pszNewName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pSelInfo->m_bScope)
|
|
{
|
|
CMTNode* pMTNode = pNode->GetMTNode();
|
|
|
|
hr = pMTNode->OnRename(1, pszNewName);
|
|
}
|
|
else
|
|
{
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
if (pCC != NULL)
|
|
{
|
|
IDataObjectPtr spDataObject;
|
|
hr = pCC->QueryDataObject(pSelInfo->m_lCookie, CCT_RESULT,
|
|
&spDataObject);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = pCC->Notify(spDataObject, MMCN_RENAME, 1,
|
|
reinterpret_cast<LPARAM>(pszNewName));
|
|
CHECK_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (pNode->IsStaticNode() == TRUE) {
|
|
USES_CONVERSION;
|
|
pNode->SetDisplayName( W2T(pszNewName) );
|
|
}
|
|
|
|
// Now inform the views to modify as needed.
|
|
SViewUpdateInfo vui;
|
|
// Snapin nodes result pane will be handled by the snapins
|
|
vui.flag = VUI_REFRESH_NODE;
|
|
pNode->GetMTNode()->CreatePathList(vui.path);
|
|
m_pCScopeTree->UpdateAllViews(VIEW_UPDATE_MODIFY,
|
|
reinterpret_cast<LPARAM>(&vui));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnNewNodeUpdate(CNode* pNode, LONG_PTR lFlags)
|
|
{
|
|
pNode->GetMTNode()->SetPropertyPageIsDisplayed(FALSE);
|
|
|
|
// Inform the views to modify.
|
|
SViewUpdateInfo vui;
|
|
vui.flag = lFlags;
|
|
pNode->GetMTNode()->CreatePathList(vui.path);
|
|
m_pCScopeTree->UpdateAllViews(VIEW_UPDATE_MODIFY,
|
|
reinterpret_cast<LPARAM>(&vui));
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnExpand(CNode* pNode, BOOL fExpand)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ASSERT(pNode != 0);
|
|
|
|
// initialize the node if needed.
|
|
if ( fExpand && (pNode->WasExpandedAtLeastOnce() == FALSE) &&
|
|
(pNode->IsInitialized() == FALSE))
|
|
{
|
|
hr = _InitializeNode(pNode);
|
|
if ((FAILED(hr)))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return pNode->OnExpand(fExpand);
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnExpanded(CNode* pNode)
|
|
{
|
|
ASSERT(pNode != 0);
|
|
|
|
pNode->SetExpandedAtLeastOnce();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnScopeSelect(CNode* pNode, BOOL bSelect,
|
|
SELECTIONINFO* pSelInfo)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnScopeSelect"));
|
|
sc = ScCheckPointers(pNode, pSelInfo);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// clear out the the status bar text if we're deselecting a node
|
|
if (! bSelect)
|
|
{
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CConsoleStatusBar* pStatusBar = pViewData->GetStatusBar();
|
|
|
|
if (pStatusBar != NULL)
|
|
pStatusBar->ScSetStatusText (NULL);
|
|
}
|
|
|
|
if (pNode->IsInitialized() == FALSE)
|
|
{
|
|
sc = _InitializeNode(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
|
|
sc = pNode->OnScopeSelect(bSelect, pSelInfo);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
|
|
#ifdef DBG
|
|
if (bSelect)
|
|
Dbg(DEB_USER11, _T("Selecting %s node."), pNode->GetDisplayName());
|
|
#endif
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::SetTaskPadList(HNODE hNode, LPUNKNOWN pUnknown)
|
|
{
|
|
IFramePrivate* pFramePrivate = GetIFramePrivateFromNode (hNode);
|
|
|
|
if (pFramePrivate == NULL)
|
|
return E_UNEXPECTED;
|
|
|
|
return (pFramePrivate->SetTaskPadList(pUnknown));
|
|
}
|
|
|
|
IFramePrivate* GetIFramePrivateFromNode (CNode* pNode)
|
|
{
|
|
if (pNode == NULL)
|
|
return (NULL);
|
|
|
|
return pNode->GetIFramePrivate();
|
|
}
|
|
|
|
void CNodeCallback::OnMultiSelect(CNode* pNode, BOOL bSelect)
|
|
{
|
|
Trace(tagNodeCallback, _T("----------------->>>>>>> MULTI_SELECT<%d>\n"), bSelect);
|
|
SC sc;
|
|
CViewData* pViewData = NULL;
|
|
|
|
if (NULL == pNode)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
pViewData = pNode->GetViewData();
|
|
if (NULL == pViewData)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
if (pViewData->IsVirtualList())
|
|
{
|
|
if (bSelect == TRUE)
|
|
DeleteMultiSelData(pNode);
|
|
}
|
|
|
|
_OnMultiSelect(pNode, bSelect);
|
|
if (bSelect == FALSE)
|
|
DeleteMultiSelData(pNode);
|
|
|
|
// Update the std-verb tool-buttons.
|
|
sc = pViewData->ScUpdateStdbarVerbs();
|
|
if (sc)
|
|
goto Error;
|
|
|
|
pViewData->UpdateToolbars(pViewData->GetToolbarsDisplayed());
|
|
|
|
Cleanup:
|
|
return;
|
|
Error:
|
|
TraceError (_T("CNodeCallback::OnMultiSelect"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
void CNodeCallback::_OnMultiSelect(CNode* pNode, BOOL bSelect)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::_OnMultiSelect"));
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return;
|
|
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
CMultiSelection* pMultiSelection = pNode->GetViewData()->GetMultiSelection();
|
|
|
|
if (pMultiSelection)
|
|
{
|
|
if (pMultiSelection->IsInUse())
|
|
return;
|
|
else
|
|
{
|
|
/*
|
|
* If result pane items are selected by dragging a mouse (that forms Marquee)
|
|
* or if snapin sets items to selected state then the items are selected one
|
|
* by one. That is multi-select for 1 item, multi-select for 2 items and so-on.
|
|
* There is no deselect inbetween, so if we already have a multiselection object
|
|
* for 2 items then when we get multi-select for 3 items we need to destroy multiselection
|
|
* object for 2 items. This is done below.
|
|
*
|
|
*/
|
|
DeleteMultiSelData(pNode);
|
|
pMultiSelection = NULL;
|
|
}
|
|
}
|
|
|
|
// set standard bars
|
|
CVerbSet* pVerbSet = dynamic_cast<CVerbSet*>(pViewData->GetVerbSet());
|
|
sc = ScCheckPointers(pVerbSet, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
sc = pVerbSet->ScInitializeForMultiSelection(pNode, bSelect);
|
|
if (sc)
|
|
return;
|
|
|
|
if (pMultiSelection == NULL)
|
|
{
|
|
if (bSelect == FALSE)
|
|
return;
|
|
|
|
CComponentPtrArray* prgComps = new CComponentPtrArray;
|
|
if (pNode->IsInitialized() == FALSE)
|
|
{
|
|
sc = _InitializeNode(pNode);
|
|
if (sc)
|
|
return;
|
|
}
|
|
|
|
// Create CMultiSelection
|
|
pMultiSelection = new CMultiSelection(pNode);
|
|
sc = ScCheckPointers(pMultiSelection, E_OUTOFMEMORY);
|
|
if (sc)
|
|
return;
|
|
|
|
sc = pMultiSelection->Init();
|
|
if (sc)
|
|
return;
|
|
|
|
pViewData->SetMultiSelection(pMultiSelection);
|
|
}
|
|
|
|
pMultiSelection->SetScopeTree(m_pCScopeTree);
|
|
|
|
IDataObjectPtr spdobj;
|
|
sc = pMultiSelection->GetMultiSelDataObject(&spdobj);
|
|
if (sc)
|
|
return;
|
|
|
|
sc = ScCheckPointers(spdobj, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
// give the scope item a chance to do any initialization that it needs.
|
|
// For instance, the console taskpad uses this opportunity to gather information
|
|
// about the selected item's context menu.
|
|
SELECTIONINFO SelInfo;
|
|
SelInfo.m_lCookie = LVDATA_MULTISELECT;
|
|
|
|
// Inform control bars of selection change.
|
|
CControlbarsCache* pCtrlbarsCache =
|
|
dynamic_cast<CControlbarsCache*>(pNode->GetControlbarsCache());
|
|
sc = ScCheckPointers(pCtrlbarsCache, E_UNEXPECTED);
|
|
if (sc)
|
|
return;
|
|
|
|
pCtrlbarsCache->OnMultiSelect(pNode, pMultiSelection, spdobj, bSelect);
|
|
|
|
sc = pVerbSet->ScComputeVerbStates();
|
|
if (sc)
|
|
return;
|
|
}
|
|
|
|
void CNodeCallback::OnSelect(CNode* pNode, BOOL bSelect, SELECTIONINFO* pSelInfo)
|
|
{
|
|
Trace(tagNodeCallback, _T("----------------->>>>>>> SELECT<%d>\n"), bSelect);
|
|
SC sc;
|
|
CViewData* pViewData = NULL;
|
|
|
|
if (pSelInfo == NULL)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
Trace(tagNodeCallback, _T("====>> NCLBK_SELECT<%d, %d, %c>\n"), pSelInfo->m_bScope, bSelect, pSelInfo->m_bDueToFocusChange ? _T('F') : _T('S'));
|
|
|
|
if (NULL == pNode)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
pViewData = pNode->GetViewData();
|
|
if (NULL == pViewData)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
goto Error;
|
|
}
|
|
|
|
DeleteMultiSelData(pNode);
|
|
|
|
if (!bSelect)
|
|
{
|
|
// Reset controlbars
|
|
pNode->ResetControlbars(bSelect, pSelInfo);
|
|
|
|
// Reset standard verbs
|
|
sc = pNode->ScInitializeVerbs(bSelect, pSelInfo);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
}
|
|
|
|
// For scoe sel change reset result pane.
|
|
if (pSelInfo->m_bScope == TRUE && pSelInfo->m_bDueToFocusChange == FALSE)
|
|
{
|
|
sc = OnScopeSelect(pNode, bSelect, pSelInfo);
|
|
if (sc)
|
|
goto Error;
|
|
}
|
|
|
|
if (bSelect)
|
|
{
|
|
// Reset controlbars
|
|
pNode->ResetControlbars(bSelect, pSelInfo);
|
|
|
|
// Reset standard verbs
|
|
sc = pNode->ScInitializeVerbs(bSelect, pSelInfo);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
}
|
|
|
|
// Update the std-verb tool-buttons.
|
|
sc = pViewData->ScUpdateStdbarVerbs();
|
|
|
|
// Dummy block
|
|
{
|
|
// Update the paste button
|
|
LPARAM lvData = pSelInfo->m_lCookie;
|
|
|
|
BOOL bScopePaneSelected = pSelInfo->m_bScope || pSelInfo->m_bBackground;
|
|
|
|
sc = UpdatePasteButton(CNode::ToHandle(pNode), bScopePaneSelected, lvData);
|
|
if (sc)
|
|
goto Error;
|
|
|
|
// Update toolbars.
|
|
pViewData->UpdateToolbars(pViewData->GetToolbarsDisplayed());
|
|
}
|
|
|
|
Cleanup:
|
|
return;
|
|
Error:
|
|
TraceError (_T("CNodeCallback::OnSelect"), sc);
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
HRESULT CNodeCallback::OnDblClk(CNode* pNode, LONG_PTR lvData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnDblClk"));
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
BOOL bScopePaneSelected = FALSE;
|
|
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, bScopePaneSelected, lvData,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If result-pane cookie should be valid.
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return (sc = E_FAIL).ToHr();
|
|
|
|
// Ignore double-click on LV background.
|
|
if (lvData == LVDATA_BACKGROUND)
|
|
return sc.ToHr();
|
|
|
|
CComponent* pCC = pSelectedNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Get the dataobject of the item which was double-clicked.
|
|
IDataObjectPtr spdtobj;
|
|
|
|
if (!bScopeItemSelected) // leaf item
|
|
{
|
|
sc = pCC->QueryDataObject(cookie, CCT_RESULT, &spdtobj);
|
|
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
return sc.ToHr();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sc = pSelectedNode->QueryDataObject(CCT_SCOPE, &spdtobj);
|
|
if (sc)
|
|
{
|
|
sc.TraceAndClear();
|
|
return sc.ToHr();
|
|
}
|
|
}
|
|
|
|
sc = pCC->Notify(spdtobj, MMCN_DBLCLICK, 0, 0);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
|
|
// Snapin has asked us to do default verb action, so findout default verb.
|
|
if (sc == S_FALSE)
|
|
{
|
|
CViewData *pViewData = pSelectedNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CVerbSet* pVerbSet = dynamic_cast<CVerbSet*>(pViewData->GetVerbSet());
|
|
sc = ScCheckPointers(pVerbSet, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
MMC_CONSOLE_VERB defaultVerb = MMC_VERB_NONE;
|
|
pVerbSet->GetDefaultVerb(&defaultVerb);
|
|
if (defaultVerb == MMC_VERB_OPEN)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
else if (defaultVerb == MMC_VERB_PROPERTIES)
|
|
{
|
|
OnProperties(pNode, bScopePaneSelected, lvData);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnContextMenu(CNode* pNode, LONG_PTR arg, LPARAM param)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnContextMenu"));
|
|
|
|
ASSERT(param != NULL);
|
|
CContextMenuInfo& contextInfo = *reinterpret_cast<CContextMenuInfo*>(param);
|
|
|
|
BOOL b = static_cast<BOOL>(arg);
|
|
|
|
if ((pNode != NULL) && !pNode->IsInitialized())
|
|
{
|
|
sc = pNode->InitComponents();
|
|
if(sc)
|
|
return sc.ToHr();
|
|
}
|
|
|
|
// Create a CContextMenu and initialize it.
|
|
CContextMenu * pContextMenu = NULL;
|
|
ContextMenuPtr spContextMenu;
|
|
|
|
sc = CContextMenu::ScCreateInstance(&spContextMenu, &pContextMenu);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pContextMenu, spContextMenu.GetInterfacePtr(), E_UNEXPECTED);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pContextMenu->ScInitialize(pNode, this, m_pCScopeTree, contextInfo);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pContextMenu->Display(b);
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::CreateContextMenu
|
|
*
|
|
* PURPOSE: Creates a context menu for the specified node.
|
|
*
|
|
* PARAMETERS:
|
|
* PNODE pNode :
|
|
* PPCONTEXTMENU ppContextMenu : [OUT]: The context menu structure.
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CNodeCallback::CreateContextMenu( PNODE pNode, HNODE hNode, PPCONTEXTMENU ppContextMenu)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::CreateContextMenu"));
|
|
|
|
sc = ScCheckPointers(pNode, ppContextMenu);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = CContextMenu::ScCreateContextMenu(pNode, hNode, ppContextMenu, this, m_pCScopeTree);
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::CreateSelectionContextMenu
|
|
*
|
|
* PURPOSE: Creates a context menu for the current selection in the result pane.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeScope :
|
|
* CContextMenuInfo * pContextInfo :
|
|
* PPCONTEXTMENU ppContextMenu :
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CNodeCallback::CreateSelectionContextMenu( HNODE hNodeScope, CContextMenuInfo *pContextInfo, PPCONTEXTMENU ppContextMenu)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::CreateSelectionContextMenu"));
|
|
|
|
sc = CContextMenu::ScCreateSelectionContextMenu(hNodeScope, pContextInfo, ppContextMenu, this, m_pCScopeTree);
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::GetProperty
|
|
*
|
|
* PURPOSE: Returns the specified property for the specified list item by calling
|
|
* IDataObject::GetData using a STREAM medium on the node's data
|
|
* object.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeScope : The parent scope item
|
|
* BOOL bForScopeItem : TRUE if the list item is a scope item in the list.
|
|
* LPARAM resultItemParam : The LPARAM of the result item
|
|
* BSTR bstrPropertyName : The name of the clipboard format.
|
|
* PBSTR pbstrPropertyValue :
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CNodeCallback::GetProperty(HNODE hNodeScope, BOOL bForScopeItem, LPARAM resultItemParam, BSTR bstrPropertyName, PBSTR pbstrPropertyValue)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetProperty"));
|
|
|
|
// check parameters
|
|
sc = ScCheckPointers(bstrPropertyName);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// initialize out parameter
|
|
*pbstrPropertyValue = NULL;
|
|
|
|
// convert the HNODE to a CNode *
|
|
CNode *pNodeScope = CNode::FromHandle(hNodeScope);
|
|
|
|
sc = ScCheckPointers(pNodeScope);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// create a data object for the specified item
|
|
IDataObjectPtr spDataObject;
|
|
|
|
bool bScopeItem;
|
|
sc = pNodeScope->ScGetDataObject(bForScopeItem, resultItemParam, bScopeItem, &spDataObject);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// try to get the propeorty from the INodeProperties interface
|
|
sc = pNodeScope->ScGetPropertyFromINodeProperties(spDataObject, bForScopeItem, resultItemParam, bstrPropertyName, pbstrPropertyValue);
|
|
if( (!sc.IsError()) && (sc.ToHr() != S_FALSE) ) // got it, exit
|
|
return sc.ToHr();
|
|
|
|
// didn't find it, continue
|
|
sc.Clear();
|
|
|
|
// get the property from data object
|
|
sc = ScGetProperty(spDataObject, bstrPropertyName, pbstrPropertyValue);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNodeCallback::ScGetProperty
|
|
*
|
|
* PURPOSE: Helper (static) method to access snapin property
|
|
*
|
|
* PARAMETERS:
|
|
* IDataObject *pDataObject - [in] data object
|
|
* BSTR bstrPropertyName - [in] property (clipboard fromat) name
|
|
* PBSTR pbstrPropertyValue - [out] resulting value
|
|
*
|
|
* RETURNS:
|
|
* SC - result code. NOTE: no error is returned if the snapin does not
|
|
* support the specified clipboard format. In this case *pbstrPropertyValue
|
|
* is set to NULL.
|
|
*
|
|
\***************************************************************************/
|
|
SC CNodeCallback::ScGetProperty(IDataObject *pDataObject, BSTR bstrPropertyName, PBSTR pbstrPropertyValue)
|
|
{
|
|
DECLARE_SC(sc, TEXT("ScGetProperty"));
|
|
|
|
// check parameters
|
|
sc = ScCheckPointers(pDataObject, bstrPropertyName, pbstrPropertyValue);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// initialize out parameter
|
|
*pbstrPropertyValue = NULL;
|
|
|
|
// create a stream for the data object to use
|
|
IStreamPtr pStm;
|
|
sc = CreateStreamOnHGlobal(NULL, true, &pStm);
|
|
if(sc)
|
|
return sc;
|
|
|
|
ULARGE_INTEGER zeroSize = {0, 0};
|
|
sc = pStm->SetSize(zeroSize);
|
|
if(sc)
|
|
return sc;
|
|
|
|
USES_CONVERSION;
|
|
CLIPFORMAT cfClipFormat = (CLIPFORMAT)RegisterClipboardFormat(OLE2T(bstrPropertyName));
|
|
|
|
// First call ExtractString which uses GetData
|
|
CStr strOutput;
|
|
sc = ExtractString (pDataObject, cfClipFormat, strOutput);
|
|
if(!sc.IsError())
|
|
{
|
|
*pbstrPropertyValue = ::SysAllocStringLen(T2COLE(strOutput), strOutput.GetLength()/*prevents the terminating zero from being added.*/); // allocate the string and return
|
|
return sc;
|
|
}
|
|
|
|
// That didn't work, so try using GetDataHere.
|
|
FORMATETC fmt = {cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM};
|
|
STGMEDIUM stgm = {TYMED_ISTREAM, NULL, NULL};
|
|
stgm.pstm = pStm;
|
|
|
|
sc = pDataObject->GetDataHere(&fmt, &stgm);
|
|
if(sc)
|
|
{
|
|
// ignore errors and return a blank string
|
|
sc.Clear();
|
|
return sc;
|
|
}
|
|
|
|
STATSTG stagStg;
|
|
ZeroMemory(&stagStg, sizeof(stagStg));
|
|
|
|
sc = pStm->Stat(&stagStg, STATFLAG_NONAME); // do not need the name in the statistics.
|
|
if(sc)
|
|
return sc;
|
|
|
|
if(stagStg.cbSize.HighPart != 0)
|
|
return sc = E_UNEXPECTED;
|
|
|
|
// go back to the beginning of the stream
|
|
LARGE_INTEGER dlibMove = {0, 0};
|
|
sc = pStm->Seek(dlibMove, STREAM_SEEK_SET, NULL);
|
|
if(sc)
|
|
return sc;
|
|
|
|
BSTR bstrValue = ::SysAllocStringLen(NULL, stagStg.cbSize.LowPart / sizeof(OLECHAR)); // one character is automatically added
|
|
if(!bstrValue)
|
|
return sc = E_OUTOFMEMORY;
|
|
|
|
ULONG cbRead = 0;
|
|
sc = pStm->Read(bstrValue, stagStg.cbSize.LowPart, &cbRead);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// make sure that the count of characters is what was expected
|
|
if(cbRead != stagStg.cbSize.LowPart)
|
|
{
|
|
::SysFreeString(bstrValue);
|
|
return sc = E_UNEXPECTED;
|
|
}
|
|
|
|
// set the output parameter
|
|
*pbstrPropertyValue = bstrValue;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::GetNodetypeForListItem
|
|
*
|
|
* PURPOSE: Returns the node type for a list item.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeScope :
|
|
* BOOL bForScopeItem :
|
|
* LPARAM resultItemParam :
|
|
* PBSTR pbstrNodetype :
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CNodeCallback::GetNodetypeForListItem(HNODE hNodeScope, BOOL bForScopeItem, LPARAM resultItemParam, PBSTR pbstrNodetype)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetNodetypeForListItem"));
|
|
|
|
// check parameters
|
|
sc = ScCheckPointers(pbstrNodetype);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// initialize out parameter
|
|
*pbstrNodetype = NULL;
|
|
|
|
// convert the HNODE to a CNode *
|
|
CNode *pNodeScope = CNode::FromHandle(hNodeScope);
|
|
|
|
sc = ScCheckPointers(pNodeScope);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
IDataObjectPtr spDataObject;
|
|
|
|
bool bScopeItem;
|
|
sc = pNodeScope->ScGetDataObject(bForScopeItem, resultItemParam, bScopeItem, &spDataObject);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// at this point we should have a valid data object
|
|
sc = ScCheckPointers((LPDATAOBJECT)spDataObject);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScGetNodetype(spDataObject, pbstrNodetype);
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::ScGetNodetype
|
|
*
|
|
* PURPOSE: Static function - returns the nodetype of a data object as a string.
|
|
*
|
|
* PARAMETERS:
|
|
* IDataObject * pDataObject :
|
|
* PBSTR pbstrNodetype :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CNodeCallback::ScGetNodetype(IDataObject *pDataObject, PBSTR pbstrNodetype)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::ScGetNodetype"));
|
|
|
|
sc = ScCheckPointers(pDataObject, pbstrNodetype);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// init out parameter
|
|
*pbstrNodetype = NULL;
|
|
|
|
GUID guidNodetype = GUID_NULL;
|
|
|
|
sc = ExtractObjectTypeGUID(pDataObject, &guidNodetype);
|
|
if(sc)
|
|
return sc;
|
|
|
|
OLECHAR szSnapInGUID[40];
|
|
int iRet = StringFromGUID2(guidNodetype, szSnapInGUID, countof(szSnapInGUID));
|
|
|
|
if(0 == iRet)
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
// allocate the string, with the correct length.
|
|
*pbstrNodetype = ::SysAllocString(szSnapInGUID);
|
|
if(!*pbstrNodetype)
|
|
return (sc = E_OUTOFMEMORY);
|
|
|
|
return sc;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnSnapInHelp(CNode* pNode, BOOL bScope, MMC_COOKIE cookie)
|
|
{
|
|
if (bScope == FALSE && pNode->GetViewData()->IsVirtualList() == FALSE)
|
|
{
|
|
ASSERT(cookie != NULL);
|
|
CResultItem* pri = CResultItem::FromHandle(cookie);
|
|
|
|
if ((pri != NULL) && pri->IsScopeItem())
|
|
{
|
|
pNode = CNode::FromResultItem(pri);
|
|
ASSERT(pNode != NULL);
|
|
}
|
|
}
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
|
|
HRESULT hr = pCC->Notify(NULL, MMCN_SNAPINHELP, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CNodeCallback::OnContextHelp(CNode* pNode, BOOL bScope, MMC_COOKIE cookie)
|
|
{
|
|
ASSERT(pNode != NULL);
|
|
|
|
if (bScope == FALSE && pNode->GetViewData()->IsVirtualList() == FALSE)
|
|
{
|
|
ASSERT(cookie != NULL);
|
|
if(cookie == NULL || IS_SPECIAL_COOKIE(cookie))
|
|
return E_UNEXPECTED;
|
|
|
|
CResultItem* pri = CResultItem::FromHandle(cookie);
|
|
if (pri == NULL)
|
|
return (E_UNEXPECTED);
|
|
|
|
cookie = pri->GetSnapinData();
|
|
|
|
bScope = pri->IsScopeItem();
|
|
if (bScope == TRUE)
|
|
{
|
|
pNode = CNode::FromResultItem(pri);
|
|
ASSERT(pNode != NULL);
|
|
}
|
|
}
|
|
|
|
if (bScope == TRUE)
|
|
{
|
|
IDataObjectPtr spdtobj;
|
|
HRESULT hr = pNode->GetMTNode()->QueryDataObject(CCT_SCOPE, &spdtobj);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
if ( pCC == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
hr = pCC->Notify(spdtobj, MMCN_CONTEXTHELP, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
if ( pCC == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
IDataObjectPtr spdtobj;
|
|
HRESULT hr = pCC->QueryDataObject(cookie, CCT_RESULT, &spdtobj);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hr = pCC->Notify(spdtobj, MMCN_CONTEXTHELP, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::GetSnapinName
|
|
//
|
|
// Synopsis: Given the node get the snapin name
|
|
//
|
|
// Arguments: [hNode] - [in]
|
|
// [ppszName] - [out] ret val, caller should free using CoTaskMemFree
|
|
// [bValidName] - [out], is the name valid or not
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::GetSnapinName (/*[in]*/HNODE hNode, /*[out]*/LPOLESTR* ppszName, /*[out]*/ bool& bValidName)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::GetSnapinName"));
|
|
sc = ScCheckPointers( (void*) hNode, ppszName);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
bValidName = false;
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*ppszName = NULL;
|
|
|
|
CSnapIn* pSnapIn = pNode->GetPrimarySnapIn();
|
|
sc = ScCheckPointers (pSnapIn, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
WTL::CString strName;
|
|
sc = pSnapIn->ScGetSnapInName(strName);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
if (strName.IsEmpty())
|
|
return sc.ToHr();
|
|
|
|
USES_CONVERSION;
|
|
*ppszName = CoTaskDupString (T2COLE (strName));
|
|
if (*ppszName == NULL)
|
|
return ((sc = E_OUTOFMEMORY).ToHr());
|
|
|
|
bValidName = true;
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: OnColumnClicked
|
|
//
|
|
// Synopsis: Ask snapin if it wants to sort and do so.
|
|
//
|
|
// Arguments: [pNode] - CNode* owner of list view.
|
|
// [nCol] - column that is clicked (to sort on this column).
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// History: 07-27-1999 AnandhaG renamed OnSort to OnColumnClicked
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::OnColumnClicked(CNode* pNode, LONG_PTR nCol)
|
|
{
|
|
ASSERT(pNode != NULL);
|
|
|
|
pNode->OnColumnClicked(nCol);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnPrint(CNode* pNode, BOOL bScopePane, LPARAM lvData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnPrint"));
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if ((!bScopePane) && (LVDATA_MULTISELECT == lvData) )
|
|
{
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CMultiSelection* pMultiSel = pViewData->GetMultiSelection();
|
|
sc = ScCheckPointers(pMultiSel, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pMultiSel->ScVerbInvoked(MMC_VERB_PRINT);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
IDataObjectPtr spdtobj;
|
|
IDataObject *pdtobj = NULL;
|
|
|
|
bool bScopeItem;
|
|
sc = pNode->ScGetDataObject(bScopePane, lvData, bScopeItem, &pdtobj);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (! IS_SPECIAL_DATAOBJECT(pdtobj))
|
|
spdtobj = pdtobj;
|
|
|
|
CComponent *pComponent = pNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pComponent, pdtobj, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pComponent->Notify(pdtobj, MMCN_PRINT, 0, 0);
|
|
if (sc)
|
|
sc.TraceAndClear();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
HRESULT
|
|
CNodeCallback::OnEditTaskpad(CNode *pNode)
|
|
{
|
|
ASSERT(pNode);
|
|
|
|
ITaskCallbackPtr spTaskCallback = pNode->GetViewData()->m_spTaskCallback;
|
|
|
|
ASSERT(spTaskCallback.GetInterfacePtr());
|
|
|
|
return spTaskCallback->OnModifyTaskpad();
|
|
}
|
|
|
|
HRESULT
|
|
CNodeCallback::OnDeleteTaskpad(CNode *pNode)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnDeleteTaskpad"));
|
|
|
|
ASSERT(pNode);
|
|
sc = ScCheckPointers( pNode );
|
|
if ( sc )
|
|
return sc.ToHr();
|
|
|
|
ITaskCallbackPtr spTaskCallback = pNode->GetViewData()->m_spTaskCallback;
|
|
|
|
ASSERT(spTaskCallback.GetInterfacePtr());
|
|
|
|
// make the node dirty
|
|
CMTNode* pMTNode = pNode->GetMTNode();
|
|
sc = ScCheckPointers( pMTNode, E_UNEXPECTED );
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
pMTNode->SetDirty();
|
|
|
|
return spTaskCallback->OnDeleteTaskpad();
|
|
}
|
|
|
|
/* CNodeCallback::OnNewTaskpadFromHere
|
|
*
|
|
* PURPOSE: Displays property pages for a new taskpad
|
|
*
|
|
* PARAMETERS:
|
|
* CNode* pNode: The node that the taskpad should target to.
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*/
|
|
HRESULT
|
|
CNodeCallback::OnNewTaskpadFromHere(CNode* pNode)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnNewTaskpadFromHere"));
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CConsoleTaskpad taskpad (pNode);
|
|
|
|
CTaskpadWizard dlg(pNode, taskpad, TRUE /*fNew*/, 0, FALSE, pNode->GetViewData());
|
|
|
|
bool fStartTaskWizard = true;
|
|
sc = dlg.Show(pNode->GetViewData()->GetMainFrame() /*hWndParent*/, &fStartTaskWizard);
|
|
|
|
if (sc != S_OK)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(m_pCScopeTree, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
m_pCScopeTree->InsertConsoleTaskpad (&taskpad, pNode, fStartTaskWizard);
|
|
|
|
// modify the view settings for this node to ensure that the taskpad is shown after the reselect.
|
|
sc = pNode->ScSetTaskpadID(taskpad.GetID(), /*bSetViewSettingDirty*/ true);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
m_pCScopeTree->UpdateAllViews(VIEW_RESELECT, 0);
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
HRESULT CNodeCallback::OnRefresh(CNode* pNode, BOOL bScopePaneSelected, LPARAM lvData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnRefresh"));
|
|
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, bScopePaneSelected, lvData,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If result-pane cookie should be valid.
|
|
ASSERT( (bScopeItemSelected) || cookie != LVDATA_ERROR);
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return E_FAIL;
|
|
|
|
// Before refreshing this node, if the user has made
|
|
// changes to list view persist it.
|
|
CViewData* pVD = pSelectedNode->GetViewData();
|
|
ASSERT(pVD != NULL);
|
|
|
|
if (bScopeItemSelected)
|
|
{
|
|
ASSERT(pNode != NULL);
|
|
IDataObjectPtr spdtobj;
|
|
HRESULT hr = pSelectedNode->GetMTNode()->QueryDataObject(CCT_SCOPE, &spdtobj);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CMTNode* pMTNode = pSelectedNode->GetMTNode();
|
|
ASSERT(pMTNode != NULL);
|
|
|
|
LPARAM lScopeItem = CMTNode::ToScopeItem(pMTNode);
|
|
|
|
// Send notify to primary snap-in
|
|
pMTNode->AddRef();
|
|
pSelectedNode->GetPrimaryComponent()->Notify(spdtobj, MMCN_REFRESH, lScopeItem, 0);
|
|
if (pMTNode->Release() == 0)
|
|
return S_OK;
|
|
|
|
// If node has been expanded, then also send notify to all namespace
|
|
// extensions for this node
|
|
if (pMTNode->WasExpandedAtLeastOnce())
|
|
{
|
|
do // dummy loop
|
|
{
|
|
// Get the node-type of this node
|
|
GUID guidNodeType;
|
|
HRESULT hr = pMTNode->GetNodeType(&guidNodeType);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
// Get list of dynmaic extensions
|
|
LPCLSID pDynExtCLSID;
|
|
int cDynExt = pMTNode->GetDynExtCLSID(&pDynExtCLSID);
|
|
|
|
// Create and init namespace extension iterator
|
|
CExtensionsIterator it;
|
|
sc = it.ScInitialize(pMTNode->GetPrimarySnapIn(), guidNodeType, g_szNameSpace, pDynExtCLSID, cDynExt);
|
|
if (sc)
|
|
break;
|
|
|
|
CSnapInNode* pSINode = pSelectedNode->GetStaticParent();
|
|
ASSERT(pSINode != NULL);
|
|
|
|
// Send refresh to each extension's component
|
|
for (; it.IsEnd() == FALSE; it.Advance())
|
|
{
|
|
CComponent* pCC = pSINode->GetComponent(it.GetCLSID());
|
|
if (pCC == NULL)
|
|
continue;
|
|
|
|
HRESULT hr = pCC->Notify(spdtobj, MMCN_REFRESH, lScopeItem, 0);
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CComponent* pCC = pSelectedNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
|
|
if (IS_SPECIAL_LVDATA(lvData))
|
|
{
|
|
LPDATAOBJECT pdobj = (lvData == LVDATA_CUSTOMOCX) ?
|
|
DOBJ_CUSTOMOCX : DOBJ_CUSTOMWEB;
|
|
|
|
HRESULT hr = pCC->Notify(pdobj, MMCN_REFRESH, 0, 0);
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
else
|
|
{
|
|
IDataObjectPtr spdtobj;
|
|
HRESULT hr = pCC->QueryDataObject(cookie, CCT_RESULT, &spdtobj);
|
|
ASSERT(SUCCEEDED(hr));
|
|
if (FAILED(hr))
|
|
return hr;
|
|
pCC->Notify(spdtobj, MMCN_REFRESH, 0, 0);
|
|
}
|
|
}
|
|
|
|
// Set the view correctly using the persisted data.
|
|
do
|
|
{
|
|
if (NULL == pVD)
|
|
break;
|
|
|
|
// After the refresh the snapin could have deleted the pSelectedNode or
|
|
// could have moved the selection. While setting view-data we
|
|
// just need the currently selected node (the owner of the view
|
|
// which is not affected by temp selection) and set the view.
|
|
CNode* pSelNode = pVD->GetSelectedNode();
|
|
if (NULL == pSelNode)
|
|
break;
|
|
|
|
sc = pSelNode->ScRestoreSortFromPersistedData();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
} while ( FALSE );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
UINT GetRelation(CMTNode* pMTNodeSrc, CMTNode* pMTNodeDest)
|
|
{
|
|
if (pMTNodeSrc == pMTNodeDest)
|
|
return 1;
|
|
|
|
for(pMTNodeDest = pMTNodeDest->Parent();
|
|
pMTNodeDest;
|
|
pMTNodeDest = pMTNodeDest->Parent())
|
|
{
|
|
if (pMTNodeSrc == pMTNodeDest)
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::UpdatePasteButton(HNODE hNode, BOOL bScope, LPARAM lvData)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::UpdatePasteButton"));
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
bool bPasteAllowed = false;
|
|
// Update only when item is being selected.
|
|
sc = QueryPasteFromClipboard(hNode, bScope, lvData, bPasteAllowed);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pViewData->ScUpdateStdbarVerb (MMC_VERB_PASTE, TBSTATE_ENABLED, bPasteAllowed);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::ScInitializeTempVerbSetForMultiSel
|
|
//
|
|
// Synopsis: For given node, initialize the tempverbset object
|
|
// provided. For this create a multi-selection object
|
|
// initialize it (multiselection object finds out what is
|
|
// selected in resultpane and sends MMCN_SELECT to appropriate
|
|
// snapins) and compute the verb states for the temp-verbset object.
|
|
//
|
|
// Arguments: [pNode] - [in] owner of resultpane.
|
|
// [tempverb] - [in] Temp verb set object which is initialzied.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNodeCallback::ScInitializeTempVerbSetForMultiSel(CNode *pNode, CTemporaryVerbSet& tempVerb)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::ScInitializeTempVerbSetForMultiSel"));
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
ASSERT(pNode->IsInitialized() == TRUE);
|
|
|
|
// 1. Create a multi-selection object.
|
|
CMultiSelection* pMultiSelection = new CMultiSelection(pNode);
|
|
sc = ScCheckPointers(pMultiSelection, E_OUTOFMEMORY);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IDataObjectPtr spdobj;
|
|
|
|
// 2. Initialize it, (it finds out what is selected in resultpane
|
|
// gets dataobjects from appropriate snapins and sends snapins
|
|
// MMCN_SELECT notifications).
|
|
sc = pMultiSelection->Init();
|
|
if (sc)
|
|
goto Cleanup;
|
|
|
|
pMultiSelection->SetScopeTree(m_pCScopeTree);
|
|
|
|
sc = pMultiSelection->GetMultiSelDataObject(&spdobj);
|
|
if (sc)
|
|
goto Cleanup;
|
|
|
|
if (spdobj == NULL)
|
|
goto Cleanup;
|
|
|
|
// 3. Init the verbset object.
|
|
sc = tempVerb.ScInitializeForMultiSelection(pNode, /*bSelect*/ true);
|
|
if (sc)
|
|
goto Cleanup;
|
|
|
|
tempVerb.SetMultiSelection(pMultiSelection);
|
|
|
|
// 4. Compute the verbs that are set by snapin along with given context.
|
|
sc = tempVerb.ScComputeVerbStates();
|
|
|
|
if (sc)
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
pMultiSelection->Release();
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::_ScGetVerbState
|
|
//
|
|
// Synopsis: For given item (dataobject), the owner node see if given
|
|
// verb is set. A temp-verb-set object is created for this purpose.
|
|
//
|
|
// Arguments: [pNode] - [in]
|
|
// [verb] - [in]
|
|
// [pDOSel] - [in] Dataobject of the item whose verb we are interested.
|
|
// [bScopePane] - [in]
|
|
// [lResultCookie] - [in]
|
|
// [bMultiSelect] - [in]
|
|
// [bIsVerbSet] - [out] verb is set or not.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNodeCallback::_ScGetVerbState( CNode* pNode, MMC_CONSOLE_VERB verb, IDataObject* pDOSel,
|
|
BOOL bScopePane, LPARAM lResultCookie,
|
|
BOOL bMultiSelect, BOOL& bIsVerbSet)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::_GetVerbState"));
|
|
bIsVerbSet = FALSE;
|
|
|
|
sc = ScCheckPointers(pNode, pDOSel);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CComObject<CTemporaryVerbSet> stdVerbTemp;
|
|
|
|
if (bMultiSelect)
|
|
sc = ScInitializeTempVerbSetForMultiSel(pNode, stdVerbTemp);
|
|
else
|
|
sc = stdVerbTemp.ScInitialize(pDOSel, pNode, bScopePane, lResultCookie);
|
|
|
|
if (sc)
|
|
return sc;
|
|
|
|
stdVerbTemp.GetVerbState(verb, ENABLED, &bIsVerbSet);
|
|
|
|
return sc;
|
|
}
|
|
|
|
HRESULT
|
|
CNodeCallback::OnCutCopy(
|
|
CNode* pNode,
|
|
BOOL bScope,
|
|
LPARAM lvData,
|
|
BOOL bCut)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::OnCutCopy"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// get the object
|
|
IMMCClipboardDataObjectPtr spClipBoardDataObject;
|
|
bool bContainsItems = false;
|
|
sc = CMMCClipBoardDataObject::ScCreate( (bCut ? ACTION_CUT : ACTION_COPY),
|
|
pNode, bScope,
|
|
(lvData == LVDATA_MULTISELECT)/*bMultiSel*/,
|
|
lvData, &spClipBoardDataObject ,
|
|
bContainsItems);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If snapin has cut or copy then dataobject should have been added.
|
|
if (! bContainsItems)
|
|
return (sc = E_UNEXPECTED).ToHr();
|
|
|
|
// QI for IDataObject
|
|
IDataObjectPtr spDataObject = spClipBoardDataObject;
|
|
sc = ScCheckPointers( spDataObject, E_UNEXPECTED );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Put the dataobject on the clipboard.
|
|
sc = OleSetClipboard( spDataObject );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::OnProperties
|
|
//
|
|
// Synopsis: Bring property sheet for given item.
|
|
//
|
|
// Arguments: CNode* - The node that owns result pane.
|
|
// BOOL - If true bring propsheet of above node else use LVData.
|
|
// LPARAM - If bScope = FALSE then use this data to get the LVData
|
|
// and bring its property sheet.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::OnProperties(CNode* pNode, BOOL bScopePaneSelected, LPARAM lvData)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::OnProperties"));
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
// NOTE: All the code below should be moved into the CNode class
|
|
BOOL bScopeItemSelected = FALSE;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, bScopePaneSelected, lvData,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If result-pane cookie should be valid.
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return (sc = E_FAIL).ToHr();
|
|
|
|
if (bScopeItemSelected)
|
|
{
|
|
sc = ScDisplaySnapinNodePropertySheet(pSelectedNode);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
}
|
|
else
|
|
{
|
|
CViewData* pViewData = pSelectedNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (pViewData->HasList())
|
|
{
|
|
if (cookie == LVDATA_MULTISELECT)
|
|
{
|
|
sc = ScDisplayMultiSelPropertySheet(pSelectedNode);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
}
|
|
else
|
|
{
|
|
sc = ScDisplaySnapinLeafPropertySheet(pSelectedNode, cookie);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPDATAOBJECT pdobj = (pViewData->HasOCX() ) ? DOBJ_CUSTOMOCX : DOBJ_CUSTOMWEB;
|
|
CComponent* pCC = pSelectedNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
pCC->Notify(pdobj, MMCN_BTN_CLICK, 0, MMC_VERB_PROPERTIES);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CNodeCallback::OnFilterChange(CNode* pNode, LONG_PTR nCode, LPARAM nCol)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(pNode);
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
|
|
if (pCC != NULL)
|
|
{
|
|
HRESULT hr = pCC->Notify(DOBJ_NULL, MMCN_FILTER_CHANGE, nCode, nCol);
|
|
return hr;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT CNodeCallback::OnFilterBtnClick(CNode* pNode, LONG_PTR nCol, LPRECT pRect)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(pNode, pRect);
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
|
|
if (pCC != NULL)
|
|
{
|
|
HRESULT hr = pCC->Notify(DOBJ_NULL, MMCN_FILTERBTN_CLICK, nCol, (LPARAM)pRect);
|
|
return hr;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::IsExpandable(HNODE hNode)
|
|
{
|
|
MMC_TRY
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
ASSERT(pNode != NULL);
|
|
|
|
CMTNode* pMTNode = pNode->GetMTNode();
|
|
ASSERT(pMTNode != NULL);
|
|
|
|
return pMTNode->IsExpandable();
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
HRESULT _GetConsoleVerb(CNode* pNode, LPCONSOLEVERB* ppConsoleVerb)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2(pNode, ppConsoleVerb);
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
ASSERT(pCC != NULL);
|
|
if (pCC == NULL)
|
|
return E_FAIL;
|
|
|
|
IFramePrivate* pIFP = pCC->GetIFramePrivate();
|
|
ASSERT(pIFP != NULL);
|
|
if (pIFP == NULL)
|
|
return E_FAIL;
|
|
|
|
IConsoleVerbPtr spConsoleVerb;
|
|
hr = pIFP->QueryConsoleVerb(&spConsoleVerb);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppConsoleVerb = spConsoleVerb.Detach();
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::GetConsoleVerb(HNODE hNode, LPCONSOLEVERB* ppConsoleVerb)
|
|
{
|
|
MMC_TRY
|
|
|
|
ASSERT(ppConsoleVerb != NULL);
|
|
|
|
return _GetConsoleVerb(CNode::FromHandle(hNode), ppConsoleVerb);
|
|
|
|
MMC_CATCH
|
|
}
|
|
|
|
|
|
|
|
// lCookie valid if both bScope & bMultiSel are FALSE.
|
|
// lCookie is the index\lParam for virtual\regular LV
|
|
STDMETHODIMP
|
|
CNodeCallback::GetDragDropDataObject(
|
|
HNODE hNode,
|
|
BOOL bScope,
|
|
BOOL bMultiSel,
|
|
LONG_PTR lvData,
|
|
LPDATAOBJECT* ppDataObject,
|
|
bool& bCopyAllowed,
|
|
bool& bMoveAllowed)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetDragDropDataObject"));
|
|
|
|
// init allowed op's to false
|
|
bCopyAllowed = false;
|
|
bMoveAllowed = false;
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers(ppDataObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// init out parameter;
|
|
*ppDataObject = NULL;
|
|
|
|
// get the object
|
|
IMMCClipboardDataObjectPtr spClipBoardDataObject;
|
|
bool bContainsItems = false;
|
|
sc = CMMCClipBoardDataObject::ScCreate( ACTION_DRAG,
|
|
CNode::FromHandle(hNode),
|
|
bScope, bMultiSel, lvData,
|
|
&spClipBoardDataObject,
|
|
bContainsItems );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// We asked for drag&drop dataobject. If snapin does not support cut/copy then
|
|
// the dataobjects will not be added which is not an error.
|
|
if (! bContainsItems)
|
|
return sc.ToHr();
|
|
|
|
// QI for IDataObject
|
|
IDataObjectPtr spDataObject = spClipBoardDataObject;
|
|
sc = ScCheckPointers( spDataObject, E_UNEXPECTED );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// inspect data objects included to see what operations are allowed
|
|
// (note: (spDataObject==valid) -> (spClipBoardDataObject==valid) )
|
|
DWORD dwCount = 0;
|
|
sc = spClipBoardDataObject->GetCount( &dwCount );
|
|
for ( DWORD dwIdx = 0; dwIdx < dwCount; dwIdx ++ )
|
|
{
|
|
IDataObjectPtr spSnapinDO;
|
|
DWORD dwOptions = 0;
|
|
sc = spClipBoardDataObject->GetDataObject( dwIdx, &spSnapinDO, &dwOptions );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// claculate allowed operations
|
|
bCopyAllowed = bCopyAllowed || ( dwOptions & COPY_ALLOWED );
|
|
bMoveAllowed = bMoveAllowed || ( dwOptions & MOVE_ALLOWED );
|
|
|
|
// enabling is inclusive, so very few tests are required
|
|
if ( bCopyAllowed && bMoveAllowed )
|
|
break;
|
|
}
|
|
|
|
// return data object
|
|
*ppDataObject = spDataObject.Detach();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::ScExtractLVData
|
|
//
|
|
// Synopsis: If listview item is selected, see if it is a scope item
|
|
// in non-virtual listview (virtual listviews cannot have
|
|
// scope items in them). If so extract that scope item else
|
|
// the cookie of result item.
|
|
//
|
|
// Arguments: [pNode] - [in, out] if scope item is selected in resultpane, then
|
|
// will contain this scope item on return.
|
|
// [bScope] - [in, out] Is scope item currently selected item (in scope or
|
|
// result pane).
|
|
// [lvData] - [in] LVDATA
|
|
// [cookie] - [in] lParam of result item.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNodeCallback::ScExtractLVData(CNode* pNodeViewOwner,
|
|
BOOL bScopePaneSelected,
|
|
LONG_PTR lvData,
|
|
CNode** ppSelectedNode,
|
|
BOOL& bScopeItemSelected,
|
|
MMC_COOKIE& cookie)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::ScExtractLVData"));
|
|
sc = ScCheckPointers(pNodeViewOwner, ppSelectedNode);
|
|
if (sc)
|
|
return sc;
|
|
|
|
*ppSelectedNode = NULL;
|
|
bScopeItemSelected = bScopePaneSelected;
|
|
*ppSelectedNode = pNodeViewOwner;
|
|
|
|
if (bScopePaneSelected)
|
|
{
|
|
cookie = lvData;
|
|
return sc;
|
|
}
|
|
|
|
// Scope pane is not selected.
|
|
CViewData *pViewData = pNodeViewOwner->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
cookie = lvData;
|
|
|
|
if (IS_SPECIAL_LVDATA(lvData))
|
|
{
|
|
if (lvData == LVDATA_BACKGROUND)
|
|
bScopeItemSelected = TRUE;
|
|
}
|
|
else if (! pViewData->IsVirtualList())
|
|
{
|
|
CResultItem* pri = CResultItem::FromHandle (lvData);
|
|
sc = ScCheckPointers(pri, E_UNEXPECTED);
|
|
if (sc)
|
|
{
|
|
cookie = LVDATA_ERROR;
|
|
return sc;
|
|
}
|
|
|
|
if (pri->IsScopeItem())
|
|
{
|
|
bScopeItemSelected = TRUE;
|
|
*ppSelectedNode = CNode::FromResultItem(pri);
|
|
sc = ScCheckPointers(*ppSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
cookie = -1;
|
|
}
|
|
else
|
|
{
|
|
cookie = pri->GetSnapinData();
|
|
}
|
|
|
|
ASSERT(!IS_SPECIAL_LVDATA(lvData) || !bScopeItemSelected);
|
|
}
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CNodeCallback::GetTaskEnumerator(
|
|
HNODE hNode,
|
|
LPCOLESTR pszTaskGroup,
|
|
IEnumTASK** ppEnumTask)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG3(hNode, pszTaskGroup, ppEnumTask);
|
|
|
|
*ppEnumTask = NULL; // init
|
|
|
|
// convert to real type
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
|
|
return pNode->GetTaskEnumerator(CComBSTR(pszTaskGroup), ppEnumTask);
|
|
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNodeCallback::GetListPadInfo(HNODE hNode, IExtendTaskPad* pExtendTaskPad,
|
|
LPCOLESTR szTaskGroup, MMC_ILISTPAD_INFO* pIListPadInfo)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(hNode);
|
|
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
return pNode->GetListPadInfo(pExtendTaskPad, CComBSTR(szTaskGroup), pIListPadInfo);
|
|
}
|
|
|
|
HRESULT CNodeCallback::OnGetPrimaryTask(CNode* pNode, LPARAM param)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(pNode);
|
|
|
|
IExtendTaskPad** ppExtendTaskPad = reinterpret_cast<IExtendTaskPad**>(param);
|
|
return pNode->OnGetPrimaryTask(ppExtendTaskPad);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CNodeCallback::UpdateWindowLayout(LONG_PTR lViewData, long lToolbarsDisplayed)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG(lViewData);
|
|
|
|
CViewData* pVD = reinterpret_cast<CViewData*>(lViewData);
|
|
pVD->UpdateToolbars(lToolbarsDisplayed);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNodeCallback::PreLoad(HNODE hNode)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::PreLoad"));
|
|
|
|
// parameter check
|
|
sc = ScCheckPointers( hNode );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode* pNode = CNode::FromHandle (hNode);
|
|
if (pNode->IsStaticNode() == FALSE ||
|
|
pNode->IsInitialized() == TRUE)
|
|
return (sc = S_FALSE).ToHr();
|
|
|
|
// if the node is:
|
|
// 1. a snapin node;
|
|
// 2. marked as "PreLoad"; and,
|
|
// 3. not initialized yet.
|
|
// if all three, then send 'em a notify containing their HSCOPEITEM
|
|
CMTNode* pMTNode = pNode->GetMTNode();
|
|
sc = ScCheckPointers( pMTNode, E_FAIL );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CMTSnapInNode* pMTSnapInNode = dynamic_cast<CMTSnapInNode*>(pMTNode);
|
|
sc = ScCheckPointers( pMTSnapInNode, E_UNEXPECTED );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (!pMTSnapInNode->IsPreloadRequired())
|
|
return (sc = S_FALSE).ToHr();
|
|
|
|
if (pMTNode->IsInitialized() == FALSE)
|
|
{
|
|
sc = pMTSnapInNode->Init();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
|
|
//
|
|
// If the snap-in needs to be preloaded, the IComponent also needs
|
|
// to be init so that the sanpin can insert icons in the result
|
|
// pane if the parent node is selected in the scope pane.
|
|
//
|
|
|
|
ASSERT(pNode->IsInitialized() == FALSE);
|
|
sc = _InitializeNode(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
STDMETHODIMP CNodeCallback::SetTaskpad(HNODE hNodeSelected, GUID *pGuidTaskpad)
|
|
{
|
|
ASSERT(hNodeSelected != NULL);
|
|
ASSERT(pGuidTaskpad != NULL);
|
|
|
|
CNode *pNode = CNode::FromHandle(hNodeSelected);
|
|
|
|
// See ScSetViewExtension for more info on parameters in the call.
|
|
HRESULT hr = pNode->ScSetViewExtension(pGuidTaskpad,
|
|
/*bUseDefaultTaskPad*/ false,
|
|
/*bSetViewSettingDirty*/ true).ToHr();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNodeCallback::OnCustomizeView (LONG_PTR lViewData)
|
|
{
|
|
::OnCustomizeView ((CViewData*) lViewData);
|
|
return (S_OK);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::SetViewSettings
|
|
//
|
|
// Synopsis: Modify the view settings data that is persisted.
|
|
//
|
|
// Arguments: [nViewID] - [in] the view id.
|
|
// [hbm] - [in] bookmark.
|
|
// [hvs] - [in] view-settings.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::SetViewSettings(int nViewID, HBOOKMARK hbm, HVIEWSETTINGS hvs)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::SetViewSettings"));
|
|
sc = ScCheckPointers( (void*)hbm, (void*) hvs);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
|
|
CViewSettings *pViewSettings = reinterpret_cast<CViewSettings *>(hvs);
|
|
CBookmark *pBookmark = reinterpret_cast<CBookmark*> (hbm);
|
|
sc = CNode::ScSetFavoriteViewSettings(nViewID, *pBookmark, *pViewSettings);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::ExecuteScopeItemVerb
|
|
//
|
|
// Synopsis: Invoke the given verb with given context. Also make sure
|
|
// the verb is enabled by snapin for this context.
|
|
//
|
|
// Arguments: [verb] - The verb to be invoked.
|
|
// [hNode] - The node for which above verb is invoked.
|
|
// [lpszNewName] - For "rename" represents new name.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::ExecuteScopeItemVerb (MMC_CONSOLE_VERB verb, HNODE hNode, LPOLESTR lpszNewName)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::ExecuteScopeItemVerb"));
|
|
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// Get data object for the item.
|
|
IDataObjectPtr spDataObject;
|
|
sc = pNode->QueryDataObject(CCT_SCOPE, &spDataObject);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
BOOL bEnabled = FALSE;
|
|
// see if the verb is enabled by the snapin.
|
|
sc = _ScGetVerbState( pNode, verb, spDataObject,
|
|
/*bScopePane*/TRUE, /*lResultCookie = */ NULL,
|
|
/*bMultiSel*/FALSE, bEnabled);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (! bEnabled) // Verb not enabled.
|
|
return (sc = ScFromMMC(MMC_E_TheVerbNotEnabled)).ToHr();
|
|
|
|
switch(verb)
|
|
{
|
|
case MMC_VERB_PROPERTIES:
|
|
sc = OnProperties(pNode, /*bScope*/ TRUE, /*LPARAM*/ NULL);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
case MMC_VERB_DELETE:
|
|
sc = OnDelete(pNode, /*bScope*/ TRUE, /*LPARAM*/ NULL);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
case MMC_VERB_REFRESH:
|
|
sc = OnRefresh(pNode, /*bScope*/ TRUE, /*LPARAM*/ NULL);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
case MMC_VERB_RENAME:
|
|
{
|
|
// To call Rename we must first initialize SELECTIONINFO.
|
|
SELECTIONINFO selInfo;
|
|
ZeroMemory(&selInfo, sizeof(selInfo));
|
|
selInfo.m_bScope = TRUE;
|
|
selInfo.m_eCmdID = MMC_VERB_RENAME;
|
|
|
|
sc = OnRename(pNode, &selInfo, lpszNewName);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
break;
|
|
|
|
case MMC_VERB_COPY:
|
|
sc = OnCutCopy(pNode, /*bScope*/ TRUE, NULL, /*bCut*/ FALSE);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
default:
|
|
sc = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::ExecuteResultItemVerb
|
|
//
|
|
// Synopsis: Invoke the given verb with given context. Also make sure
|
|
// the verb is enabled by snapin for this context.
|
|
//
|
|
// Arguments: [verb] - The verb to be invoked.
|
|
// [hNode] - The node that owns result pane now.
|
|
// [lvData] - The list view selection context.
|
|
// [lpszNewName] - For "rename" represents new name else NULL.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::ExecuteResultItemVerb (MMC_CONSOLE_VERB verb, HNODE hNode, LPARAM lvData, LPOLESTR lpszNewName)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::ExecuteResultItemVerb"));
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
// We need to see if the given verb is enabled by the snapin. We need
|
|
// dataobject for given context for this. So get the context by calling
|
|
// ScExtractLVData().
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, /*bScopePaneSelected*/ FALSE, lvData,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Cookie should be valid for result pane.
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return (sc = E_FAIL).ToHr();
|
|
|
|
BOOL bMultiSelect = (LVDATA_MULTISELECT == lvData);
|
|
if (bMultiSelect)
|
|
cookie = MMC_MULTI_SELECT_COOKIE;
|
|
|
|
// Depending on whether this is scope item in result pane or result item
|
|
// ask ComponentData or Component the data object.
|
|
IDataObjectPtr spDataObject;
|
|
if (bScopeItemSelected)
|
|
{
|
|
sc = pSelectedNode->QueryDataObject (CCT_SCOPE, &spDataObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
else
|
|
{
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pCC->QueryDataObject(cookie, CCT_RESULT, &spDataObject);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
BOOL bEnabled = FALSE;
|
|
// See if the verb is enabled for this selection.
|
|
sc = _ScGetVerbState( pSelectedNode , verb, spDataObject,
|
|
/*bScopePaneSelected*/ FALSE, lvData,
|
|
bMultiSelect, bEnabled);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (! bEnabled) // Verb not enabled.
|
|
return (sc = ScFromMMC(MMC_E_TheVerbNotEnabled)).ToHr();
|
|
|
|
|
|
switch(verb)
|
|
{
|
|
case MMC_VERB_PROPERTIES:
|
|
sc = OnProperties(pNode, /*bScope*/ FALSE, /*LPARAM*/ lvData);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
case MMC_VERB_DELETE:
|
|
sc = OnDelete(pNode, /*bScope*/ FALSE, /*LPARAM*/ lvData);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
case MMC_VERB_REFRESH:
|
|
sc = OnRefresh(pNode, /*bScope*/ FALSE, /*LPARAM*/ lvData);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
case MMC_VERB_RENAME:
|
|
{
|
|
// For Rename we should also call ScExtractLVData before calling OnRename.
|
|
// To call Rename we must first initialize SELECTIONINFO.
|
|
SELECTIONINFO selInfo;
|
|
ZeroMemory(&selInfo, sizeof(selInfo));
|
|
selInfo.m_bScope = bScopeItemSelected;
|
|
selInfo.m_lCookie = cookie;
|
|
selInfo.m_eCmdID = MMC_VERB_RENAME;
|
|
|
|
sc = OnRename(pNode, &selInfo, lpszNewName);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
break;
|
|
|
|
case MMC_VERB_COPY:
|
|
sc = OnCutCopy(pNode, /*bScope*/ FALSE, lvData, /*bCut*/ FALSE);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
break;
|
|
|
|
default:
|
|
sc = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* FUNCTION: CNodeCallback::QueryCompDataDispatch
|
|
*
|
|
* PURPOSE: Get the disp interface for given scope node object from snapin.
|
|
*
|
|
* PARAMETERS:
|
|
* PNODE - The Node object for which the disp interface is required.
|
|
* PPDISPATCH [out] - Disp interface pointer returned by snapin.
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CNodeCallback::QueryCompDataDispatch(PNODE pNode, PPDISPATCH ppScopeNodeObject)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::QueryCompDataDispInterface"));
|
|
sc = ScCheckPointers(m_pCScopeTree);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
CMTNode *pMTNode = NULL;
|
|
sc = m_pCScopeTree->ScGetNode(pNode, &pMTNode);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pMTNode->ScQueryDispatch(CCT_SCOPE, ppScopeNodeObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::QueryComponentDispatch
|
|
//
|
|
// Synopsis: Get the disp interface for given item in resultpane from snapin.
|
|
//
|
|
// Arguments:
|
|
// HNODE - The Scope Node which owns result pane.
|
|
// LVDATA - The LVDATA of selected item
|
|
// PPDISPATCH [out] - Disp interface pointer returned by snapin.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::QueryComponentDispatch (HNODE hNode,
|
|
LPARAM lvData,
|
|
PPDISPATCH SelectedObject)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::QueryComponentDispatch"));
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, /*bScopePaneSelected*/ FALSE, lvData,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
/*
|
|
* In case of multiselection, set cookie to MMC_MULTI_SELECT_COOKIE
|
|
* which snapins can understand.
|
|
*/
|
|
BOOL bMultiSelect = (LVDATA_MULTISELECT == lvData);
|
|
if (bMultiSelect)
|
|
{
|
|
cookie = MMC_MULTI_SELECT_COOKIE;
|
|
ASSERT(bScopeItemSelected == false);
|
|
}
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If result-pane cookie should be valid.
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return (sc = E_FAIL).ToHr();
|
|
|
|
// Scope item is selected in result pane.
|
|
if (bScopeItemSelected)
|
|
{
|
|
CMTNode* pMTNode = pSelectedNode->GetMTNode();
|
|
sc = ScCheckPointers(pMTNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pMTNode->ScQueryDispatch(CCT_SCOPE, SelectedObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
else
|
|
{
|
|
CComponent* pCC = pSelectedNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pCC->ScQueryDispatch(cookie, CCT_RESULT, SelectedObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNodeCallback::ShowColumn
|
|
*
|
|
* PURPOSE: Shows/hides the column. Implements both UI part as snapin notifications
|
|
* Used as helper implementing functionality for Column com object.
|
|
* [uses CNode to perform the task]
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeSelected - scope node - oener of the view
|
|
* int iColIndex - column index to perform action on
|
|
* bool bVisible - show/hide flag for operation
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
STDMETHODIMP CNodeCallback::ShowColumn(HNODE hNodeSelected, int iColIndex, bool bShow)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::ShowColumn"));
|
|
|
|
// get CNode pointer
|
|
CNode* pNode = CNode::FromHandle(hNodeSelected);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pNode->ScShowColumn(iColIndex, bShow);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNodeCallback::GetSortColumn
|
|
*
|
|
* PURPOSE: retrieves index of sort column
|
|
* Used as helper implementing functionality for Column com object.
|
|
* [uses CNode to perform the task]
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeSelected - scope node - oener of the view
|
|
* int *piSortCol - resulting index
|
|
*
|
|
* RETURNS:
|
|
* SC - result code
|
|
*
|
|
\***************************************************************************/
|
|
STDMETHODIMP CNodeCallback::GetSortColumn(HNODE hNodeSelected, int *piSortCol)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetSortColumn"));
|
|
|
|
// get CNode pointer
|
|
CNode* pNode = CNode::FromHandle(hNodeSelected);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pNode->ScGetSortColumn(piSortCol);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNodeCallback::SetSortColumn
|
|
*
|
|
* PURPOSE: sorts result data by specified column
|
|
* Used as helper implementing functionality for Column com object.
|
|
* [uses CNode to perform the task]
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeSelected - scope node - oener of the view
|
|
* int iSortCol - sort column index
|
|
* bool bAscending - sort order
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
\***************************************************************************/
|
|
STDMETHODIMP CNodeCallback::SetSortColumn(HNODE hNodeSelected, int iSortCol, bool bAscending)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::SetSortColumn"));
|
|
|
|
// get CNode pointer
|
|
CNode* pNode = CNode::FromHandle(hNodeSelected);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pNode->ScSetSortColumn(iSortCol, bAscending);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNodeCallback::RestoreResultView
|
|
*
|
|
* PURPOSE: Called by conui to restore the result view with given data.
|
|
* This method asks snapin (indirectly) to restore the view.
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNode - scope node - oener of the view
|
|
* CResultViewType rvt - The resultview type data to be used for restore.
|
|
*
|
|
* RETURNS:
|
|
* HRESULT S_OK if snapin used the data to restore the view
|
|
* S_FALSE if snapin refused to restore.
|
|
*
|
|
\***************************************************************************/
|
|
STDMETHODIMP CNodeCallback::RestoreResultView(HNODE hNode, const CResultViewType& rvt)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::RestoreResultView"));
|
|
|
|
// get CNode pointer
|
|
CNode* pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pNode->ScRestoreResultView(rvt);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CNodeCallback::GetNodeViewExtensions
|
|
*
|
|
* PURPOSE: Forwards calls to CNode to collect view extensions
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNodeScope
|
|
* CViewExtInsertIterator it
|
|
*
|
|
* RETURNS:
|
|
* HRESULT - result code
|
|
*
|
|
\***************************************************************************/
|
|
STDMETHODIMP CNodeCallback::GetNodeViewExtensions(/*[in]*/ HNODE hNodeScope, /*[out]*/ CViewExtInsertIterator it)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::GetNodeViewExtensions"));
|
|
|
|
// get CNode pointer
|
|
CNode* pNode = CNode::FromHandle(hNodeScope);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pNode->ScGetViewExtensions(it);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::SaveColumnInfoList
|
|
//
|
|
// Synopsis: The column-data for given node has changed persist the
|
|
// new column data.
|
|
//
|
|
// Arguments: [hNode] - Node that owns result-pane.
|
|
// [columnsList] - The new column-data.
|
|
//
|
|
// Note: The sort-data is not given by this call, so do not change it.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::SaveColumnInfoList (HNODE hNode, const CColumnInfoList& columnsList)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::SaveColumnInfoList"));
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CLSID guidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = pNode->ScGetSnapinAndColumnDataID(guidSnapin, columnID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Get the old persisted column data. This contains width values
|
|
// for hidden columns which is used if the column is un-hidden.
|
|
CColumnSetData columnSetData;
|
|
BOOL bRet = pViewData->RetrieveColumnData(guidSnapin, *pColID, columnSetData);
|
|
|
|
if (bRet)
|
|
{
|
|
CColumnInfoList* pColInfoListOld = columnSetData.get_ColumnInfoList();
|
|
|
|
if (columnsList.size() == pColInfoListOld->size())
|
|
{
|
|
// Merge the persisted column width for hidden columns
|
|
// to the new list created.
|
|
CColumnInfoList::iterator itColInfo1;
|
|
CColumnInfoList::iterator itColInfo2;
|
|
|
|
for (itColInfo1 = pColInfoListOld->begin(), itColInfo2 = columnsList.begin();
|
|
itColInfo1 != pColInfoListOld->end(); ++itColInfo1, ++itColInfo2)
|
|
{
|
|
if (itColInfo2->IsColHidden())
|
|
itColInfo2->SetColWidth(itColInfo1->GetColWidth());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the new columns list in column-set-data.
|
|
columnSetData.set_ColumnInfoList(columnsList);
|
|
|
|
// Save the data.
|
|
sc = pViewData->ScSaveColumnInfoList(guidSnapin, *pColID, columnsList);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::GetPersistedColumnInfoList
|
|
//
|
|
// Synopsis: The list-view requests the column-data (no sort data) to setup the headers
|
|
// before any items are inserted into the list-view.
|
|
// (Note: Modify headers after all columns are inserted before any list-view
|
|
// items will be inserted to reduce flicker).
|
|
//
|
|
// Arguments: [hNode] - node that owns result-pane for which column-data is needed.
|
|
// [pColumnsList] - [out param], the column-data.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::GetPersistedColumnInfoList (HNODE hNode, CColumnInfoList *pColumnsList)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::GetPersistedColumnInfoList"));
|
|
sc = ScCheckPointers(hNode, pColumnsList);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CLSID guidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = pNode->ScGetSnapinAndColumnDataID(guidSnapin, columnID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Get the old persisted column data. This contains width values
|
|
// for hidden columns which is used if the column is un-hidden.
|
|
CColumnSetData columnSetData;
|
|
BOOL bRet = pViewData->RetrieveColumnData(guidSnapin, *pColID, columnSetData);
|
|
|
|
if (!bRet)
|
|
return (sc = S_FALSE).ToHr();
|
|
|
|
CColumnInfoList *pColListOriginal = columnSetData.get_ColumnInfoList();
|
|
if (!pColListOriginal)
|
|
return (sc = S_FALSE).ToHr();
|
|
|
|
*pColumnsList = *pColListOriginal;
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::DeletePersistedColumnData
|
|
//
|
|
// Synopsis: The column data for given node is invalid, remove it.
|
|
//
|
|
// Arguments: [hNode] - The node for which the data is invalid.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
HRESULT CNodeCallback::DeletePersistedColumnData(HNODE hNode)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::DeletePersistedColumnData"));
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CViewData *pViewData = pNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CLSID guidSnapin;
|
|
CXMLAutoBinary columnID;
|
|
sc = pNode->ScGetSnapinAndColumnDataID(guidSnapin, columnID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CXMLBinaryLock sLock(columnID);
|
|
SColumnSetID* pColID = NULL;
|
|
sc = sLock.ScLock(&pColID);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pColID, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Get the old persisted column data. This contains width values
|
|
// for hidden columns which is used if the column is un-hidden.
|
|
pViewData->DeleteColumnData(guidSnapin, *pColID);
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::DoesAboutExist
|
|
//
|
|
// Synopsis: See if about information exists for given node's snapin.
|
|
//
|
|
// Arguments: [hNode] -
|
|
// [pbAboutExists] - out param, ptr to bool, true if about exists.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::DoesAboutExist (HNODE hNode, bool *pbAboutExists)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::DoesAboutExist"));
|
|
sc = ScCheckPointers(hNode, pbAboutExists);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*pbAboutExists = false;
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// No about for console root eventhough it is a Folder snapin.
|
|
if (pNode->IsConsoleRoot())
|
|
return sc.ToHr();
|
|
|
|
CLSID clsidAbout;
|
|
const CLSID& clsidSnapin = pNode->GetPrimarySnapInCLSID();
|
|
SC scNoTrace = ScGetAboutFromSnapinCLSID(clsidSnapin, clsidAbout);
|
|
if (scNoTrace)
|
|
return scNoTrace.ToHr();
|
|
|
|
CSnapinAbout snapinAbout;
|
|
snapinAbout.GetSnapinInformation(clsidAbout);
|
|
sc = snapinAbout.GetObjectStatus();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*pbAboutExists = true;
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::ShowAboutInformation
|
|
//
|
|
// Synopsis: Given the context of currently selected item.
|
|
// Show its about information.
|
|
//
|
|
// Arguments: [hNode] - scope node that owns result pane.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::ShowAboutInformation (HNODE hNode)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::ShowAboutInformation"));
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CLSID clsidAbout;
|
|
const CLSID& clsidSnapin = pNode->GetPrimarySnapInCLSID();
|
|
sc = ScGetAboutFromSnapinCLSID(clsidSnapin, clsidAbout);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CSnapinAbout snapinAbout;
|
|
snapinAbout.GetSnapinInformation(clsidAbout);
|
|
|
|
USES_CONVERSION;
|
|
tstring szSnapinName;
|
|
if (GetSnapinNameFromCLSID(clsidSnapin, szSnapinName))
|
|
snapinAbout.SetSnapinName(T2COLE(szSnapinName.data()));
|
|
|
|
sc = snapinAbout.GetObjectStatus();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
snapinAbout.ShowAboutBox();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CNodeCallback::ExecuteShellCommand
|
|
*
|
|
* PURPOSE: Executes a shell command with the specified parameters in the
|
|
* specified directory with the correct window size
|
|
*
|
|
* PARAMETERS:
|
|
* HNODE hNode :
|
|
* BSTR Command :
|
|
* BSTR Directory :
|
|
* BSTR Parameters :
|
|
* BSTR WindowState :
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CNodeCallback::ExecuteShellCommand(HNODE hNode, BSTR Command, BSTR Directory, BSTR Parameters, BSTR WindowState)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CNodeCallback::ExecuteShellCommand"));
|
|
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = pNode->ScExecuteShellCommand(Command, Directory, Parameters, WindowState);
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::QueryPasteFromClipboard
|
|
//
|
|
// Synopsis: Given the context of paste target, get the clipboard dataobject
|
|
// and see if target allows paste.
|
|
//
|
|
// Arguments: [hNode] -
|
|
// [bScope] -
|
|
// [lCookie] - All above params describe paste target context.
|
|
// [bPasteAllowed] - [out]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::QueryPasteFromClipboard (HNODE hNode, BOOL bScope, LPARAM lCookie, bool& bPasteAllowed)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::QueryPasteFromClipboard"));
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// 1. Get the current dataobject from clipboard.
|
|
IDataObjectPtr spDOPaste;
|
|
sc = OleGetClipboard(&spDOPaste);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(spDOPaste, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
bool bCopyOperatationIsDefault = false; /*unused*/
|
|
|
|
sc = QueryPaste(hNode, bScope, lCookie, spDOPaste, bPasteAllowed, bCopyOperatationIsDefault);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::QueryPaste
|
|
//
|
|
// Synopsis: Given the context for current selection which is the target
|
|
// for paste (or drop). Find out it can paste given dataobject.
|
|
//
|
|
// Arguments: [hNode] - The node owning the view.
|
|
// [bScope] - Selection on Scope or Result pane.
|
|
// [lCookie] - If result pane selected the cookie for selected result item.
|
|
// [pDataObjectToPaste] - The dataobject to be pasted.
|
|
// [bPasteAllowed] - [out param], paste was permitted or not.
|
|
// [bCopyOperatationIsDefault] - [out param], is copy default operation (for r-click&l-click drag&drop)
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::QueryPaste (HNODE hNode, BOOL bScopePaneSelected, LPARAM lCookie,
|
|
IDataObject *pDataObjectToPaste,
|
|
bool& bPasteAllowed, bool& bCopyOperatationIsDefault)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::NewQueryPaste"));
|
|
bPasteAllowed = false;
|
|
sc = ScCheckPointers(hNode, pDataObjectToPaste);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If result-pane cookie should be valid.
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, bScopePaneSelected, lCookie,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return (sc = E_FAIL).ToHr();
|
|
|
|
CViewData *pViewData = pSelectedNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// Do not allow paste into OCX/WEB/Multiselection
|
|
// We can allow paste into OCX/WEB if we expose IMMCClipboardDataObject
|
|
// interface. But paste into Multiselection should not be allowed as
|
|
// it is not intuitive.
|
|
if ( (!bScopeItemSelected) && IS_SPECIAL_COOKIE(lCookie))
|
|
return sc.ToHr();
|
|
|
|
/*
|
|
* In MMC1.2 the drop target is always scope node. In MMC2.0
|
|
* it can be any result item. If the snapin has RVTI_LIST_OPTIONS_ALLOWPASTE
|
|
* set, then we need to provide proper parameters to below _GetVerbState.
|
|
*/
|
|
if ( (bScopeItemSelected == FALSE) && (! (RVTI_LIST_OPTIONS_ALLOWPASTE & pViewData->GetListOptions())) )
|
|
return sc.ToHr();
|
|
|
|
IDataObjectPtr spTargetDataObject;
|
|
sc = pSelectedNode->ScGetDropTargetDataObject(bScopeItemSelected, lCookie, &spTargetDataObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(spTargetDataObject, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
BOOL bFlag = FALSE;
|
|
sc = _ScGetVerbState(pSelectedNode, MMC_VERB_PASTE, spTargetDataObject,
|
|
bScopeItemSelected, lCookie, /*bMultiSel*/FALSE, bFlag);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
if (!bFlag)
|
|
return sc.ToHr();
|
|
|
|
// QI to see if it is MMC's data object
|
|
IMMCClipboardDataObjectPtr spMMCClipboardDataObj = pDataObjectToPaste;
|
|
|
|
if (spMMCClipboardDataObj)
|
|
{
|
|
// This is our own dataobject.
|
|
|
|
// 3. Get how, where it is created, and how many snapin objects are there.
|
|
DWORD dwSourceProcess = 0;
|
|
sc = spMMCClipboardDataObj->GetSourceProcessId( &dwSourceProcess );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// If from different process then ask snapin if it can handle out of proc dataobjects.
|
|
BOOL bSourceFromDifferentMMCProcess = ( dwSourceProcess != ::GetCurrentProcessId() );
|
|
|
|
DWORD dwNumObjects = 0;
|
|
sc = spMMCClipboardDataObj->GetCount(&dwNumObjects);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// 4. For each snapin object, get the dataobject and ask target item if
|
|
// it can allow the source to be pasted.
|
|
for (DWORD index = 0; index < dwNumObjects; ++index)
|
|
{
|
|
IDataObjectPtr spSourceDataObject;
|
|
DWORD dwFlags = 0;
|
|
sc = spMMCClipboardDataObj->GetDataObject( index, &spSourceDataObject, &dwFlags );
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(spSourceDataObject, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
// must have some operation allowed - else it is invalid entry
|
|
if ( dwFlags == 0 )
|
|
return (sc = E_UNEXPECTED).ToHr();
|
|
/*
|
|
* During construction of th MMCClipboardDataObject we have checked if
|
|
* cut/copy is enabled before adding the snapin dataobject.
|
|
* So we are sure now atleast cut or copy is enabled for each snapin
|
|
* object and we dont have to check this again.
|
|
*/
|
|
|
|
bool bSnapinPasteAllowed = false;
|
|
bool bSnapinWantsCopyAsDefault = false;
|
|
sc = _ScQueryPaste (pSelectedNode, spTargetDataObject, spSourceDataObject,
|
|
bSourceFromDifferentMMCProcess, bSnapinPasteAllowed,
|
|
bSnapinWantsCopyAsDefault);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
bPasteAllowed = bPasteAllowed || bSnapinPasteAllowed;
|
|
bCopyOperatationIsDefault = bCopyOperatationIsDefault || bSnapinWantsCopyAsDefault;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// We do not recognize the dataobject and we dont know if it is from
|
|
// this MMC process or from any other process. So do not ask snapin if
|
|
// it can handle outofproc dataobjects or not. (This is MMC1.2 legacy case).
|
|
|
|
sc = _ScQueryPaste (pSelectedNode, spTargetDataObject, pDataObjectToPaste,
|
|
/*bSourceFromDifferentMMCProcess = */ false,
|
|
bPasteAllowed, bCopyOperatationIsDefault);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
}
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::_ScQueryPaste
|
|
//
|
|
// Synopsis: Send MMCN_QUERY_PASTE(2) to the snapin.
|
|
//
|
|
// Arguments: [pNode] - Owner of result pane.
|
|
// [spTargetDataObject] - Target object where we want to paste.
|
|
// [spSourceDataObject] - The object that we want to paste.
|
|
// [bSourceFromDifferentMMCProcess] -
|
|
// [bPasteAllowed] - out param
|
|
// [bCopyOperationIsDefault] - out param
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNodeCallback::_ScQueryPaste (CNode *pNode,
|
|
IDataObject *pTargetDataObject,
|
|
IDataObject *pSourceDataObject,
|
|
bool bSourceFromDifferentMMCProcess,
|
|
bool& bPasteAllowed,
|
|
bool& bCopyOperatationIsDefault)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::_ScQueryPaste"));
|
|
sc = ScCheckPointers(pNode, pTargetDataObject, pSourceDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
bCopyOperatationIsDefault = false;
|
|
bPasteAllowed = false;
|
|
|
|
CComponent* pCC = pNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pCC, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
BOOL bCanPasteOutOfProcDataObject = FALSE;
|
|
|
|
sc = pCC->Notify(NULL, MMCN_CANPASTE_OUTOFPROC,
|
|
0, reinterpret_cast<LPARAM>(&bCanPasteOutOfProcDataObject) );
|
|
|
|
// Snapins return E_* values so check if they are OK with above notification.
|
|
if ( sc != S_OK)
|
|
{
|
|
bCanPasteOutOfProcDataObject = false;
|
|
sc.Clear();
|
|
}
|
|
|
|
// Source from diff MMC process & cannot handle outofproc dataobjects then return.
|
|
if (bSourceFromDifferentMMCProcess && (! bCanPasteOutOfProcDataObject) )
|
|
return sc.ToHr();
|
|
|
|
// Send MMCN_QUERY_PASTE
|
|
DWORD dwFlags = 0;
|
|
sc = pCC->Notify(pTargetDataObject, MMCN_QUERY_PASTE,
|
|
reinterpret_cast<LPARAM>(pSourceDataObject),
|
|
reinterpret_cast<LPARAM>(&dwFlags));
|
|
if (sc)
|
|
{
|
|
// Clear any snapin returned errors.
|
|
sc.Clear();
|
|
return sc.ToHr();
|
|
}
|
|
|
|
if (sc == SC(S_OK))
|
|
bPasteAllowed = true;
|
|
|
|
bCopyOperatationIsDefault = (dwFlags & MMC_DEFAULT_OPERATION_COPY);
|
|
|
|
return (sc);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::Drop
|
|
//
|
|
// Synopsis: Given the drop object context & the source object to
|
|
// be dropped. Do paste operation.
|
|
//
|
|
// Arguments: [hNode] - The node owning the view.
|
|
// [bScope] - Selection on Scope or Result pane.
|
|
// [lCookie] - If result pane selected the cookie for selected result item.
|
|
// [pDataObjectToPaste] - The dataobject to be pasted.
|
|
// [bIsDragOperationMove]- Is the drag operation move or copy.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::Drop (HNODE hNode, BOOL bScope, LPARAM lCookie, IDataObject *pDataObjectToPaste, BOOL bIsDragOperationMove)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::Drop"));
|
|
sc = ScCheckPointers(hNode, pDataObjectToPaste);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScPaste(hNode, bScope, lCookie, pDataObjectToPaste, TRUE, bIsDragOperationMove);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::Paste
|
|
//
|
|
// Synopsis: Given the target where the clipboard object is to be
|
|
// pasted. Paste the object.
|
|
//
|
|
// Arguments: [hNode] - The node owning the view.
|
|
// [bScope] - Selection on Scope or Result pane.
|
|
// [lCookie] - If result pane selected the cookie for selected result item.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::Paste (HNODE hNode, BOOL bScope, LPARAM lCookie)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::Paste"));
|
|
sc = ScCheckPointers(hNode);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
IDataObjectPtr spDOPaste;
|
|
sc = OleGetClipboard(&spDOPaste);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScCheckPointers(spDOPaste, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
sc = ScPaste(hNode, bScope, lCookie, spDOPaste, /*bDragDrop*/FALSE, FALSE);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::ScPaste
|
|
//
|
|
// Synopsis: Given the current drop target (or paste target) context
|
|
// paste the given data object if it is drag&drop operation
|
|
// else paste the one from clipboard.
|
|
//
|
|
// Arguments: [hNode] - The node owning the view.
|
|
// [bScopePaneSelected] - Selection on Scope or Result pane.
|
|
// [lCookie] - If result pane selected the cookie for selected result item.
|
|
// [pDataObjectToPaste] - The dataobject to be pasted.
|
|
// [bDragDrop] - Is the operation drag & drop operation.
|
|
// [bIsDragOperationMove]- Is the drag operation move or copy.
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNodeCallback::ScPaste (HNODE hNode, BOOL bScopePaneSelected, LPARAM lCookie,
|
|
IDataObject *pDataObjectToPaste, BOOL bDragDrop,
|
|
BOOL bIsDragOperationMove)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::Paste"));
|
|
sc = ScCheckPointers(hNode, pDataObjectToPaste);
|
|
if (sc)
|
|
return sc;
|
|
|
|
CNode *pNode = CNode::FromHandle(hNode);
|
|
sc = ScCheckPointers(pNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// If result-pane cookie should be valid.
|
|
BOOL bScopeItemSelected;
|
|
CNode *pSelectedNode = NULL;
|
|
MMC_COOKIE cookie = -1;
|
|
|
|
sc = CNodeCallback::ScExtractLVData(pNode, bScopePaneSelected, lCookie,
|
|
&pSelectedNode, bScopeItemSelected, cookie);
|
|
if (sc)
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(pSelectedNode, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if ( (FALSE == bScopeItemSelected) && (cookie == LVDATA_ERROR) )
|
|
return (sc = E_FAIL);
|
|
|
|
CViewData *pViewData = pSelectedNode->GetViewData();
|
|
sc = ScCheckPointers(pViewData, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Do not allow paste into OCX/WEB/Multiselection
|
|
// We can allow paste into OCX/WEB if we expose IMMCClipboardDataObject
|
|
// interface. But paste into Multiselection should not be allowed as
|
|
// it is not intuitive.
|
|
if ( (!bScopeItemSelected) && IS_SPECIAL_COOKIE(lCookie))
|
|
return sc;
|
|
|
|
/*
|
|
* In MMC1.2 the drop target is always scope node. In MMC2.0
|
|
* it can be any result item.
|
|
* Make sure if the snapin has RVTI_LIST_OPTIONS_ALLOWPASTE.
|
|
*/
|
|
if ( (bScopeItemSelected == FALSE) && (! (RVTI_LIST_OPTIONS_ALLOWPASTE & pViewData->GetListOptions())) )
|
|
{
|
|
ASSERT(0 && "UNEXPECTED: We can paste only into a folder!");
|
|
// We can paste only into a folder.
|
|
return (sc = E_FAIL);
|
|
}
|
|
|
|
if (pSelectedNode->IsInitialized() == FALSE)
|
|
{
|
|
sc = _InitializeNode(pSelectedNode);
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
IDataObject* pTargetDataObject = NULL;
|
|
sc = pSelectedNode->ScGetDropTargetDataObject(bScopeItemSelected, lCookie, &pTargetDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IDataObjectPtr spTargetDataObject;
|
|
if (! IS_SPECIAL_DATAOBJECT(pTargetDataObject))
|
|
spTargetDataObject = pTargetDataObject; // Addref the object
|
|
|
|
sc = ScCheckPointers(pTargetDataObject, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// QI to see if it is MMC's data object
|
|
IMMCClipboardDataObjectPtr spMMCClipboardDataObj = pDataObjectToPaste;
|
|
|
|
if (spMMCClipboardDataObj)
|
|
{
|
|
// This is our own dataobject.
|
|
|
|
// 3. Get how, where it is created, and how many snapin objects are there.
|
|
|
|
DATA_SOURCE_ACTION eSourceAction;
|
|
sc = spMMCClipboardDataObj->GetAction( &eSourceAction );
|
|
if (sc)
|
|
return sc;
|
|
|
|
BOOL bIsCreatedForCut = FALSE;
|
|
BOOL bIsCreatedForCopy = FALSE;
|
|
|
|
if (bDragDrop)
|
|
{
|
|
bIsCreatedForCut = bIsDragOperationMove;
|
|
bIsCreatedForCopy = !bIsDragOperationMove;
|
|
}
|
|
else
|
|
{
|
|
bIsCreatedForCut = ( eSourceAction == ACTION_CUT );
|
|
bIsCreatedForCopy = ( eSourceAction == ACTION_COPY );
|
|
}
|
|
|
|
DWORD dwNumObjects = 0;
|
|
sc = spMMCClipboardDataObj->GetCount(&dwNumObjects);
|
|
if (sc)
|
|
return sc;
|
|
|
|
BOOL bDoCutOperation = FALSE;
|
|
BOOL bDoCopyOperation = FALSE;
|
|
|
|
// 4. For each snapin object, get the dataobject and ask target to paste it.
|
|
|
|
// need to form the array of copy objects, so that we do not delete them while
|
|
// processing - this invalidates data object and prevents accessing the rest of
|
|
// items
|
|
std::vector<IDataObjectPtr> vecObjectsToCopy;
|
|
std::vector<DWORD> vecObjectFlags;
|
|
|
|
vecObjectsToCopy.reserve(dwNumObjects); // small optimization
|
|
vecObjectFlags.reserve(dwNumObjects); // small optimization
|
|
|
|
// fill with data objects to copy
|
|
for (DWORD index = 0; index < dwNumObjects; ++index)
|
|
{
|
|
IDataObjectPtr spSourceDataObject;
|
|
DWORD dwFlags = 0;
|
|
sc = spMMCClipboardDataObj->GetDataObject( index, &spSourceDataObject, &dwFlags );
|
|
if (sc)
|
|
return sc;
|
|
|
|
vecObjectsToCopy.push_back( spSourceDataObject );
|
|
vecObjectFlags.push_back( dwFlags );
|
|
}
|
|
|
|
// perform action on the data
|
|
for (index = 0; index < dwNumObjects; ++index)
|
|
{
|
|
IDataObjectPtr spSourceDataObject = vecObjectsToCopy[index];
|
|
DWORD dwFlags = vecObjectFlags[index];
|
|
|
|
sc = ScCheckPointers(spSourceDataObject, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
BOOL bHasCutEnabled = ( dwFlags & MOVE_ALLOWED );
|
|
BOOL bHasCopyEnabled = ( dwFlags & COPY_ALLOWED );
|
|
|
|
/*
|
|
* In case of multiselection even if one of the selected
|
|
* object enables cut, the cut operation can be performed.
|
|
*
|
|
* But when we paste the objects we need to see if source
|
|
* enabled cut or not. If it did not enable then do nothing.
|
|
*
|
|
* Below is a table for this.
|
|
*
|
|
* Source object enables (only)
|
|
* -------------------------------------------
|
|
* |Operation | Cut | Copy |
|
|
* -------------------------------------------
|
|
* | | | |
|
|
* | Cut | Cut | Do nothing |
|
|
* Current | | | |
|
|
* Operation|-----------------------------------------
|
|
* | | | |
|
|
* | Copy | Do nothing | Copy |
|
|
* | | | |
|
|
* -------------------------------------------
|
|
*/
|
|
bDoCutOperation = (bIsCreatedForCut && bHasCutEnabled);
|
|
bDoCopyOperation = (bIsCreatedForCopy && bHasCopyEnabled);
|
|
|
|
// See above table: this is "Do nothing".
|
|
if ( (!bDoCutOperation) && (!bDoCopyOperation) )
|
|
continue;
|
|
|
|
IDataObjectPtr spCutDataObject;
|
|
sc = _ScPaste (pSelectedNode, pTargetDataObject,
|
|
spSourceDataObject, &spCutDataObject,
|
|
bDoCutOperation );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// remove cut items when required
|
|
if (bDoCutOperation && spCutDataObject != NULL)
|
|
{
|
|
sc = spMMCClipboardDataObj->RemoveCutItems( index, spCutDataObject );
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
}
|
|
|
|
// If this is cut operation that is initiated by cut/copy/paste and
|
|
// not by drag & drop operation then the dataobject in clipboard is
|
|
// ours. So clear the clipboard so that we dont use that dataobject.
|
|
if ( eSourceAction == ACTION_CUT )
|
|
OleSetClipboard(NULL);
|
|
}
|
|
else
|
|
{
|
|
// We do not recognize the dataobject and we dont know if it is from
|
|
// this MMC process or from any other process. We cannot decode this
|
|
// dataobject so we just send MMCN_PASTE and ignore any dataobject
|
|
// retuned by snapin for cut operation (this is legacy case).
|
|
|
|
// for drag operation we can give a hint to snapin
|
|
// what operation (copy/move) was attempted.
|
|
// however we are not ensuring deletion of source items
|
|
bool bCutOrMove = (bDragDrop && bIsDragOperationMove);
|
|
|
|
IDataObjectPtr spCutDataObject;
|
|
sc = _ScPaste (pSelectedNode, pTargetDataObject,
|
|
pDataObjectToPaste, &spCutDataObject,
|
|
bCutOrMove );
|
|
if (sc)
|
|
return sc;
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::_ScPaste
|
|
//
|
|
// Synopsis: Send MMCN_PASTE to snapin.
|
|
//
|
|
// Arguments: [pNode] - Owner of resultpane.
|
|
// [pTargetDataObject] - target where we need to paste.
|
|
// [pSourceDataObject] - source to be pasted.
|
|
// [ppCutDataObject] - (out) cut items
|
|
// [bCutOrMove]
|
|
//
|
|
// Returns: SC
|
|
//
|
|
//--------------------------------------------------------------------
|
|
SC CNodeCallback::_ScPaste (CNode *pNode,
|
|
IDataObject *pTargetDataObject,
|
|
IDataObject *pSourceDataObject,
|
|
IDataObject **ppCutDataObject,
|
|
bool bCutOrMove)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::_ScSendPasteNotification"));
|
|
sc = ScCheckPointers(pNode, pTargetDataObject, pSourceDataObject, ppCutDataObject);
|
|
if (sc)
|
|
return sc;
|
|
|
|
// init out param
|
|
*ppCutDataObject = NULL;
|
|
|
|
CComponent* pComponent = pNode->GetPrimaryComponent();
|
|
sc = ScCheckPointers(pComponent, E_UNEXPECTED);
|
|
if (sc)
|
|
return sc;
|
|
|
|
IDataObject* pDataObjectToBeCutBySource = NULL;
|
|
sc = pComponent->Notify(pTargetDataObject, MMCN_PASTE,
|
|
reinterpret_cast<LPARAM>(pSourceDataObject),
|
|
bCutOrMove ? reinterpret_cast<LPARAM>(&pDataObjectToBeCutBySource) : NULL);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (! bCutOrMove)
|
|
return sc;
|
|
|
|
// Exchange returns NULL dataobject. Do not trace error to be compatible with MMC1.2
|
|
if ( (pDataObjectToBeCutBySource) && (IS_SPECIAL_DATAOBJECT(pDataObjectToBeCutBySource) ) )
|
|
return (sc = E_UNEXPECTED);
|
|
|
|
// transfer control to the client ( no addref nor release in neaded )
|
|
*ppCutDataObject = pDataObjectToBeCutBySource;
|
|
|
|
return (sc);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::QueryViewSettingsPersistor
|
|
//
|
|
// Synopsis: Get the IPersistStream interface of CViewSettingsPersistor
|
|
// object to load the viewsettings (will not be asked for
|
|
// storing as saving is always XML format).
|
|
//
|
|
// Arguments: [ppStream] - [out]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::QueryViewSettingsPersistor (IPersistStream** ppStream)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::QueryViewSettingsPersistor"));
|
|
sc = ScCheckPointers(ppStream);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*ppStream = NULL;
|
|
|
|
// Call CNode static method to get IPersistStream interface.
|
|
sc = CNode::ScQueryViewSettingsPersistor(ppStream);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::QueryViewSettingsPersistor
|
|
//
|
|
// Synopsis: Get the CXMLObject interface of CViewSettingsPersistor
|
|
// object to save/load the viewsettings from XML console file.
|
|
//
|
|
// Arguments: [ppXMLObject] - [out]
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::QueryViewSettingsPersistor (CXMLObject** ppXMLObject)
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::QueryViewSettingsPersistor"));
|
|
|
|
sc = ScCheckPointers(ppXMLObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
*ppXMLObject = NULL;
|
|
|
|
// Call CNode static method to get CXMLObject interface.
|
|
sc = CNode::ScQueryViewSettingsPersistor(ppXMLObject);
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CNodeCallback::DocumentClosing
|
|
//
|
|
// Synopsis: The document is to be closed, so release any document
|
|
// related objects. (CViewSettingsPersistor).
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//--------------------------------------------------------------------
|
|
STDMETHODIMP CNodeCallback::DocumentClosing ()
|
|
{
|
|
DECLARE_SC(sc, _T("CNodeCallback::DocumentClosing"));
|
|
|
|
// 1. Call CNode static method informing document closing.
|
|
sc = CNode::ScOnDocumentClosing();
|
|
if (sc)
|
|
return sc.ToHr();
|
|
|
|
return (sc.ToHr());
|
|
}
|