|
|
//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Administration SnapIn
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: DSEvent.cpp
//
// Contents: Main DS Snapin file
// This file contains all the interfaces between the snapin and
// the slate console. IComponent, IDataObject...etc
//
// History: 02-Oct-96 WayneSc Created
// 06-Mar-97 EricB - added Property Page Extension support
//
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "uiutil.h"
#include "dsutil.h"
#include "dssnap.h" // Note: this has to be before dsevent.h
#include "DSEvent.h"
#include "ContextMenu.h"
#include "DataObj.h"
#include "dsctx.h"
#include "dsdirect.h"
#include "dsfilter.h"
#include "helpids.h"
#include "query.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
// DS Snapin CLSID - {E355E538-1C2E-11d0-8C37-00C04FD8FE93}
const CLSID CLSID_DSSnapin = {0xe355e538, 0x1c2e, 0x11d0, {0x8c, 0x37, 0x0, 0xc0, 0x4f, 0xd8, 0xfe, 0x93}};
// DS Snapin Extension CLSID - {006A2A75-547F-11d1-B930-00A0C9A06D2D}
const CLSID CLSID_DSSnapinEx = { 0x6a2a75, 0x547f, 0x11d1, { 0xb9, 0x30, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
// DS Site CLSID - {d967f824-9968-11d0-b936-00c04fd8d5b0}
const CLSID CLSID_SiteSnapin = { 0xd967f824, 0x9968, 0x11d0, { 0xb9, 0x36, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
// Default Nodetype GUID - {FC04A81C-1DFA-11D0-8C3b-00C04FD8FE93}
const GUID cDefaultNodeType = {0xFC04A81C, 0x1dfa, 0x11d0, {0x8C, 0x3B, 0x00, 0xC0, 0x4F, 0xD8, 0xFE, 0x93}};
// DS About Snapin CLSID - {c3a904fe-c4f2-11d1-b10b-00104b243180}
const CLSID CLSID_DSAboutSnapin = {0xc3a904fe, 0xc4f2, 0x11d1, {0xb1, 0x0b, 0x00, 0x10, 0x4b, 0x24, 0x31, 0x80}};
// DS About Snapin CLSID - {765901ea-c5a1-11d1-b10c-00104b243180}
const CLSID CLSID_SitesAboutSnapin = {0x765901ea, 0xc5a1, 0x11d1, {0xb1, 0x0c, 0x00, 0x10, 0x4b, 0x24, 0x31, 0x80}};
// DS Query UI Form extension for saved queries {8C16E7CB-17C2-4729-A669-8474D6712B81}
const CLSID CLSID_DSAdminQueryUIForm = { 0x8c16e7cb, 0x17c2, 0x4729, { 0xa6, 0x69, 0x84, 0x74, 0xd6, 0x71, 0x2b, 0x81 } };
const wchar_t* cszDefaultNodeType = _T("{FC04A81C-1DFA-11d0-8C3B-00C04FD8FE93}");
/////////////////////////////////////////////////////////////////////////////
// CDSEvent
//+-------------------------------------------------------------------------
//
// Function: Constructor / Destructor
//
// Synopsis:
//
//--------------------------------------------------------------------------
CDSEvent::CDSEvent() : m_pFrame(NULL), m_pHeader(NULL), m_pResultData(NULL), m_pScopeData(NULL), m_pConsoleVerb(NULL), m_pRsltImageList(NULL), m_pSelectedFolderNode(NULL), m_pComponentData( NULL ), m_pToolbar(NULL), m_pControlbar(NULL), m_bUpdateAllViewsOrigin(FALSE) { TRACE(_T("CDSEvent::CDSEvent() - Constructor\n")); }
CDSEvent::~CDSEvent() { TRACE(_T("CDSEvent::~CDSEvent() - Destructor\n"));
SetIComponentData( NULL ); }
/////////////////////////////////////////////////////////////////////////////
// IComponent Interfaces
//+-------------------------------------------------------------------------
//
// Function: Destroy
//
// Synopsis: Used for clean up
//
//--------------------------------------------------------------------------
STDMETHODIMP CDSEvent::Destroy(MMC_COOKIE) { TRACE(_T("CDSEvent::Destroy()\n"));
if (NULL != m_pHeader) m_pFrame->SetHeader(NULL);
if (NULL != m_pToolbar) { m_pToolbar->Release(); }
m_pHeader->Release();
m_pResultData->Release(); m_pScopeData->Release(); m_pRsltImageList->Release(); m_pFrame->Release(); m_pConsoleVerb->Release(); return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: Initialize
//
// Synopsis: Called everytime the snapin get created.
//
// Arguments: IConsole - Pointer to calling object
//
//--------------------------------------------------------------------------
STDMETHODIMP CDSEvent::Initialize(IConsole* pConsole) { TRACE(_T("CDSEvent::Initialize()\n")); AFX_MANAGE_STATE(AfxGetStaticModuleState()); CWaitCursor wait;
if (pConsole == NULL) { // Invalid argument
return E_POINTER; } // hold on to the frame
HRESULT hr = pConsole->QueryInterface(IID_IConsole3, (void**)&m_pFrame); if (FAILED(hr)) return hr; // cache interface pointers we use
hr = m_pFrame->QueryInterface(IID_IHeaderCtrl, (void**)&m_pHeader); if (FAILED(hr)) return hr; ASSERT(m_pHeader != NULL);
hr = m_pFrame->SetHeader(m_pHeader); if (FAILED(hr)) return hr;
hr = m_pFrame->QueryInterface(IID_IResultData2, (void**)&m_pResultData); if (FAILED(hr)) return hr; ASSERT(m_pResultData != NULL);
hr = m_pFrame->QueryInterface(IID_IConsoleNameSpace, (void**)&m_pScopeData); if (FAILED(hr)) return hr; ASSERT(m_pScopeData != NULL);
hr = m_pFrame->QueryResultImageList(&m_pRsltImageList); if (FAILED(hr)) return hr; ASSERT(m_pRsltImageList != NULL);
hr = m_pFrame->QueryConsoleVerb (&m_pConsoleVerb); if (FAILED(hr)) return hr;
m_hwnd = m_pComponentData->GetHWnd();
return S_OK; }
STDMETHODIMP CDSEvent::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { TRACE(_T("CDSEvent::GetDataObject()\n"));
HRESULT hr=S_OK;
CUINode* pUINode; CDSDataObject* const pDataObject = new CComObject<CDSDataObject>; ASSERT(pDataObject != 0);
pDataObject->SetType(type, m_pComponentData->QuerySnapinType()); pDataObject->SetComponentData(m_pComponentData);
if (cookie != MMC_MULTI_SELECT_COOKIE) { pUINode = reinterpret_cast<CUINode*>(cookie); pDataObject->SetCookie(pUINode); } else { TRACE(_T("CDSEvent::GetDataObject() - multi-select.\n")); RESULTDATAITEM rdi; ZeroMemory(&rdi, sizeof(rdi)); rdi.mask = RDI_STATE; rdi.nIndex = -1; rdi.nState = LVIS_SELECTED; do { rdi.lParam = 0; ASSERT(rdi.mask == RDI_STATE); ASSERT(rdi.nState == LVIS_SELECTED); hr = m_pResultData->GetNextItem(&rdi); if (hr != S_OK) break; pUINode = reinterpret_cast<CUINode*>(rdi.lParam); pDataObject->AddCookie(pUINode); } while (1); }
// addref() the new pointer and return it.
pDataObject->AddRef(); *ppDataObject = pDataObject; TRACE(_T("new data object is at %lx(%lx).\n"), pDataObject, *pDataObject); return hr; }
STDMETHODIMP CDSEvent::GetDisplayInfo(LPRESULTDATAITEM pResult) { ASSERT(pResult != NULL); HRESULT hr = S_OK; // get the node we are interested in
CUINode* pUINode = reinterpret_cast<CUINode*>(pResult->lParam); ASSERT( NULL != pUINode );
if (pResult->mask & RDI_STR) { // need string value
// get the parent to retrieve the column set
CUINode* pUIParentNode = pUINode->GetParent(); ASSERT(pUIParentNode != NULL); ASSERT(pUIParentNode->IsContainer());
// retrieve the column set
CDSColumnSet* pColumnSet = pUIParentNode->GetColumnSet(m_pComponentData); ASSERT(pColumnSet != NULL);
// ask the node to provide the string for the
// given column in the column set
pResult->str = const_cast<LPWSTR>(pUINode->GetDisplayString(pResult->nCol, pColumnSet)); }
if (pResult->mask & RDI_IMAGE) { // need an icon for result pane
pResult->nImage = m_pComponentData->GetImage(pUINode, FALSE); }
return hr; }
/////////////////////////////////////////////////////////////////////////////
//IResultCallback
STDMETHODIMP CDSEvent::GetResultViewType(MMC_COOKIE, LPWSTR* ppViewType, long *pViewOptions) { *ppViewType = NULL; *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
return S_FALSE; }
//+----------------------------------------------------------------------------
//
// Member: CDSEvent::IExtendPropertySheet::CreatePropertyPages
//
// Synopsis: Called in response to a user click on the Properties context
// menu item.
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDSEvent::CreatePropertyPages(LPPROPERTYSHEETCALLBACK pCall, LONG_PTR lNotifyHandle, LPDATAOBJECT pDataObject) { IExtendPropertySheet * pEPS = (IExtendPropertySheet *)m_pComponentData; return pEPS->CreatePropertyPages(pCall, lNotifyHandle, pDataObject); }
//+----------------------------------------------------------------------------
//
// Member: CDSEvent::IExtendPropertySheet::QueryPagesFor
//
// Synopsis: Called before a context menu is posted. If we support a
// property sheet for this object, then return S_OK.
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDSEvent::QueryPagesFor(LPDATAOBJECT pDataObject) { TRACE(TEXT("CDSEvent::QueryPagesFor().\n")); return m_pComponentData->QueryPagesFor( pDataObject); }
//+---------------------------------------------------------------------------
//
// Function: LocaleStrCmp
//
// Synopsis: Do a case insensitive string compare that is safe for any
// locale.
//
// Arguments: [ptsz1] - strings to compare
// [ptsz2]
//
// Returns: -1, 0, or 1 just like lstrcmpi
//
// History: 10-28-96 DavidMun Created
//
// Notes: This is slower than lstrcmpi, but will work when sorting
// strings even in Japanese.
//
//----------------------------------------------------------------------------
int LocaleStrCmp(LPCTSTR ptsz1, LPCTSTR ptsz2) { int iRet = 0;
iRet = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, ptsz1, -1, ptsz2, -1);
if (iRet) { iRet -= 2; // convert to lstrcmpi-style return -1, 0, or 1
if ( 0 == iRet ) { UNICODE_STRING unistr1; unistr1.Length = (USHORT)(::lstrlen(ptsz1)*sizeof(WCHAR)); unistr1.MaximumLength = unistr1.Length; unistr1.Buffer = (LPWSTR)ptsz1; UNICODE_STRING unistr2; unistr2.Length = (USHORT)(::lstrlen(ptsz2)*sizeof(WCHAR)); unistr2.MaximumLength = unistr2.Length; unistr2.Buffer = (LPWSTR)ptsz2; iRet = ::RtlCompareUnicodeString( &unistr1, &unistr2, FALSE ); } } else { DWORD dwErr = GetLastError (); if (dwErr != 0) { TRACE3 ("CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, dwErr); } } return iRet; } //+----------------------------------------------------------------------------
//
// Member: CDSEvent::IResultDataCompareEx::Compare
//
// Synopsis: called to do the comparison for sorting in the result
// pane
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDSEvent::Compare(RDCOMPARE* prdc, int* pnResult) { HRESULT hr = S_OK; if (pnResult == NULL) { ASSERT(FALSE); return E_POINTER; }
*pnResult = 0; if (prdc == NULL) { ASSERT(FALSE); return E_POINTER; } CUINode* pUINodeA = reinterpret_cast<CUINode*>(prdc->prdch1->cookie); CUINode* pUINodeB = reinterpret_cast<CUINode*>(prdc->prdch2->cookie); ASSERT(pUINodeA != NULL); ASSERT(pUINodeB != NULL); if ( (pUINodeA == NULL) || (pUINodeB == NULL) ) { return E_INVALIDARG; }
CString strA, strB;
CDSColumnSet* pColSetA = pUINodeA->GetParent()->GetColumnSet(m_pComponentData); CDSColumnSet* pColSetB = pUINodeB->GetParent()->GetColumnSet(m_pComponentData);
if ((pColSetA == NULL) || (pColSetB == NULL)) { return E_INVALIDARG; }
CDSColumn* pColA = (CDSColumn*)pColSetA->GetColumnAt(prdc->nColumn);
if (IS_CLASS(CDSUINode, *pUINodeA) && IS_CLASS(CDSUINode, *pUINodeB)) { //
// extract cookie info (DS objects)
//
CDSCookie* pCookieA = GetDSCookieFromUINode(pUINodeA); CDSCookie* pCookieB = GetDSCookieFromUINode(pUINodeB); if ( (pCookieB == NULL) || (pCookieA == NULL)) { return E_INVALIDARG; }
switch (pColA->GetColumnType()) { case ATTR_COLTYPE_NAME: //name
strA = pCookieA->GetName(); strB = pCookieB->GetName();
*pnResult = LocaleStrCmp(strA, strB); break;
case ATTR_COLTYPE_CLASS: //class
strA = pCookieA->GetLocalizedClassName(); strB = pCookieB->GetLocalizedClassName();
*pnResult = LocaleStrCmp(strA, strB); break;
case ATTR_COLTYPE_DESC: //description
strA = pCookieA->GetDesc(); strB = pCookieB->GetDesc();
*pnResult = LocaleStrCmp(strA, strB); break;
case ATTR_COLTYPE_SPECIAL: //special columns
{ int nSpecialCol = 0; int idx = 0; POSITION pos = pColSetA->GetHeadPosition(); while (idx < prdc->nColumn && pos != NULL) // JonN 4/3/01 313564
{ CDSColumn* pColumn = (CDSColumn*)pColSetA->GetNext(pos); ASSERT(pColumn != NULL);
if ((pColumn->GetColumnType() == ATTR_COLTYPE_SPECIAL || pColumn->GetColumnType() == ATTR_COLTYPE_MODIFIED_TIME) && pColumn->IsVisible()) { nSpecialCol++; }
idx++; } CStringList& strlistA = pCookieA->GetParentClassSpecificStrings(); POSITION posA = strlistA.FindIndex( nSpecialCol ); CStringList& strlistB = pCookieB->GetParentClassSpecificStrings(); POSITION posB = strlistB.FindIndex( nSpecialCol ); if ( NULL != posA && NULL != posB) { strA = strlistA.GetAt( posA ); strB = strlistB.GetAt( posB ); } *pnResult = LocaleStrCmp(strA, strB); break; } case ATTR_COLTYPE_MODIFIED_TIME: { SYSTEMTIME* pTimeA = pCookieA->GetModifiedTime(); SYSTEMTIME* pTimeB = pCookieB->GetModifiedTime(); if (pTimeA == NULL) { *pnResult = -1; break; } else if (pTimeB == NULL) { *pnResult = 1; break; }
FILETIME fileTimeA, fileTimeB; if (!SystemTimeToFileTime(pTimeA, &fileTimeA)) return E_FAIL;
if (!SystemTimeToFileTime(pTimeB, &fileTimeB)) return E_FAIL;
*pnResult = CompareFileTime(&fileTimeA, &fileTimeB); break; } default: return E_INVALIDARG; } } else // Not DS objects
{ strA = pUINodeA->GetDisplayString(prdc->nColumn, pColSetA); strB = pUINodeB->GetDisplayString(prdc->nColumn, pColSetB); *pnResult = LocaleStrCmp(strA, strB); }
// TRACE(_T("Compare: %d\n"), *pnResult);
return hr; }
//+----------------------------------------------------------------------------
//
// Member: CDSEvent::IComponent::CompareObjects
//
// Synopsis: If the data objects belong to the same DS object, then return
// S_OK.
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDSEvent::CompareObjects(LPDATAOBJECT pDataObject1, LPDATAOBJECT pDataObject2) { //
// Delegate to the IComponentData implementation.
//
return m_pComponentData->CompareObjects(pDataObject1, pDataObject2); }
STDMETHODIMP CDSEvent::Notify(IDataObject * pDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) {
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HRESULT hr = S_FALSE; CInternalFormatCracker dobjCracker; CUINode* pUINode = NULL;
if (pDataObject != NULL) { if (FAILED(dobjCracker.Extract(pDataObject))) { if ( (event == MMCN_ADD_IMAGES) && !m_pComponentData->m_bRunAsPrimarySnapin ) { m_pComponentData->FillInIconStrip (m_pRsltImageList); } return S_OK; } pUINode = dobjCracker.GetCookie(); }
if (event == MMCN_PROPERTY_CHANGE) { CWaitCursor cwait; TRACE(_T("CDSEvent::Notify() - property change, pDataObj = 0x%08x, param = 0x%08x, arg = %d.\n"), pDataObject, param, arg); if (param != 0) { hr = m_pComponentData->_OnPropertyChange((LPDATAOBJECT)param, FALSE); if (FAILED(hr)) { hr = S_FALSE; } } return S_OK; }
// some of the MMCN_VIEW_CHANGE, MMCN_CUTORMOVE messages have a NULL data object
if ((event != MMCN_VIEW_CHANGE) && (event != MMCN_CUTORMOVE) && (pUINode == NULL)) return S_FALSE;
switch (event) { case MMCN_SHOW: if (arg == TRUE) { // Show
CWaitCursor cwait; _EnumerateCookie(pUINode,(HSCOPEITEM)param,event); hr = S_OK; } break;
case MMCN_MINIMIZED: hr = S_FALSE; break;
case MMCN_SELECT: { BOOL bScope = LOWORD(arg); BOOL bSelect = HIWORD(arg);
CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(m_pComponentData);
if (pMenuVerbs == NULL) { ASSERT(FALSE); return S_FALSE; } pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb, bScope/*bScope*/, bSelect/*bSelect*/, pUINode, pDataObject); hr = S_OK; } break;
case MMCN_DELETE: { CWaitCursor cwait; _Delete(pDataObject, &dobjCracker); hr = S_OK; } break;
case MMCN_QUERY_PASTE: { hr = _QueryPaste(pUINode, (IDataObject*)(arg)); if (FAILED(hr)) { hr = S_FALSE; } } break;
case MMCN_PASTE: { CWaitCursor cwait; _Paste(pUINode, (IDataObject*)(arg), (LPDATAOBJECT*)param); hr = S_OK; } break; case MMCN_CUTORMOVE: { CWaitCursor cwait; ASSERT(pUINode == NULL); _CutOrMove((IDataObject*)(arg)); hr = S_OK; } break;
case MMCN_RENAME: { CWaitCursor cwait;
hr = m_pComponentData->_Rename (pUINode, (LPWSTR) param); if (SUCCEEDED(hr)) { m_pFrame->UpdateAllViews (pDataObject, (LPARAM)pUINode, DS_RENAME_OCCURRED);
MMC_SORT_SET_DATA* pColumnData = NULL;
CDSColumnSet* pColumnSet = pUINode->GetParent()->GetColumnSet(m_pComponentData); if (pColumnSet == NULL) break;
LPCWSTR lpszID = pColumnSet->GetColumnID(); size_t iLen = wcslen(lpszID);
//
// allocate enough memory for the struct and the guid
//
SColumnSetID* pNodeID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR))); if (pNodeID != NULL) { memset(pNodeID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR))); pNodeID->cBytes = static_cast<ULONG>(iLen * sizeof(WCHAR)); memcpy(pNodeID->id, lpszID, (iLen * sizeof(WCHAR)));
CComPtr<IColumnData> spColumnData; hr = m_pFrame->QueryInterface(IID_IColumnData, (void**)&spColumnData); if (spColumnData != NULL) { hr = spColumnData->GetColumnSortData(pNodeID, &pColumnData); }
if (SUCCEEDED(hr)) { if (pColumnData != NULL) { if (pColumnData->pSortData[0].nColIndex == 0) { m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode->GetParent(), DS_SORT_RESULT_PANE); } CoTaskMemFree(pColumnData); } } else { hr = S_FALSE; } free(pNodeID); } } else { hr = S_FALSE; } } break;
case MMCN_VIEW_CHANGE: { CWaitCursor cwait; TRACE (_T("CDSEvent::Notify() - view change message.\n")); HandleViewChange (pDataObject, arg, param); hr = S_OK; } break;
case MMCN_ADD_IMAGES: { CWaitCursor cwait; m_pComponentData->FillInIconStrip (m_pRsltImageList); hr = S_OK; } break;
case MMCN_REFRESH: { CWaitCursor cwait; m_pComponentData->Refresh(pUINode); hr = S_OK; } break; case MMCN_DBLCLICK: hr = S_FALSE; break; case MMCN_COLUMN_CLICK: hr = S_OK; break; case MMCN_COLUMNS_CHANGED: { CWaitCursor cwait; MMC_VISIBLE_COLUMNS* pVisibleColumns = reinterpret_cast<MMC_VISIBLE_COLUMNS*>(param); // Delegate to IComponentData
hr = m_pComponentData->ColumnsChanged(this, pUINode, pVisibleColumns, TRUE); if (FAILED(hr)) { hr = S_FALSE; } } break; case MMCN_RESTORE_VIEW : { CWaitCursor cwait; m_pComponentData->ColumnsChanged(this, pUINode, NULL, FALSE); *((BOOL*)param) = TRUE; hr = S_OK; } break; case MMCN_CONTEXTHELP: { CWaitCursor cwait;
IDisplayHelp * phelp = NULL; hr = m_pFrame->QueryInterface (IID_IDisplayHelp, (void **)&phelp); CString strDefTopic; if (SUCCEEDED(hr)) { if (m_pComponentData->QuerySnapinType() == SNAPINTYPE_SITE) { strDefTopic = DSSITES_DEFAULT_TOPIC; } else { strDefTopic = DSADMIN_DEFAULT_TOPIC; } phelp->ShowTopic ((LPWSTR)(LPCWSTR)strDefTopic); phelp->Release(); } else { ReportErrorEx (m_hwnd, IDS_HELPLESS, hr, NULL, 0); hr = S_FALSE; } if (FAILED(hr)) { hr = S_FALSE; } } break;
default: hr = S_FALSE; }
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// IExtendContextMenu
STDMETHODIMP CDSEvent::AddMenuItems(IDataObject* piDataObject, IContextMenuCallback* piCallback, long *pInsertionAllowed) { TRACE(_T("CDSEvent::AddExtensionContextMenuItems()\n")); AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr; CWaitCursor cwait; CInternalFormatCracker dobjCracker;
hr = dobjCracker.Extract(piDataObject); if (FAILED(hr)) { return hr; }
DATA_OBJECT_TYPES dotType = dobjCracker.GetType(); CUINode* pUINode = dobjCracker.GetCookie();
//
// Retrieve the verb handler from the node
// NOTE: multi-selection is handled by cracking the dataobject not by which node
// is called to retrieve the CContextMenuVerbs object
//
CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(m_pComponentData); if (pMenuVerbs == NULL) { ASSERT(FALSE); return E_FAIL; }
CComPtr<IContextMenuCallback2> spContextMenuCallback2; hr = piCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spContextMenuCallback2); if (FAILED(hr)) { ASSERT(FALSE && L"Unable to QI for the IContextMenuCallback2 interface."); return hr; }
if (dotType == CCT_RESULT) { pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb, FALSE/*bScope*/, TRUE /*bSelect*/, pUINode, piDataObject);
//
// Create the main menu, if allowed
//
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { hr = pMenuVerbs->LoadMainMenu(spContextMenuCallback2,piDataObject,pUINode); hr = pMenuVerbs->LoadMenuExtensions(spContextMenuCallback2, m_pComponentData->m_pShlInit, piDataObject, pUINode); } if (SUCCEEDED(hr)) { // create the task menu
if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) { hr = pMenuVerbs->LoadTaskMenu(spContextMenuCallback2,pUINode); } } } else if (dotType == CCT_SCOPE) { pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb, TRUE/*bScope*/, TRUE /*bSelect*/, pUINode, piDataObject); hr = m_pComponentData->AddMenuItems (piDataObject, piCallback, pInsertionAllowed); } else // CCT_UNINITIALIZED
{ if (dobjCracker.GetCookieCount() > 1) { hr = pMenuVerbs->LoadMenuExtensions(spContextMenuCallback2, m_pComponentData->m_pShlInit, piDataObject, pUINode); } } ASSERT( SUCCEEDED(hr) ); return hr; }
STDMETHODIMP CDSEvent::Command(long lCommandID, IDataObject * pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACE(_T("CDSEvent::Command()\n"));
CWaitCursor CWait;
// crack data object
CInternalFormatCracker dobjCracker; HRESULT hr = dobjCracker.Extract(pDataObject); if (FAILED(hr)) { ASSERT(FALSE); // not our data object
return hr; }
DATA_OBJECT_TYPES dotType = dobjCracker.GetType(); if (dotType == CCT_SCOPE) { // if called from the tree view context, delegate to ComponentData
return m_pComponentData->Command(lCommandID, pDataObject); } // context menu shell extensions
if ((lCommandID >= MENU_MERGE_BASE) && (lCommandID <= MENU_MERGE_LIMIT)) { return _CommandShellExtension(lCommandID, pDataObject); }
// standard commands
CUINode* pUINode = dobjCracker.GetCookie(); CDSCookie* pCookie = GetDSCookieFromUINode(pUINode); if ( (pUINode == NULL) ||(pCookie==NULL) ) { ASSERT(FALSE); // Invalid Cookie
return E_INVALIDARG; } switch (lCommandID) { case IDM_GEN_TASK_MOVE: { CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(pUINode); ASSERT(pDSUINode != NULL);
CDSCookie* pMoveCookie = pDSUINode->GetCookie();
hr = m_pComponentData->GetActiveDS()->MoveObject(pMoveCookie); if (hr == S_OK) { CUINode* pNewParentNode = NULL; hr = m_pComponentData->FindParentCookie(pMoveCookie->GetPath(), &pNewParentNode); if ((hr == S_OK) && (pNewParentNode->GetFolderInfo()->IsExpanded())) { pNewParentNode->GetFolderInfo()->AddNode(pUINode); } m_pFrame->UpdateAllViews(pDataObject, (LPARAM)pUINode, DS_MOVE_OCCURRED); } } break;
default: ; } // switch
return S_OK; }
HRESULT CDSEvent::_CommandShellExtension(long nCommandID, LPDATAOBJECT pDataObject) { CWaitCursor wait;
// initialize shell code with data object
IShellExtInit* pShlInit = m_pComponentData->m_pShlInit; // local copy, no addref
HRESULT hr = pShlInit->Initialize(NULL, pDataObject, 0); if (FAILED(hr)) { TRACE(TEXT("pShlInit->Initialize failed, hr: 0x%x\n"), hr); return hr; }
// get the context menu specific interface
CComPtr<IContextMenu> spICM; hr = pShlInit->QueryInterface(IID_IContextMenu, (void **)&spICM); if (FAILED(hr)) { TRACE(TEXT("pShlInit->QueryInterface(IID_IContextMenu, ...) failed, hr: 0x%x\n"), hr); return hr; }
// invoke the shell extension command
HWND hwnd; CMINVOKECOMMANDINFO cmiCommand; hr = m_pFrame->GetMainWindow (&hwnd); ASSERT (hr == S_OK); cmiCommand.hwnd = hwnd; cmiCommand.cbSize = sizeof (CMINVOKECOMMANDINFO); cmiCommand.fMask = SEE_MASK_ASYNCOK; cmiCommand.lpVerb = MAKEINTRESOURCEA(nCommandID - MENU_MERGE_BASE); spICM->InvokeCommand (&cmiCommand);
CInternalFormatCracker dobjCracker; hr = dobjCracker.Extract(pDataObject); if (FAILED(hr)) { ASSERT(FALSE); // not our data object
return hr; }
// -----------------------------------------------------------------
// code to update the views if the extension says it moved items
//
TRACE(_T("Command: returned from extension commdand\n"));
CUINodeList nodesMoved;
HSCOPEITEM ItemID; CUINode* pCurrentParentNode = NULL; CUINode* pNewParentNode = NULL;
for (UINT index = 0; index < dobjCracker.GetCookieCount(); index ++) { CUINode* pUINode = dobjCracker.GetCookie(index);
// make sure the node moved is of the right type: for the time
// being we just deal with DS objects
if (!IS_CLASS(*pUINode, CDSUINode)) { ASSERT(FALSE); // should not get here
continue; } CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
if (pUINode->GetExtOp() & OPCODE_MOVE) { if (pNewParentNode == NULL) { // get the parent from the first node
// assume that all have the same parent
m_pComponentData->FindParentCookie(pCookie->GetPath(), &pNewParentNode); }
pCurrentParentNode = pUINode->GetParent(); if (pCurrentParentNode && IS_CLASS(*pCurrentParentNode, CDSUINode)) { if (pUINode->IsContainer()) { ItemID = pUINode->GetFolderInfo()->GetScopeItem();
// delete the scope item in MMC
hr = m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE); ASSERT(SUCCEEDED(hr)); #ifdef DBG
if (FAILED(hr)) { TRACE(_T("DeleteItem failed on %lx (%s).\n"), ItemID, pUINode->GetName()); } TRACE(_T("Move postprocessing - deleted scope node: %x (%s)\n"), ItemID, pUINode->GetName()); #endif
if (pCurrentParentNode) { pCurrentParentNode->GetFolderInfo()->RemoveNode(pUINode); }
if ((pNewParentNode) && pNewParentNode->GetFolderInfo()->IsExpanded()) { pUINode->ClearParent(); pNewParentNode->GetFolderInfo()->AddNode(pUINode); hr = m_pComponentData->_AddScopeItem(pUINode, pNewParentNode->GetFolderInfo()->GetScopeItem()); #ifdef DBG
if (FAILED(hr)) { TRACE(_T("AddItem failed on %lx (%s).\n"), ItemID, pUINode->GetName()); } TRACE(_T("Move postprocessing - added scope node: %s\n"), pUINode->GetName()); #endif
} else { // not expanded
delete pCookie; pCookie = NULL; } } else { // not a container
if ((pNewParentNode) && (pNewParentNode->GetFolderInfo()->IsExpanded())) { pUINode->ClearParent(); pNewParentNode->GetFolderInfo()->AddNode(pUINode); } nodesMoved.AddTail(pUINode); } } if (pUINode) { pUINode->SetExtOp(NULL); } } } // for items in multiple selection
if (!nodesMoved.IsEmpty()) { m_pFrame->UpdateAllViews(NULL, (LPARAM)&nodesMoved, DS_MULTIPLE_MOVE_OCCURRED); } //------------------------------ends here--------------------------------------
m_pComponentData->SortResultPane(pNewParentNode); return S_OK; }
HRESULT CDSEvent::_InitView(CUINode* pUINode) { CWaitCursor wait;
HRESULT hr=S_OK;
//
// This is more a suggestion than anything so its OK to ignore the return value but
// we will ASSERT for testing purposes
//
hr = m_pResultData->ModifyViewStyle(MMC_ENSUREFOCUSVISIBLE, (MMC_RESULT_VIEW_STYLE)0); ASSERT(SUCCEEDED(hr));
hr=_SetColumns(pUINode);
m_pSelectedFolderNode = pUINode;
return hr; }
HRESULT CDSEvent::_EnumerateCookie(CUINode* pUINode, HSCOPEITEM hParent, MMC_NOTIFY_TYPE event) { TRACE(_T("CDSEvent::_EnumerateCookie()\n")); HRESULT hr = S_OK;
CWaitCursor cwait;
if ( (pUINode == NULL) || (!pUINode->IsContainer()) ) { ASSERT(FALSE); // Invalid Arguments
return E_INVALIDARG; }
if (MMCN_SHOW == event) { _InitView(pUINode);
if (!pUINode->GetFolderInfo()->IsExpanded()) { m_pComponentData->_OnExpand(pUINode, hParent, event); }
_DisplayCachedNodes(pUINode); pUINode->GetFolderInfo()->UpdateSerialNumber(m_pComponentData);
if (pUINode->GetFolderInfo()->GetSortOnNextSelect()) { m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_SORT_RESULT_PANE); pUINode->GetFolderInfo()->SetSortOnNextSelect(FALSE); }
} return hr; }
HRESULT CDSEvent::_DisplayCachedNodes(CUINode* pUINode) { if ( (pUINode == NULL) || (!pUINode->IsContainer()) ) { ASSERT(FALSE); // Invalid Arguments
return E_INVALIDARG; }
HRESULT hr = S_OK;
// Add the leaf nodes
CUINodeList* pLeafList = pUINode->GetFolderInfo()->GetLeafList();
for (POSITION pos = pLeafList->GetHeadPosition(); pos != NULL; ) { POSITION prevPos = pos; CUINode* pCurrChildUINode = pLeafList->GetNext(pos); ASSERT(pCurrChildUINode != NULL); if (pCurrChildUINode->GetExtOp() & OPCODE_MOVE) { pLeafList->RemoveAt(prevPos); pCurrChildUINode->SetExtOp(NULL); delete pCurrChildUINode; } else { hr = _AddResultItem(pCurrChildUINode); } }
_UpdateObjectCount(FALSE /* set count to 0?*/);
return S_OK; }
HRESULT CDSEvent::_AddResultItem(CUINode* pUINode, BOOL bSetSelect) { if (pUINode == NULL) { ASSERT(FALSE); // Invalid Arguments
return E_INVALIDARG; }
HRESULT hr = S_OK;
RESULTDATAITEM rdiListView; ZeroMemory(&rdiListView, sizeof(RESULTDATAITEM));
rdiListView.lParam = reinterpret_cast<LPARAM>(pUINode); rdiListView.mask = RDI_STR | RDI_IMAGE | RDI_PARAM; rdiListView.str = MMC_CALLBACK; rdiListView.nImage = MMC_IMAGECALLBACK;
if (bSetSelect) { rdiListView.mask |= RDI_STATE; rdiListView.nState = LVIS_SELECTED | LVIS_FOCUSED; } return hr = m_pResultData->InsertItem(&rdiListView); }
HRESULT CDSEvent::SelectResultNode(CUINode* pUINode) { HRESULTITEM ItemID = 0; HRESULT hr = m_pResultData->FindItemByLParam ((LPARAM)pUINode, &ItemID); if (SUCCEEDED(hr)) { hr = m_pResultData->ModifyItemState(0 /*unused*/, ItemID, LVIS_FOCUSED | LVIS_SELECTED, 0 /*no removing*/); } return hr; }
void CDSEvent::_DeleteSingleSel(IDataObject* pDataObject, CUINode* pUINode) { ASSERT(!pUINode->IsContainer()); HRESULT hr = S_OK;
//
// Get the parent container for later use
//
CUINode* pParentNode = pUINode->GetParent(); ASSERT(pParentNode != NULL);
CDSCookie* pCookie = NULL; if (IS_CLASS(*pUINode, CDSUINode)) { pCookie = GetDSCookieFromUINode(pUINode);
if (pCookie == NULL) { return; }
//
// delete from the back end
// this call will handle the notifification to extensions
//
hr = m_pComponentData->_DeleteFromBackEnd(pDataObject, pCookie); } else { hr = pUINode->Delete(m_pComponentData); }
//
// update the result pane
//
if (SUCCEEDED(hr) && (hr != S_FALSE)) { m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_DELETE_OCCURRED); }
//
// Remove the '+' next to the parent in the UI if this is the last container
// object in this container
//
if (pParentNode != NULL && pParentNode->GetFolderInfo()->GetContainerList()->GetCount() == 0) { SCOPEDATAITEM sdi; memset(&sdi, 0, sizeof(SCOPEDATAITEM));
sdi.ID = pParentNode->GetFolderInfo()->GetScopeItem(); sdi.mask |= SDI_CHILDREN; sdi.cChildren = 0;
hr = m_pScopeData->SetItem(&sdi); }
}
///////////////////////////////////////////////////////////////////////////
// CResultPaneMultipleDeleteHandler
class CResultPaneMultipleDeleteHandler : public CMultipleDeleteHandlerBase { public: CResultPaneMultipleDeleteHandler(CDSComponentData* pComponentData, HWND hwnd, IDataObject* pDataObject, CInternalFormatCracker* pObjCracker, CUINodeList* pNodesDeletedList) : CMultipleDeleteHandlerBase(pComponentData, hwnd) { m_pDataObject = pDataObject; m_pObjCracker = pObjCracker; m_pNodesDeletedList = pNodesDeletedList; }
protected: virtual UINT GetItemCount() { return m_pObjCracker->GetCookieCount();} virtual HRESULT BeginTransaction() { return GetTransaction()->Begin(m_pDataObject, NULL, NULL, FALSE); } virtual HRESULT DeleteObject(UINT i) { CUINode* pUINode = m_pObjCracker->GetCookie(i); CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
if (pCookie != NULL) { // need to pass full ADSI path to ObjectDeletionCheck
CString strPath; GetComponentData()->GetBasePathsInfo()->ComposeADsIPath( strPath, pCookie->GetPath());
bool fAlternateDeleteMethod = false; HRESULT hr = ObjectDeletionCheck( strPath, pCookie->GetName(), pCookie->GetClass(), fAlternateDeleteMethod ); if ( FAILED(hr) || HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr || fAlternateDeleteMethod ) return hr; }
return GetComponentData()->GetActiveDS()->DeleteObject(pCookie, FALSE); //raise UI for error?
} virtual HRESULT DeleteSubtree(UINT i) { CUINode* pUINode = m_pObjCracker->GetCookie(i); CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
return GetComponentData()->_DeleteSubtreeFromBackEnd(pCookie); } virtual void OnItemDeleted(UINT i) { CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(m_pObjCracker->GetCookie(i)); ASSERT(pDSUINode != NULL);
m_pNodesDeletedList->AddTail(pDSUINode); } virtual void GetItemName(IN UINT i, OUT CString& szName) { CUINode* pUINode = m_pObjCracker->GetCookie(i); CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
if (pCookie != NULL) { szName = pCookie->GetName(); } }
virtual void GetItemPath(UINT i, CString& szPath) { CUINode* pUINode = m_pObjCracker->GetCookie(i); CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
if (pCookie != NULL) { GetComponentData()->GetBasePathsInfo()->ComposeADsIPath(szPath, pCookie->GetPath()); } } virtual PCWSTR GetItemClass(UINT i) { CUINode* pUINode = m_pObjCracker->GetCookie(i); CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
PCWSTR pszClass = NULL; if (pCookie != NULL) { pszClass = pCookie->GetClass(); } return pszClass; } private: IDataObject* m_pDataObject; CInternalFormatCracker* m_pObjCracker; CUINodeList* m_pNodesDeletedList;
};
void CDSEvent::_DeleteNodeListFromUI(CUINodeList* pNodesDeletedList) { // finally, we have to update the UI
if (pNodesDeletedList->GetCount() == 0) { return; }
TIMER(_T("updating UI after delete, containers first.\n"));
//walk this cookie list and take
//care of the containers (scope pane items)
for (POSITION pos = pNodesDeletedList->GetHeadPosition(); pos != NULL; ) { POSITION posCurrNode = pos; CUINode* pCurrNode = pNodesDeletedList->GetNext(pos); ASSERT(pCurrNode != NULL); HSCOPEITEM ItemID, ParentItemID; if (pCurrNode->IsContainer()) { ItemID = pCurrNode->GetFolderInfo()->GetScopeItem(); CUINode* pParentNode = NULL; HRESULT hr = m_pComponentData->m_pScope->GetParentItem(ItemID, &ParentItemID, (MMC_COOKIE *)&pParentNode); m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE); if (SUCCEEDED(hr)) { pParentNode->GetFolderInfo()->DeleteNode(pCurrNode); pNodesDeletedList->RemoveAt(posCurrNode); } } // container
} // for
TIMER(_T("updating UI after delete, now the leaf items.\n"));
// now update all the views to take care of result pane items
m_pFrame->UpdateAllViews(NULL, (LPARAM)pNodesDeletedList, DS_MULTIPLE_DELETE_OCCURRED); TIMER(_T("updating UI after delete, done.\n"));
}
void CDSEvent::_DeleteMultipleSel(IDataObject* pDataObject, CInternalFormatCracker* pObjCracker) { // handle the deletion in the back end involving the extensions
// by calling the delete handler
//
// Get the parent container
//
CUINode* pContainerNode = NULL; CUINode* pUINode = pObjCracker->GetCookie(); if (pUINode != NULL) { pContainerNode = pUINode->GetParent(); } else { ASSERT(FALSE); }
// REVIEW_MARCOC_PORT: for the time being we assume that all the
// items in the multiple selection are of DS type
if (!AreAllNodesOfType<CDSUINode>(pObjCracker)) { //
// Delegate the delete to the container object
//
if (pContainerNode != NULL) { pContainerNode->DeleteMultiselect(m_pComponentData, pObjCracker); } else { ASSERT(FALSE); } } else // All are DS nodes
{ CUINodeList nodesDeletedList; CResultPaneMultipleDeleteHandler deleteHandler(m_pComponentData, m_hwnd, pDataObject, pObjCracker, &nodesDeletedList); deleteHandler.Delete();
_DeleteNodeListFromUI(&nodesDeletedList); } //
// Remove the '+' sign in the UI if this was the last container child in this container
//
if (pContainerNode != NULL && pContainerNode->GetFolderInfo()->GetContainerList()->GetCount() == 0) { SCOPEDATAITEM sdi; memset(&sdi, 0, sizeof(SCOPEDATAITEM));
sdi.ID = pContainerNode->GetFolderInfo()->GetScopeItem(); sdi.mask |= SDI_CHILDREN; sdi.cChildren = 0;
m_pComponentData->m_pScope->SetItem(&sdi); } }
void CDSEvent::_Delete(IDataObject* pDataObject, CInternalFormatCracker* pObjCracker) { CWaitCursor cwait;
// protect against deletion with sheets up
if (m_pComponentData->_WarningOnSheetsUp(pObjCracker)) return;
// do the actual deletion
if (pObjCracker->GetCookieCount() == 1) { _DeleteSingleSel(pDataObject, pObjCracker->GetCookie()); } else { _DeleteMultipleSel(pDataObject, pObjCracker); } }
BOOL AllObjectsHaveTheSameServerName(IN LPCWSTR lpszServerName, IN CObjectNamesFormatCracker* pObjectNamesFormatPaste) { if (lpszServerName == NULL) { ASSERT(FALSE); return FALSE; } CComBSTR bstrCurrServerName; for (UINT k=0; k<pObjectNamesFormatPaste->GetCount(); k++) { HRESULT hr = GetServerFromLDAPPath(pObjectNamesFormatPaste->GetName(k), &bstrCurrServerName); if (FAILED(hr) || (&bstrCurrServerName == NULL)) { // something was wrong
return FALSE; } if (_wcsicmp(lpszServerName, bstrCurrServerName) != 0) { // got something different
return FALSE; } } return TRUE; // all are the same
}
BOOL HasSameObject(IN CUINode* pUINode, IN IDataObject* pPasteData) { if (pUINode == NULL) { ASSERT(FALSE); return FALSE; }
//
// Check to see if the target is a DS node
//
CDSUINode* pDSTargetNode = NULL; BOOL bCookieIsDSUINode = FALSE; if(IS_CLASS(*pUINode, CDSUINode)) { bCookieIsDSUINode = TRUE; pDSTargetNode = dynamic_cast<CDSUINode*>(pUINode); }
CInternalFormatCracker ifc; HRESULT hr = ifc.Extract(pPasteData); if (SUCCEEDED(hr)) { for (UINT k=0; k < ifc.GetCookieCount(); k++) { //
// If the cookies are the same return TRUE
//
if (ifc.GetCookie(k) == pUINode) { return TRUE; }
if (bCookieIsDSUINode && pDSTargetNode != NULL) { //
// If its a DS node and their DNs are the same return TRUE
//
CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(ifc.GetCookie(k)); if (pDSUINode != NULL) { if (_wcsicmp(pDSUINode->GetName(), pDSTargetNode->GetName()) == 0) { return TRUE; } } } } } return FALSE; // all are the different
}
HRESULT CDSEvent::_QueryPaste(IN CUINode* pUINode, // paste target data object (container)
IN IDataObject* pPasteData // paste argument data object
) { TRACE(L"CDSEvent::_QueryPaste()\n"); HRESULT hr = S_OK; ASSERT(pUINode != NULL); ASSERT(pUINode->IsContainer()); TRACE(L"MMCN_QUERY_PASTE on %s\n", pUINode->GetName());
// First lets make sure we are talking within the same snapin type
// For instance we will allow paste between instances of AD U&C
// but we will not allow paste between AD S&S and AD U&C
CInternalFormatCracker ifc; hr = ifc.Extract(pPasteData); if (FAILED(hr) || !ifc.HasData()) { return S_FALSE; }
if (m_pComponentData->QuerySnapinType() != ifc.GetSnapinType()) { // The snapins are not of the same type so fail
return S_FALSE; }
if (!IS_CLASS(*pUINode, CDSUINode)) { //
// For non DS nodes we will delegate the operation to the node itself
//
hr = pUINode->QueryPaste(pPasteData, m_pComponentData); return hr; }
// it is a DS object, extract the cookie
CDSCookie* pCookie = GetDSCookieFromUINode(pUINode); ASSERT(pCookie != NULL); TRACE(L"MMCN_QUERY_PASTE on %s\n",pCookie->GetPath());
CObjectNamesFormatCracker objectNamesFormatPaste; hr = objectNamesFormatPaste.Extract(pPasteData);
if (!objectNamesFormatPaste.HasData() || (objectNamesFormatPaste.GetCount() < 1)) { // we have something that does not contain the
// data format for DS operations
return S_FALSE; }
if (SNAPINTYPE_SITE == m_pComponentData->QuerySnapinType()) { //
// DSSite
//
if (_wcsicmp(pCookie->GetClass(), L"serversContainer") != 0) { //
// Drops only allowed on sites
//
return S_FALSE; }
//
// We only allow servers to be moved between sites
//
for (UINT idx = 0; idx < objectNamesFormatPaste.GetCount(); idx++) { if (_wcsicmp(objectNamesFormatPaste.GetClass(idx), L"server") != 0) { return S_FALSE; } }
// make sure all items have the same server in the LDAP path
if (!AllObjectsHaveTheSameServerName( m_pComponentData->GetBasePathsInfo()->GetServerName(), &objectNamesFormatPaste)) { return S_FALSE; }
return S_OK; }
//
// DSAdmin
//
// we do not allow drops on users, contacts,
// but we do allow drops on computers
// NTRAID#NTBUG9-342116-2001/05/07-sburns
// NOTICE: we allow groups because we allow add to group semantics
if ((_wcsicmp(pCookie->GetClass(), L"user") == 0) || #ifdef INETORGPERSON
(_wcsicmp(pCookie->GetClass(), L"inetOrgPerson") == 0) || #endif
(_wcsicmp(pCookie->GetClass(), L"contact") == 0)) { return S_FALSE; }
// make sure all items have the same server in the LDAP path
if (!AllObjectsHaveTheSameServerName( m_pComponentData->GetBasePathsInfo()->GetServerName(), &objectNamesFormatPaste)) { return S_FALSE; }
//
// make sure we are not dropping an object on itself
//
if (HasSameObject(pUINode, pPasteData)) { return S_FALSE; }
if (_wcsicmp(pCookie->GetClass(), L"group") == 0) { //
// Check to see if we are trying to add a group type to this group
// that is illegal
//
//
// Retrieve the group type
//
INT iGroupType = -1; CDSCookieInfoGroup* pExtraInfo = dynamic_cast<CDSCookieInfoGroup*>(pCookie->GetExtraInfo()); if (pExtraInfo != NULL) { iGroupType = pExtraInfo->m_GroupType; } else { //
// Couldn't retrieve the group type so don't allow anything to be added
//
return S_FALSE; }
//
// See if we are in native mode or mixed mode
//
BOOL bMixedMode = TRUE; CString szDomainRoot; m_pComponentData->GetBasePathsInfo()->GetDefaultRootPath(szDomainRoot); if (!szDomainRoot.IsEmpty()) { //
// bind to the domain object
//
CComPtr<IADs> spDomainObj; hr = DSAdminOpenObject(szDomainRoot, IID_IADs, (void **) &spDomainObj, TRUE /*bServer*/); if (SUCCEEDED(hr)) { //
// retrieve the mixed node attribute
//
CComVariant Mixed; CComBSTR bsMixed(L"nTMixedDomain"); spDomainObj->Get(bsMixed, &Mixed); bMixedMode = (BOOL)Mixed.bVal; } }
//
// Loop through the objects passed by the data object
// looking for groups
//
for (UINT k=0; k < ifc.GetCookieCount(); k++) { CUINode* pNode = ifc.GetCookie(k); if (pNode != NULL) { //
// Must be a DS node to be added to a group
//
if (!IS_CLASS(*pNode, CDSUINode)) { return S_FALSE; }
CDSCookie* pTempCookie = dynamic_cast<CDSCookie*>(pNode->GetNodeData()); if (pTempCookie) { if (!m_pComponentData->CanAddCookieToGroup(pTempCookie, iGroupType, bMixedMode)) { return S_FALSE; } } } } }
return S_OK; // we allow to paste
}
// given an LDAP path, it returns
// the LDAP path and the class of the container
// e.g. given "LDAP://foo.com/cn=a,cn=b,..."
// it returns "LDAP://foo.com/cn=b,..." and "b_class"
HRESULT GetContainerLdapPathAndClass(IN LPCWSTR lpszLdapPath, OUT BSTR* pbstrSourceContainerPath, OUT BSTR* pbstrSourceContainerClass) { if (*pbstrSourceContainerPath != NULL) { ::SysFreeString(*pbstrSourceContainerPath); *pbstrSourceContainerPath = NULL; } if (*pbstrSourceContainerClass != NULL) { ::SysFreeString(*pbstrSourceContainerClass); *pbstrSourceContainerClass = NULL; }
// remove leaf element from path
CPathCracker pathCracker; HRESULT hr = pathCracker.Set((LPWSTR)lpszLdapPath, ADS_SETTYPE_FULL); RETURN_IF_FAILED(hr); hr = pathCracker.RemoveLeafElement(); RETURN_IF_FAILED(hr); CComBSTR bstrParentLdapPath; hr = pathCracker.Retrieve(ADS_FORMAT_X500, pbstrSourceContainerPath); RETURN_IF_FAILED(hr);
// now try to bind and determine the class of the object
CComPtr<IADs> spParentIADs; hr = DSAdminOpenObject(*pbstrSourceContainerPath, IID_IADs, (void **)&spParentIADs, TRUE /*bServer*/); RETURN_IF_FAILED(hr); CComBSTR bstrParentClass; hr = spParentIADs->get_Class(pbstrSourceContainerClass); RETURN_IF_FAILED(hr);
return S_OK; }
// given an LDAP path, it returns
// the DN of the container
// e.g. given "LDAP://foo.com/cn=a,cn=b,..."
// it returns "cn=b,..."
HRESULT GetContainerDN(IN LPCWSTR lpszLdapPath, OUT BSTR* pbstrSourceContainerDN) { if (*pbstrSourceContainerDN != NULL) { ::SysFreeString(*pbstrSourceContainerDN); *pbstrSourceContainerDN = NULL; } CPathCracker pathCracker; HRESULT hr = pathCracker.Set((LPWSTR)lpszLdapPath, ADS_SETTYPE_FULL); RETURN_IF_FAILED(hr); hr = pathCracker.RemoveLeafElement(); RETURN_IF_FAILED(hr); return pathCracker.Retrieve(ADS_FORMAT_X500_DN, pbstrSourceContainerDN); }
void CDSEvent::_Paste( IN CUINode* pUINode, // paste target (container)
IN IDataObject* pPasteData, // paste argument data object
OUT LPDATAOBJECT* ppCutDataObj // data object to return for a cut operation
) { TRACE(L"CDSEvent::_Paste()\n");
ASSERT(pUINode != NULL); ASSERT(pUINode->IsContainer()); TRACE(L"MMCN_PASTE on %s\n", pUINode->GetName());
if (ppCutDataObj == NULL) { //
// We only support copy in the Saved Queries tree
//
pUINode->Paste(pPasteData, m_pComponentData, NULL); return; }
TRACE(L"ppCutDataObj != NULL, cut\n"); *ppCutDataObj = NULL;
if (!IS_CLASS(*pUINode, CDSUINode)) { //
// Delegate the paste for non DS nodes to the node itself
//
pUINode->Paste(pPasteData, m_pComponentData, ppCutDataObj); return; } // it is a DS object, extract the cookie
CDSCookie* pCookie = GetDSCookieFromUINode(pUINode); ASSERT(pCookie != NULL); TRACE(L"MMCN_PASTE on %s\n",pCookie->GetPath());
CObjectNamesFormatCracker objectNamesFormatPaste; HRESULT hr = objectNamesFormatPaste.Extract(pPasteData);
if (!objectNamesFormatPaste.HasData() || (objectNamesFormatPaste.GetCount() < 1)) { // we have something that does not contain the
// data format for DS operations
ASSERT(FALSE); return; } UINT nPasteCount = objectNamesFormatPaste.GetCount(); #ifdef DBG
// see what we are pasting
for (UINT kTest=0; kTest<nPasteCount; kTest++) { TRACE(L"Pasting = %s\n", objectNamesFormatPaste.GetName(kTest)); } #endif
// short circuit if the source container
// is the same as this container (drop onto itself)
CComBSTR bstrContainerDN; hr = GetContainerDN(objectNamesFormatPaste.GetName(0), &bstrContainerDN); if (FAILED(hr)) { // something is really bad here...
ASSERT(FALSE); return; } if (_wcsicmp(pCookie->GetPath(), bstrContainerDN) == 0) { TRACE(L"Dropping on the same container, short circuiting\n"); return; }
// make sure all items have the same server in the LDAP path
if (!AllObjectsHaveTheSameServerName( m_pComponentData->GetBasePathsInfo()->GetServerName(), &objectNamesFormatPaste)) { ASSERT(FALSE); return; }
// we do not allow drops on users,
// but we do allow drops on computers
// NTRAID#NTBUG9-342116-2001/05/07-sburns
if ((_wcsicmp(pCookie->GetClass(), L"user") == 0) || #ifdef INETORGPERSON
(_wcsicmp(pCookie->GetClass(), L"inetOrgPerson") == 0)) #endif
{ return; } // if it is a group, dropping means adding to group
if (_wcsicmp(pCookie->GetClass(), L"group") == 0) { _PasteAddToGroup(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatPaste, ppCutDataObj); return; }
//
// We also want the internal clipboard format so that we can change the path of
// object(s) that was/were the source of the move
//
CInternalFormatCracker ifc; hr = ifc.Extract(pPasteData); if (SUCCEEDED(hr)) { _PasteDoMove(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatPaste, &ifc, ppCutDataObj); } else { //
// The move can succeed without the internal clipboard format but if the source
// was from a saved query then it will not be updated with the new path.
//
_PasteDoMove(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatPaste, NULL, ppCutDataObj); }
}
void CDSEvent::_PasteDoMove(CDSUINode* pTargetUINode, CObjectNamesFormatCracker* pObjectNamesFormatPaste, CInternalFormatCracker* pInternalFC, LPDATAOBJECT* ppCutDataObj) { //
// Get the UI source node
//
CUINode* pSourceNode = NULL; if (pInternalFC != NULL) { pSourceNode = pInternalFC->GetCookie()->GetParent(); }
//
// Get the actual source containers from the DS
// There can be more than one source node especially if the move is from a
// Saved Query so make a list of all the parents
//
CUINodeList possibleMovedObjectList;
for (UINT idx = 0; idx < pObjectNamesFormatPaste->GetCount(); idx++) { CUINode* pTempChildNode = NULL;
CString szDN; StripADsIPath(pObjectNamesFormatPaste->GetName(idx), szDN); if (m_pComponentData->FindUINodeByDN(m_pComponentData->GetRootNode(), szDN, &pTempChildNode)) { if (pTempChildNode != NULL) { possibleMovedObjectList.AddTail(pTempChildNode); } } }
// bind to the first item in the paste selection and
// try to get to the container object
CComBSTR bstrSourceContainerPath; CComBSTR bstrSourceContainerClass;
HRESULT hr = GetContainerLdapPathAndClass(pObjectNamesFormatPaste->GetName(0), &bstrSourceContainerPath, &bstrSourceContainerClass); if (FAILED(hr)) { ASSERT(FALSE); return; } // create a data object to specify the source container
// the objects are moved from
CComPtr<IDataObject> spDataObjectContainer; hr = CDSNotifyHandlerTransaction::BuildTransactionDataObject( bstrSourceContainerPath, bstrSourceContainerClass, TRUE /*bContainer*/, m_pComponentData, &spDataObjectContainer);
if (FAILED(hr)) { ASSERT(FALSE); return; }
CMultiselectMoveHandler moveHandler(m_pComponentData, m_hwnd, NULL); hr = moveHandler.Initialize(spDataObjectContainer, pObjectNamesFormatPaste, pInternalFC); ASSERT(SUCCEEDED(hr));
CString szTargetContainer; m_pComponentData->GetBasePathsInfo()->ComposeADsIPath(szTargetContainer, pTargetUINode->GetCookie()->GetPath());
moveHandler.Move(szTargetContainer);
*ppCutDataObj = NULL; CUINodeList nodesMoved;
// -----------------------------------------------------------------
// code to update the views if the extension says it moved items
//
TRACE(_T("Command: returned from extension commdand\n"));
if (pSourceNode != NULL && IS_CLASS(*pSourceNode, CDSUINode)) { for (UINT index = 0; index < pInternalFC->GetCookieCount(); index ++) { CUINode* pUINode = pInternalFC->GetCookie(index);
// make sure the node moved is of the right type: for the time
// being we just deal with DS objects
if (!IS_CLASS(*pUINode, CDSUINode)) { ASSERT(FALSE); // should not get here
continue; } CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
if (pUINode->GetExtOp() & OPCODE_MOVE) { if (pTargetUINode == NULL) { // get the parent from the first node
// assume that all have the same parent
CUINode* pPossibleTargetNode = NULL; m_pComponentData->FindParentCookie(pCookie->GetPath(), &pPossibleTargetNode); if (pPossibleTargetNode != NULL) { pTargetUINode = dynamic_cast<CDSUINode*>(pPossibleTargetNode); } }
if (pUINode->IsContainer()) { HSCOPEITEM ItemID = 0, ParentItemID = 0; ItemID = pUINode->GetFolderInfo()->GetScopeItem(); if (pSourceNode == NULL) { // do it once for the first node, all the same
hr = m_pComponentData->m_pScope->GetParentItem (ItemID, &ParentItemID, (MMC_COOKIE *)&pSourceNode); }
// delete the scope item in MMC
hr = m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE); ASSERT(SUCCEEDED(hr)); #ifdef DBG
if (FAILED(hr)) { TRACE(_T("DeleteItem failed on %lx (%s).\n"), ItemID, pUINode->GetName()); } TRACE(_T("Move postprocessing - deleted scope node: %x (%s)\n"), ItemID, pUINode->GetName()); #endif
if (pSourceNode) { pSourceNode->GetFolderInfo()->RemoveNode(pUINode); } //
// Remove all children and mark it as unexpanded so that it will be expanded
// when selected
//
pUINode->GetFolderInfo()->DeleteAllContainerNodes(); pUINode->GetFolderInfo()->DeleteAllLeafNodes(); pUINode->GetFolderInfo()->ReSetExpanded();
if ((pTargetUINode) && pTargetUINode->GetFolderInfo()->IsExpanded()) { pUINode->ClearParent(); pTargetUINode->GetFolderInfo()->AddNode(pUINode); hr = m_pComponentData->_AddScopeItem(pUINode, pTargetUINode->GetFolderInfo()->GetScopeItem()); #ifdef DBG
if (FAILED(hr)) { TRACE(_T("AddItem failed on %lx (%s).\n"), ItemID, pUINode->GetName()); } TRACE(_T("Move postprocessing - added scope node: %s\n"), pUINode->GetName()); #endif
} else { //
// This object was created during the enumeration of the source container.
// Since the target container hasn't been expanded yet we can just throw
// this node away and it will be recreated if the target node ever gets
// expanded
//
delete pUINode; pUINode = NULL; } } else { // not a container
if ((pTargetUINode) && (pTargetUINode->GetFolderInfo()->IsExpanded())) { pUINode->ClearParent(); pTargetUINode->GetFolderInfo()->AddNode(pUINode); }
//
// If the folder is not select (like on cut/paste)
// the FindItemByLParam() in UpdateAllViews will fail
// and the node will not be removed from the UI.
// So just remove it from the node list of the source
// container.
//
if (pSourceNode && m_pSelectedFolderNode != pSourceNode) { pSourceNode->GetFolderInfo()->RemoveNode(pUINode); } nodesMoved.AddTail(pUINode); } if (pUINode) { pUINode->SetExtOp(NULL); } } } } else if (pSourceNode != NULL && IS_CLASS(*pSourceNode, CSavedQueryNode)) { //
// Refresh the target node so that we get new cookies
// for all the moved objects. It would just be too
// difficult to do a deep copy of the cookies in the
// saved query tree
//
if (pTargetUINode && pTargetUINode->GetFolderInfo()->IsExpanded()) { m_pComponentData->Refresh(pTargetUINode); }
//
// Mark the moved leaf objects with the opcode. Simply remove containers from
// the UI and the list. The move handler only marks the
// selected items, not those found using FindUINodeByDN.
//
POSITION posPossible = possibleMovedObjectList.GetHeadPosition(); while (posPossible) { CUINode* pPossibleMoved = possibleMovedObjectList.GetNext(posPossible); if (pPossibleMoved) { if (pPossibleMoved->IsContainer()) { HSCOPEITEM ItemID = 0; ItemID = pPossibleMoved->GetFolderInfo()->GetScopeItem();
// delete the scope item in MMC
hr = m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE); if (SUCCEEDED(hr)) { hr = pPossibleMoved->GetParent()->GetFolderInfo()->RemoveNode(pPossibleMoved); } } else { pPossibleMoved->SetExtOp(OPCODE_MOVE); } } }
//
// Now reset the opcode for all the nodes in the saved query tree so
// that they will still show up the next time the saved query node is selected
//
for (UINT index = 0; index < pInternalFC->GetCookieCount(); index ++) { CUINode* pUINode = pInternalFC->GetCookie(index);
if (pUINode) { pUINode->SetExtOp(NULL); } } // for
} // IS_CLASS
if (!nodesMoved.IsEmpty()) { m_pFrame->UpdateAllViews(NULL, (LPARAM)&nodesMoved, DS_MULTIPLE_MOVE_OCCURRED); } //------------------------------ends here--------------------------------------
m_pComponentData->SortResultPane(pTargetUINode); }
void CDSEvent::_PasteAddToGroup(CDSUINode* pUINode, CObjectNamesFormatCracker* pObjectNamesFormatPaste, LPDATAOBJECT*) { if (_wcsicmp(pUINode->GetCookie()->GetClass(), L"group") != 0) { ASSERT(FALSE); return; } // get the LDAP path of the group we want to add to
CString szGroupLdapPath; m_pComponentData->GetBasePathsInfo()->ComposeADsIPath(szGroupLdapPath, pUINode->GetCookie()->GetPath()); AddDataObjListToGivenGroup(pObjectNamesFormatPaste, szGroupLdapPath, pUINode->GetCookie()->GetName(), m_pComponentData->GetHWnd(), m_pComponentData); }
BOOL FindDSUINodeInListByDN(IN LPCWSTR lpszDN, IN CUINodeList* pNodeList, OUT CDSUINode** ppNode) { *ppNode = NULL; for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; ) { CUINode* pCurrentNode = pNodeList->GetNext(pos); CDSUINode* pCurrDSUINode = dynamic_cast<CDSUINode*>(pCurrentNode); if (pCurrDSUINode == NULL) { // not a node with a cookie, just skip
continue; }
// get the cookie from the node
if (_wcsicmp(lpszDN, pCurrDSUINode->GetCookie()->GetPath()) == 0) { *ppNode = pCurrDSUINode; return TRUE; } }// for
return FALSE; } void FindListOfChildNodes(IN CDSUINode* pDSUIContainerNode, IN CObjectNamesFormatCracker* pObjectNamesFormat, INOUT CUINodeList* pNodesDeletedList) { ASSERT(pDSUIContainerNode != NULL); ASSERT(pDSUIContainerNode->IsContainer());
// it is a DS object, extract the cookie
CDSCookie* pContainerCookie = pDSUIContainerNode->GetCookie(); ASSERT(pContainerCookie != NULL); TRACE(L"FindListOfChildNodes(%s,...)\n",pContainerCookie->GetPath());
//for each item in the list of paths, find it into the list
// of children
CPathCracker pathCracker; UINT nCount = pObjectNamesFormat->GetCount(); for (UINT k=0; k<nCount; k++) { // from the LDAP path, get the DN
HRESULT hr = pathCracker.Set((LPWSTR)pObjectNamesFormat->GetName(k), ADS_SETTYPE_FULL); ASSERT(SUCCEEDED(hr)); CComBSTR bstrDN; hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrDN); ASSERT(SUCCEEDED(hr));
// find it into the lists of children
CDSUINode* pFoundNode = NULL; if (FindDSUINodeInListByDN(bstrDN, pDSUIContainerNode->GetFolderInfo()->GetContainerList(), &pFoundNode)) { ASSERT(pFoundNode != NULL); pNodesDeletedList->AddTail(pFoundNode); continue; } if (FindDSUINodeInListByDN(bstrDN, pDSUIContainerNode->GetFolderInfo()->GetLeafList(), &pFoundNode)) { ASSERT(pFoundNode != NULL); pNodesDeletedList->AddTail(pFoundNode); continue; } } // for
}
void CDSEvent::_CutOrMove(IN IDataObject* pCutOrMoveData) { TRACE(L"CDSEvent::_CutOrMove()\n");
if (pCutOrMoveData == NULL) { //
// With a single pass move operation we return a NULL data object
// but the move was still successful
//
return; }
CInternalFormatCracker ifc; HRESULT hr = ifc.Extract(pCutOrMoveData); if (SUCCEEDED(hr)) { //
// Non DS nodes
//
//
// Build a list of the nodes to be deleted
//
CUINodeList nodesDeletedList; for (UINT nCount = 0; nCount < ifc.GetCookieCount(); nCount++) { CUINode* pUINode = ifc.GetCookie(nCount); if (pUINode != NULL) { nodesDeletedList.AddTail(pUINode); } } //
// finally, delete the nodes from the UI
//
_DeleteNodeListFromUI(&nodesDeletedList); } else { //
// DS Objects
//
CObjectNamesFormatCracker objectNamesFormatCutOrMove; hr = objectNamesFormatCutOrMove.Extract(pCutOrMoveData); if (SUCCEEDED(hr)) { if (!objectNamesFormatCutOrMove.HasData() || (objectNamesFormatCutOrMove.GetCount() < 1)) { // we have something that does not contain the
// data format for DS operations
ASSERT(FALSE); return; }
// make sure all items have the same server in the LDAP path
if (!AllObjectsHaveTheSameServerName( m_pComponentData->GetBasePathsInfo()->GetServerName(), &objectNamesFormatCutOrMove)) { ASSERT(FALSE); return; }
// find the source container the objects are moved from
// (we assume they all come from the same container)
TRACE(L"GetName(0) = %s\n", objectNamesFormatCutOrMove.GetName(0));
CComBSTR bstrContainerDN; hr = GetContainerDN(objectNamesFormatCutOrMove.GetName(0), &bstrContainerDN); if (FAILED(hr)) { ASSERT(FALSE); return; } TRACE(L"GetContainerDN() bstrContainerDN = %s\n", bstrContainerDN);
// find the container object in the folders
// NOTICE: for the time being we ignore the query folders
CUINode* pUINode = NULL; if (!FindCookieInSubtree(m_pComponentData->GetRootNode(), bstrContainerDN, m_pComponentData->QuerySnapinType(), &pUINode)) { // should never happen...
return; }
// found the container node
ASSERT(pUINode != NULL); ASSERT(pUINode->IsContainer());
if (!IS_CLASS(*pUINode, CDSUINode)) { // we do not allow paste on non DS nodes,
// so we should never get here...
ASSERT(FALSE); return; }
ASSERT(pUINode->GetFolderInfo()->IsExpanded());
// need to remove the items that are in the data object
// from the pUINode container: find the list of nodes
// to be deleted in the
CUINodeList nodesDeletedList; FindListOfChildNodes(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatCutOrMove, &nodesDeletedList);
// finally, delete the nodes from the UI
_DeleteNodeListFromUI(&nodesDeletedList); } } }
void CDSEvent::HandleViewChange(LPDATAOBJECT pDataObject, LPARAM arg, LPARAM Action) { HRESULT hr = S_OK;
TRACE(_T("handle view change. action is %lx.\n"), Action); switch (Action) { case DS_DELETE_OCCURRED: { HRESULTITEM ItemID; hr = m_pResultData->FindItemByLParam(arg, &ItemID); if (!SUCCEEDED(hr)) { break; } hr = m_pResultData->DeleteItem(ItemID, 0); #ifdef DBG
if (FAILED(hr)) { TRACE (_T("Delete Item Failed on IResultData. Item %lx, hr = %lx\n"), ItemID, hr); } #endif
// this will fail for all but the first update, we don't care
hr = m_pSelectedFolderNode->GetFolderInfo()->DeleteNode(reinterpret_cast<CUINode*>(arg)); _UpdateObjectCount(FALSE); break; } case DS_MULTIPLE_DELETE_OCCURRED: { TIMER(_T("updating result pane for mult. delete ...")); CUINodeList* pNodesDeletedList = reinterpret_cast<CUINodeList*>(arg); // gross
for (POSITION pos = pNodesDeletedList->GetHeadPosition(); pos != NULL; ) { CUINode* pCurrNode = pNodesDeletedList->GetNext(pos); ASSERT(pCurrNode != NULL); HRESULTITEM ItemID; hr = m_pResultData->FindItemByLParam((LPARAM)pCurrNode, &ItemID); if (FAILED(hr)) { //
// We cannot find the item by lParam if the node is not selected so
// just delete the node from the container
//
CUIFolderInfo* pFolderInfo = pCurrNode->GetParent()->GetFolderInfo(); if (pFolderInfo != NULL) { hr = pFolderInfo->DeleteNode(pCurrNode); } continue; } hr = m_pResultData->DeleteItem(ItemID, 0);
CUIFolderInfo* pSelectedFolderInfo = m_pSelectedFolderNode->GetFolderInfo(); if (pSelectedFolderInfo != NULL) { // this will fail for all but the first update, we don't care
hr = m_pSelectedFolderNode->GetFolderInfo()->DeleteNode(pCurrNode); } } _UpdateObjectCount(FALSE); TIMER(_T("updating result pane for mult. delete, done")); } break; case DS_RENAME_OCCURRED: case DS_UPDATE_OCCURRED: { HRESULTITEM ItemID; hr = m_pResultData->FindItemByLParam (arg, &ItemID); if (SUCCEEDED(hr)) { m_pResultData->UpdateItem (ItemID); } break; } case DS_MOVE_OCCURRED: { CDSUINode* pDSUINode = reinterpret_cast<CDSUINode*>(arg); CDSUINode* pDSSelectedFolderNode = dynamic_cast<CDSUINode*>(m_pSelectedFolderNode);
// REVIEW_MARCOC_PORT: this is working for DS objects only
// need to generalize for all folder types
ASSERT(pDSUINode != NULL); ASSERT(pDSSelectedFolderNode != NULL); if ((pDSUINode == NULL) || (pDSSelectedFolderNode == NULL)) break;
// remove the result pane item
HRESULTITEM ItemID; hr = m_pResultData->FindItemByLParam (arg, &ItemID); if (SUCCEEDED(hr)) { hr = m_pSelectedFolderNode->GetFolderInfo()->RemoveNode(pDSUINode); hr = m_pResultData->DeleteItem(ItemID, 0); } CString szParent; hr = m_pComponentData->GetActiveDS()->GetParentDN(pDSUINode->GetCookie(), szParent); if (SUCCEEDED(hr)) { if (szParent.CompareNoCase(pDSSelectedFolderNode->GetCookie()->GetPath()) == 0) { _AddResultItem(pDSUINode);
m_pComponentData->SortResultPane(pDSUINode->GetParent()); _UpdateObjectCount(FALSE); } }
break; } case DS_MULTIPLE_MOVE_OCCURRED: { CUINodeList* pNodesMovedList = reinterpret_cast<CUINodeList*>(arg); // gross
//
// If the selected folder is not a DS node then its probably a saved query
// in which case we just want to break because we don't want to delete the results
// of the saved query just change its path
//
CDSUINode* pDSSelectedFolderNode = dynamic_cast<CDSUINode*>(m_pSelectedFolderNode); if (pDSSelectedFolderNode == NULL) break;
CString ObjPath; CString szParent = L""; BOOL fInThisContainer = FALSE;
for (POSITION pos = pNodesMovedList->GetHeadPosition(); pos != NULL; ) { CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(pNodesMovedList->GetNext(pos)); // REVIEW_MARCOC_PORT: this is working for DS objects only
// need to generalize for all folder types
if (pDSUINode == NULL) { ASSERT(FALSE); break; // can't do it, should be doing it in the future
}
if (!pDSUINode->IsContainer()) { // it s a leaf node, delete from result pane
HRESULTITEM ItemID; hr = m_pResultData->FindItemByLParam ((LPARAM)pDSUINode, &ItemID); if (SUCCEEDED(hr)) { hr = m_pSelectedFolderNode->GetFolderInfo()->RemoveNode(pDSUINode); hr = m_pResultData->DeleteItem(ItemID, 0); } if (szParent.IsEmpty()) { hr = m_pComponentData->GetActiveDS()->GetParentDN(pDSUINode->GetCookie(), szParent); if (SUCCEEDED(hr)) { if (szParent.CompareNoCase(pDSSelectedFolderNode->GetCookie()->GetPath()) == 0) { fInThisContainer = TRUE; } } } if (fInThisContainer) { _AddResultItem(pDSUINode); } } } _UpdateObjectCount(FALSE); break; } case DS_CREATE_OCCURRED_RESULT_PANE: case DS_CREATE_OCCURRED: {
CUINode* pParent = NULL; CUINode* pTmpNode = NULL;
if (pDataObject) { CInternalFormatCracker dobjCracker; VERIFY(SUCCEEDED(dobjCracker.Extract(pDataObject))); pTmpNode = dobjCracker.GetCookie(); if (Action == DS_CREATE_OCCURRED_RESULT_PANE) { pParent = pTmpNode->GetParent(); } else { pParent = pTmpNode; } } else { pParent = m_pSelectedFolderNode; } if (pParent == m_pSelectedFolderNode) { // reset icon list, just in case it was a new type of object
m_pComponentData->FillInIconStrip (m_pRsltImageList);
//
// Add and select the new item
//
_AddResultItem(reinterpret_cast<CUINode*>(arg), FALSE); m_pComponentData->SortResultPane(pParent);
// Must select the result node after the sort to ensure visibility
SelectResultNode(reinterpret_cast<CUINode*>(arg));
_UpdateObjectCount(FALSE); } else { pParent->GetFolderInfo()->SetSortOnNextSelect(TRUE); }
break; } case DS_HAVE_DATA: { CInternalFormatCracker dobjCracker; VERIFY(SUCCEEDED(dobjCracker.Extract(pDataObject))); CUINode* pContainerNode = dobjCracker.GetCookie(); if (pContainerNode == m_pSelectedFolderNode) { TIMER(_T("adding leaf items to view\n")); CUINodeList* pNodeList = reinterpret_cast<CUINodeList*>(arg); for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; ) { CUINode* pNewUINode = pNodeList->GetNext(pos); if (!pNewUINode->IsContainer()) { // add to the scope pane
_AddResultItem(pNewUINode); } _UpdateObjectCount(FALSE); } } break; } case DS_REFRESH_REQUESTED: { CUINode* pUINode = reinterpret_cast<CUINode*>(arg); if (pUINode == m_pSelectedFolderNode) { m_pResultData->DeleteAllRsltItems(); _UpdateObjectCount (TRUE); } break; } case DS_VERB_UPDATE: { CUINode* pUINode = reinterpret_cast<CUINode*>(arg); if (pUINode == m_pSelectedFolderNode) { CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(m_pComponentData);
if (pMenuVerbs == NULL) { ASSERT(FALSE); return; } pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb, TRUE/*bScope*/, TRUE /*bSelect*/, pUINode, pDataObject); } break; } case DS_DELAYED_EXPAND: { CUINode* pUINode = reinterpret_cast<CUINode*>(arg); ASSERT(pUINode->IsContainer()); // if (pCookie == m_pSelectedFolderNode) {
m_pFrame->Expand (pUINode->GetFolderInfo()->GetScopeItem(), TRUE); //}
} break; case DS_ICON_STRIP_UPDATE: { // reset icon list, just in case it was a new type of object
m_pComponentData->FillInIconStrip (m_pRsltImageList); } break;
case DS_IS_COOKIE_SELECTION: { PUINODESELECTION pUINodeSel = reinterpret_cast<PUINODESELECTION>(arg); //gross
if (pUINodeSel->IsSelection) { // got the snawer from some other view, just skip
break; } if (pUINodeSel->pUINode == m_pSelectedFolderNode) { // selected folder in this view
pUINodeSel->IsSelection = TRUE; } else { // not selected in this view, but look for the parents
// of the current selection
CUINode* pParentNode = m_pSelectedFolderNode->GetParent(); while (pParentNode) { if (pUINodeSel->pUINode == pParentNode) { pUINodeSel->IsSelection = TRUE; break; } else { pParentNode = pParentNode->GetParent(); } } // while
} } // case
break;
case DS_SORT_RESULT_PANE: { CUINode* pUINode = reinterpret_cast<CUINode*>(arg); MMC_SORT_SET_DATA* pColumnData = NULL; TIMER(_T("sorting result pane, starting")); CDSColumnSet* pColumnSet = pUINode->GetColumnSet(m_pComponentData); if (pColumnSet == NULL) break; LPCWSTR lpszID = pColumnSet->GetColumnID(); size_t iLen = wcslen(lpszID); // allocate enough memory for the struct and the column ID
SColumnSetID* pNodeID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR))); if (pNodeID != NULL) { memset(pNodeID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR))); pNodeID->cBytes = static_cast<ULONG>(iLen * sizeof(WCHAR)); memcpy(pNodeID->id, lpszID, (iLen * sizeof(WCHAR)));
CComPtr<IColumnData> spColumnData; hr = m_pFrame->QueryInterface(IID_IColumnData, (void**)&spColumnData); if (spColumnData != NULL) { hr = spColumnData->GetColumnSortData(pNodeID, &pColumnData); }
if (hr == S_OK && pColumnData != NULL) { m_pResultData->Sort(pColumnData->pSortData->nColIndex, pColumnData->pSortData->dwSortOptions, NULL); CoTaskMemFree(pColumnData); } else { //
// Sort by the name column ascending if the user hasn't persisted something else
//
m_pResultData->Sort(0, RSI_NOSORTICON, NULL); } free(pNodeID); } else { //
// Sort by the name column ascending if the user hasn't persisted something else
//
m_pResultData->Sort(0, RSI_NOSORTICON, NULL); } break; TIMER(_T("sorting result pane, done"));
if (pUINode != m_pSelectedFolderNode && pUINode->IsContainer()) { pUINode->GetFolderInfo()->SetSortOnNextSelect(TRUE); } } break; case DS_UPDATE_VISIBLE_COLUMNS: { CUINode* pUINode = reinterpret_cast<CUINode*>(arg); if (m_bUpdateAllViewsOrigin) { // this message originated from this instance,
// it is handled separately
break; }
CDSColumnSet* pColumnSet = pUINode->GetColumnSet(m_pComponentData); if (pColumnSet == NULL) break; CComPtr<IColumnData> spColumnData; hr = m_pFrame->QueryInterface(IID_IColumnData, (void**)&spColumnData); if (spColumnData != NULL) hr = pColumnSet->LoadFromColumnData(spColumnData); if (FAILED(hr)) { pColumnSet->SetAllColumnsToDefaultVisibility(); } break; } case DS_UPDATE_OBJECT_COUNT: _UpdateObjectCount(FALSE); break;
case DS_UNSELECT_OBJECT: { CUINode* pUINode = reinterpret_cast<CUINode*>(arg); if (pUINode != NULL) { HRESULTITEM ItemID; hr = m_pResultData->FindItemByLParam ((LPARAM)pUINode, &ItemID); if (SUCCEEDED(hr)) { VERIFY(SUCCEEDED(m_pResultData->ModifyItemState(0 /*unused*/, ItemID, 0 /*not adding*/, LVIS_FOCUSED | LVIS_SELECTED))); } } } break;
} // switch
}
void CDSEvent::_UpdateObjectCount(BOOL fZero) { if (!m_pSelectedFolderNode->IsContainer()) { ASSERT(m_pSelectedFolderNode->IsContainer()); return; }
UINT cItems = 0; if (!fZero) { CUINodeList* pclFolders = m_pSelectedFolderNode->GetFolderInfo()->GetContainerList(); CUINodeList* pclLeaves = m_pSelectedFolderNode->GetFolderInfo()->GetLeafList();
if (pclFolders && pclLeaves) { cItems = (UINT)(pclFolders->GetCount() + pclLeaves->GetCount()); } } else //set the count to 0
{ m_pSelectedFolderNode->GetFolderInfo()->SetTooMuchData(FALSE, 0); } CString csTemp; if (IS_CLASS(*m_pSelectedFolderNode, CSavedQueryNode)) { CSavedQueryNode* pSavedQueryNode = dynamic_cast<CSavedQueryNode*>(m_pSelectedFolderNode); if (pSavedQueryNode && !pSavedQueryNode->IsValid()) { VERIFY(csTemp.LoadString(IDS_DESCBAR_INVALID_SAVEDQUERY)); } }
if (csTemp.IsEmpty()) { if (m_pSelectedFolderNode->GetFolderInfo()->HasTooMuchData()) { UINT nApprox = m_pSelectedFolderNode->GetFolderInfo()->GetApproxTotalContained(); nApprox = __max(nApprox, cItems);
csTemp.Format(IDS_DESCBAR_TOO_MUCH_DATA, nApprox); } else { VERIFY(csTemp.LoadString(IDS_OBJECTS)); } }
CString csDescription; csDescription.Format (L"%d%s", cItems, csTemp); if (m_pComponentData->m_pQueryFilter && m_pComponentData->m_pQueryFilter->IsFilteringActive()) { CString csFilter; csFilter.LoadString (IDS_FILTERING_ON); csDescription += csFilter; }
if (m_pResultData) { m_pResultData->SetDescBarText ((LPWSTR)(LPCWSTR)csDescription); } }
HRESULT CDSEvent::_SetColumns(CUINode* pUINode) { ASSERT(pUINode->IsContainer());
TRACE(_T("CDSEvent::_SetColumns on container %s\n"), (LPWSTR)(LPCWSTR)pUINode->GetName());
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HRESULT hr = S_OK;
CDSColumnSet* pColumnSet = pUINode->GetColumnSet(m_pComponentData); if (pColumnSet == NULL) return hr;
for (POSITION pos = pColumnSet->GetHeadPosition(); pos != NULL; ) { CDSColumn* pColumn = (CDSColumn*)pColumnSet->GetNext(pos); int nWidth = (pColumn->IsVisible()) ? AUTO_WIDTH : HIDE_COLUMN; hr = m_pHeader->InsertColumn(pColumn->GetColumnNum(), pColumn->GetHeader(), pColumn->GetFormat(), nWidth); ASSERT(SUCCEEDED(hr));
hr = m_pHeader->SetColumnWidth(pColumn->GetColumnNum(), pColumn->GetWidth());
ASSERT(SUCCEEDED(hr)); }
return S_OK; }
|