//+------------------------------------------------------------------------- // // 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) { IF_NULL_RETURN_INVALIDARG(pScopeTree); m_pCScopeTree = dynamic_cast(pScopeTree); ASSERT(m_pCScopeTree != NULL); return S_OK; } STDMETHODIMP CNodeCallback::GetImages(HNODE hNode, int* piImage, int* piSelectedImage) { IF_NULL_RETURN_INVALIDARG(hNode); // 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; } 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); 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(); } // // '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(pNode); if (pSINode) pSINode->SetResultImageList (pImageList); } return S_OK; } STDMETHODIMP CNodeCallback::GetState(HNODE hNode, UINT* pnState) { IF_NULL_RETURN_INVALIDARG2(hNode, pnState); // convert to real type CNode* pNode = CNode::FromHandle(hNode); *pnState = pNode->GetMTNode()->GetState(); return S_OK; } STDMETHODIMP CNodeCallback::Notify(HNODE hNode, NCLBK_NOTIFY_TYPE event, LONG_PTR arg, LPARAM param) { 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(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(arg)); break; case NCLBK_PROPERTIES: hr = OnProperties(pNode, static_cast(arg), param); break; case NCLBK_REFRESH: hr = OnRefresh(pNode, static_cast(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(arg), param); break; case NCLBK_NEW_NODE_UPDATE: hr = OnNewNodeUpdate(pNode, arg); break; case NCLBK_RENAME: hr = OnRename(pNode, reinterpret_cast(arg), reinterpret_cast(param)); break; case NCLBK_MULTI_SELECT: OnMultiSelect(pNode, static_cast(arg)); break; case NCLBK_SELECT: OnSelect(pNode, static_cast(arg), reinterpret_cast(param)); break; case NCLBK_FINDITEM: OnFindResultItem(pNode, reinterpret_cast(arg), reinterpret_cast(param)); break; case NCLBK_COLUMN_CLICKED: hr = OnColumnClicked(pNode, param); break; case NCLBK_CONTEXTHELP: hr = OnContextHelp(pNode, static_cast(arg), param); break; case NCLBK_SNAPINHELP: hr = OnSnapInHelp(pNode, static_cast(arg), param); break; case NCLBK_FILTER_CHANGE: hr = OnFilterChange(pNode, arg, param); break; case NCLBK_FILTERBTN_CLICK: hr = OnFilterBtnClick(pNode, arg, reinterpret_cast(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; } STDMETHODIMP CNodeCallback::GetMTNode(HNODE hNode, HMTNODE* phMTNode) { IF_NULL_RETURN_INVALIDARG2(hNode, phMTNode); // convert to real type CNode* pNode = CNode::FromHandle(hNode); *phMTNode = CMTNode::ToHandle(pNode->GetMTNode()); return S_OK; } STDMETHODIMP CNodeCallback::SetResultItem(HNODE hNode, HRESULTITEM hri) { IF_NULL_RETURN_INVALIDARG(hNode); // convert to real type CNode* pNode = CNode::FromHandle(hNode); pNode->SetResultItem(hri); return S_OK; } STDMETHODIMP CNodeCallback::GetResultItem(HNODE hNode, HRESULTITEM* phri) { IF_NULL_RETURN_INVALIDARG(hNode); // convert to real type CNode* pNode = CNode::FromHandle(hNode); *phri = pNode->GetResultItem(); return S_OK; } STDMETHODIMP CNodeCallback::GetMTNodeID(HNODE hNode, MTNODEID* pnID) { IF_NULL_RETURN_INVALIDARG(pnID); // convert to real type CNode* pNode = CNode::FromHandle(hNode); *pnID = pNode->GetMTNode()->GetID(); return S_OK; } /*+-------------------------------------------------------------------------* * * 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) { ASSERT(hNode && hTestNode); CNode* pNode = CNode::FromHandle(hNode); CNode* pTestNode = CNode::FromHandle(hTestNode); ASSERT(pNode); return pNode->IsTargetNode(pTestNode); } 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(); // convert to real type CNode* pNode = CNode::FromHandle(hNode); CNode* pRootNode = CNode::FromHandle(hRootNode); CBookmark* pbmOut = reinterpret_cast(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(); } STDMETHODIMP CNodeCallback::GetStaticParentID(HNODE hNode, MTNODEID* pnID) { IF_NULL_RETURN_INVALIDARG2(hNode, pnID); // 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; } // 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); // 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; } /*+-------------------------------------------------------------------------* * * 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); CNode* pNode = CNode::FromHandle(hNode); if (pNode->IsStaticNode()) *pOwnerID = 0; else *pOwnerID = pNode->GetOwnerID(); return S_OK; } STDMETHODIMP CNodeCallback::GetNodeCookie(HNODE hNode, MMC_COOKIE* pCookie) { IF_NULL_RETURN_INVALIDARG2(hNode, pCookie); // only dynamic nodes have cookies CNode* pNode = CNode::FromHandle(hNode); if (!pNode->IsDynamicNode()) return E_FAIL; *pCookie = pNode->GetUserParam(); return S_OK; } /*+-------------------------------------------------------------------------* * * 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) { 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(); } /*+-------------------------------------------------------------------------* * * 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(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(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(&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(&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(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(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(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(param); BOOL b = static_cast(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 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) { // convert to real type CNode* pNode = CNode::FromHandle(hNode); ASSERT(pNode != NULL); CMTNode* pMTNode = pNode->GetMTNode(); ASSERT(pMTNode != NULL); return pMTNode->IsExpandable(); } 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) { ASSERT(ppConsoleVerb != NULL); return _GetConsoleVerb(CNode::FromHandle(hNode), ppConsoleVerb); } // 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(param); return pNode->OnGetPrimaryTask(ppExtendTaskPad); } STDMETHODIMP CNodeCallback::UpdateWindowLayout(LONG_PTR lViewData, long lToolbarsDisplayed) { IF_NULL_RETURN_INVALIDARG(lViewData); CViewData* pVD = reinterpret_cast(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(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(hvs); CBookmark *pBookmark = reinterpret_cast (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(&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(pSourceDataObject), reinterpret_cast(&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 vecObjectsToCopy; std::vector 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(pSourceDataObject), bCutOrMove ? reinterpret_cast(&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()); }