Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1713 lines
59 KiB

/*
* basesnap.cxx
*
*
* Copyright (c) 1998-1999 Microsoft Corporation
*
* PURPOSE: Defines CBaseSnapin.
*
*
* OWNER: ptousig
*/
#include "headers.hxx"
#include "basesnap.rgs"
// Some substitution strings used to create a registry script on the fly.
#define szDLLName L"DLLName"
#define szModule L"Module"
#define szCLSID_Snapin L"CLSID_Snapin"
#define szCLSID_About L"CLSID_About"
#define szClassName L"ClassName"
#define szSnapinName L"SnapinName"
#define szCLSID_NodeType L"CLSID_NodeType"
// -----------------------------------------------------------------------------
CBaseSnapin::CBaseSnapin(void)
{
}
// -----------------------------------------------------------------------------
CBaseSnapin::~CBaseSnapin(void)
{
// Release all of our root items.
while (m_ilRootItems.empty() == false)
{
static_cast<LPDATAOBJECT>(m_ilRootItems.back())->Release();
m_ilRootItems.pop_back();
}
}
// -----------------------------------------------------------------------------
// The simple version of Pitem() simply calls the full version.
//
CBaseSnapinItem *CBaseSnapin::Pitem(LPDATAOBJECT lpDataObject, HSCOPEITEM hscopeitem, long cookie)
{
return Pitem(NULL, NULL, lpDataObject, hscopeitem, cookie);
}
// -----------------------------------------------------------------------------
// The full version of Pitem() attempts to find an existing CBaseSnapinItem
// that matches the given parameters. If it can't find any, it will create
// one.
//
// Note: In order to create a new item, one of the two first parameters must
// be provided.
//
CBaseSnapinItem *CBaseSnapin::Pitem(
CComponentData * pComponentData,
CComponent * pComponent,
LPDATAOBJECT lpDataObject,
HSCOPEITEM hscopeitem,
long cookie)
{
SC sc;
CBaseSnapinItem *pitem = NULL;
ItemList::iterator iter;
// For debugging purposes, I don't want to modify the 'hscopeitem' parameter,
// so I make a copy of it.
HSCOPEITEM hscopeitem2 = hscopeitem;
if (cookie)
{
//
// We can simply cast the cookie into a CBaseSnapinItem *.
//
pitem = reinterpret_cast<CBaseSnapinItem *>(cookie);
ASSERT(dynamic_cast<CBaseSnapinItem *>(pitem));
goto Cleanup;
}
if (hscopeitem2 == 0 && lpDataObject == NULL)
{
//
// We are being asked for the stand-alone root.
//
ASSERT(pComponentData);
pitem = pComponentData->PitemStandaloneRoot();
if (pitem)
goto Cleanup;
}
if (lpDataObject)
{
CLSID clsid;
//
// Are we the snapin who created this item ?
//
sc = CBaseDataObject::ScGetClassID(lpDataObject, &clsid);
if (sc)
goto Error;
if (::IsEqualCLSID(*PclsidSnapin(), clsid))
{
//
// We created this item, we can simply cast the pointer
// to a CBaseSnapinItem.
//
pitem = dynamic_cast<CBaseSnapinItem *>(lpDataObject);
ASSERT(pitem);
goto Cleanup;
}
}
if (lpDataObject && hscopeitem2 == 0)
{
//
// We got an IDataObject *, but we were not given a HSCOPEITEM :-(
// We'll get it from the CF_EXCHANGE_ADMIN_HSCOPEITEM clipboard format.
//
sc = CBaseDataObject::ScGetAdminHscopeitem(lpDataObject, &hscopeitem2);
if (sc == DV_E_FORMATETC)
{
//
// We don't own this item, we were not given a HSCOPEITEM and it
// doesn't support CF_EXCHANGE_ADMIN_HSCOPEITEM.
//
// $REVIEW (ptousig) Does this ever happen ?
//
ASSERT("Does this ever happen ?" && FALSE);
sc = S_OK;
}
else if (sc)
goto Error;
}
// If the user adds the snapin twice in the same console, we will
// be asked for two root items. If we are being asked for the same root
// twice, then the "if (hscopeitem2 == 0 && lpDataObject == NULL)" above
// will have caught it. If we get this far, it means we are being asked
// for another root item. So we want to search through our existing
// list of roots only if we have a HSCOPEITEM.
if (hscopeitem2)
{
//
// We are going to search through our list of existing root items
// to find one with this HSCOPEITEM.
// We can't really use a STL map here because the HSCOPEITEM of the items
// will change after the root is added to the list. Besides, we don't expect
// more than a handful of roots anyway.
//
for (iter = m_ilRootItems.begin(); iter != m_ilRootItems.end(); iter++)
{
if ((*iter)->Hscopeitem() == hscopeitem2)
{
pitem = *iter;
goto Cleanup; // We found it, stop looking
}
}
}
//
// If we reach this point it's because we couldn't find this node.
// So we create a new one and append it to the end of the list.
//
sc = ScCreateRootItem(lpDataObject, hscopeitem2, &pitem);
if (sc)
goto Error;
ASSERT(pitem);
//
// Initialize the new root
//
if (pComponentData)
pitem->SetComponentData(pComponentData);
sc = pitem->ScInit(this, NULL, 0, TRUE);
if (sc)
goto Error;
// Add this new item to our list of roots.
static_cast<LPDATAOBJECT>(pitem)->AddRef();
m_ilRootItems.push_back(pitem);
// If this is a standalone root, better tell the component data about it.
if (hscopeitem2 == 0 && lpDataObject == NULL)
{
ASSERT(pComponentData);
pComponentData->SetPitemStandaloneRoot(pitem);
}
if (lpDataObject)
{
BOOL fIsOwned = FALSE;
CNodeType *pnodetype = NULL;
// $REVIEW (ptousig) There's a better way of doing this.
// We know we don't own that node, but ScInitializeNamespaceExtension expects
// a CNodeType so we have to call this to get one.
sc = ScIsOwnedDataObject(lpDataObject, &fIsOwned, &pnodetype);
if (sc)
goto Error;
// Initialize the root item's code from the dataobject of the parent item.
pitem->SetIsGhostRoot(TRUE);
sc = pitem->ScInitializeNamespaceExtension(lpDataObject, hscopeitem2, pnodetype);
if (sc)
goto Error;
}
Cleanup:
// Make sure this item knows its HSCOPEITEM
if (hscopeitem2)
pitem->SetHscopeitem(hscopeitem2);
ASSERT(pitem);
return pitem;
Error:
TraceError(_T("CBaseSnapin::Pitem"), sc);
MMCErrorBox(sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Returns whether a dataobject is "owned" by this snapin. It does that
// by looking at the list of nodetypes this snapin says it can create, if
// this node is one of these, we assume we own it.
// As a side-effect, this function also returns the nodetype of the node.
//
// $REVIEW (ptousig) This is not an accurate test, we need to use the CCF_SNAPIN_CLASSID.
//
SC CBaseSnapin::ScIsOwnedDataObject(LPDATAOBJECT pdataobject, BOOL *pfIsOwned, CNodeType **ppnodetype)
{
SC sc;
BOOL fIsOwned = FALSE;
CNodeType * pnodetype = NULL;
CLSID clsid;
INT isnr = 0;
ASSERT(pdataobject);
ASSERT(pfIsOwned);
ASSERT(ppnodetype);
// Get the nodetype, in guid format, of the data object.
sc = CBaseDataObject::ScGetNodeType(pdataobject, &clsid);
if (sc)
goto Error;
for (isnr = 0; isnr < Csnr(); isnr ++)
{
if (IsEqualCLSID(*(Psnr(isnr)->pnodetype->PclsidNodeType()), clsid))
{
// We found the CLSID, keep track of its nodetype.
pnodetype = Psnr(isnr)->pnodetype;
SNRTypes snrtypes = Psnr(isnr)->snrtypes;
// Do we enumerate nodes of this type? If so, we must be the owner.
if ((snrtypes & snrEnumSP) || (snrtypes & snrEnumRP) || (snrtypes & snrEnumSM))
fIsOwned = TRUE;
break; // exit the loop.
}
}
Cleanup:
*pfIsOwned = fIsOwned;
*ppnodetype = pnodetype;
return sc;
Error:
TraceError(_T("CBaseSnapin::ScIsOwnedDataObject"), sc);
goto Cleanup;
}
#ifdef _DEBUG
// -----------------------------------------------------------------------------
// Debug menu options
//
SnapinMenuItem CBaseSnapin::s_rgmenuitemBase[] =
{
{IDS_Test, IDS_Test, 0, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, 0, dwMenuNeverGray, dwMenuNeverChecked},
#if 0
{idsBarfTraces, idsBarfTracesStatusText, idmBarfTraces, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfClearDbgScreen, idsBarfClearDbgScreenStatusText, idmBarfClearDbgScreen, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfSCDescription, idsBarfSCDescriptionStatusText, idmBarfSCDescription, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{NULL, idsBarfSeparatorStatusText, idmBarfSeparator1, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, MF_SEPARATOR, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfSettings, idsBarfSettingsStatusText, idmBarfSettings, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfAll, idsBarfAllStatusText, idmBarfAll, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfMemoryChkpoint, idsBarfMemoryChkpointStatusText, idmBarfMemoryChkpoint, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfMemoryDiff, idsBarfMemoryDiffStatusText, idmBarfMemoryDiff, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfValidateMemory, idsBarfValidateMemoryStatusText, idmBarfValidateMemory, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfTotalMemAllocd, idsBarfTotalMemAllocdStatusText, idmBarfTotalMemAllocd, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
{NULL, idsBarfSeparatorStatusText, idmBarfSeparator3, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, MF_SEPARATOR, dwMenuNeverGray, dwMenuNeverChecked},
{idsBarfDebugBreak, idsBarfDebugBreakStatusText, idmBarfDebugBreak, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
#endif
};
INT CBaseSnapin::s_cMenuItemBase = CMENUITEM(s_rgmenuitemBase);
// -----------------------------------------------------------------------------
SnapinMenuItem *CBaseSnapin::PmenuitemBase(void)
{
return s_rgmenuitemBase;
}
// -----------------------------------------------------------------------------
INT CBaseSnapin::CMenuItemBase(void)
{
return s_cMenuItemBase;
}
#endif // _DEBUG
// -----------------------------------------------------------------------------
// This table allows us to map a MMC verb to a specific bit in a dword.
//
VerbMap CBaseSnapin::s_rgverbmap[] =
{
{ vmOpen, MMC_VERB_OPEN},
{ vmCopy, MMC_VERB_COPY},
{ vmPaste, MMC_VERB_PASTE},
{ vmDelete, MMC_VERB_DELETE},
{ vmProperties, MMC_VERB_PROPERTIES},
{ vmRename, MMC_VERB_RENAME},
{ vmRefresh, MMC_VERB_REFRESH},
{ vmPrint, MMC_VERB_PRINT},
{ vmCut, MMC_VERB_CUT},
};
// -----------------------------------------------------------------------------
// Accesses a given entry in the VerbMap table.
//
VerbMap *CBaseSnapin::Pverbmap(INT i)
{
ASSERT(i>=0 && i<Cverbmap());
return &(s_rgverbmap[i]);
}
// -----------------------------------------------------------------------------
// Returns the number of entries in the VerbMap table.
//
INT CBaseSnapin::Cverbmap(void)
{
return(sizeof(s_rgverbmap) / sizeof(VerbMap));
}
// -----------------------------------------------------------------------------
// Has the icon information been initialized ?
BOOL CBaseSnapin::s_fBaseSnapinInitialized = FALSE;
// -----------------------------------------------------------------------------
// The bitmaps containing all the icons
WTL::CBitmap CBaseSnapin::s_bmpImage16;
WTL::CBitmap CBaseSnapin::s_bmpImage32;
// -----------------------------------------------------------------------------
// The Registrar
//
CRegistrar CBaseSnapin::s_registrar;
// -----------------------------------------------------------------------------
// Initializes the global bitmaps (once) as well as the per-snapin bitmaps.
//
SC CBaseSnapin::ScInitBitmaps(void)
{
DECLARE_SC(sc, _T("CBaseSnapin::ScInitBitmaps"));
// Once for the whole app...
if (s_fBaseSnapinInitialized == FALSE)
{
sc = BmpImage16().LoadBitmap(IDB_NODES16) ? S_OK : E_FAIL;
if (sc)
return sc;
sc = BmpImage32().LoadBitmap(IDB_NODES32) ? S_OK : E_FAIL;
if (sc)
return sc;
s_fBaseSnapinInitialized = TRUE;
}
if (BitmapSmall().IsNull())
{
sc = BitmapSmall().LoadBitmap(IDB_NODES16) ? S_OK : E_FAIL;
if (sc)
return sc;
}
if (BitmapLarge().IsNull())
{
sc = BitmapLarge().LoadBitmap(IDB_NODES32) ? S_OK : E_FAIL;
if (sc)
return sc;
}
if (BitmapStaticSmall().IsNull())
{
sc = BitmapStaticSmall().LoadBitmap(IDB_FOLDER16) ? S_OK : E_FAIL;
if (sc)
return sc;
}
if (BitmapStaticSmallOpen().IsNull())
{
sc = BitmapStaticSmallOpen().LoadBitmap(IDB_FOLDER16OP) ? S_OK : E_FAIL;
if (sc)
return sc;
}
if (BitmapStaticLarge().IsNull())
{
sc = BitmapStaticLarge().LoadBitmap(IDB_FOLDER32) ? S_OK : E_FAIL;
if (sc)
return sc;
}
return sc;
}
inline HBITMAP CopyBitmap (HBITMAP hbm)
{
return ((HBITMAP) CopyImage ((HANDLE) hbm, IMAGE_BITMAP, 0, 0, 0));
}
// -----------------------------------------------------------------------------
// MMC wants icons to persist in the .msc file.
//
SC CBaseSnapin::ScGetStaticFolderImage(HBITMAP *phSmallImage, HBITMAP *phSmallImageOpen, HBITMAP *phLargeImage, COLORREF *pcMask)
{
ASSERT(phSmallImage && phSmallImageOpen && phLargeImage && pcMask);
*phSmallImage = CopyBitmap (BitmapStaticSmall());
*phSmallImageOpen = CopyBitmap (BitmapStaticSmallOpen());
*phLargeImage = CopyBitmap (BitmapStaticLarge());
*pcMask = RGB (255, 0, 255);
return S_OK;
}
// -----------------------------------------------------------------------------
// Compares two fields for sorting by MMC. This applies to regular result items, i.e. not to virtual
// list snapin items. Our snapins can override the compare and impact the sort. We use a smart compare
// to guess if the field is numeric. If so, we perform a numeric compare.
// Otherwise we use case insensitive string compare.
//
// On input, *pnResult contains the column number to compare.
// On output, *pnResult contains the result of our comparison:
// -1 means A is smaller than B
// 0 means A is equal to B
// 1 means A is greater than B
//
SC CBaseSnapin::ScCompare(MMC_COOKIE cookieA, MMC_COOKIE cookieB, INT nColumn, INT * pnResult)
{
// Declarations
SC sc; // execution code
CBaseSnapinItem * pitemA = NULL; // snapin item A
CBaseSnapinItem * pitemB = NULL; // snapin item B
tstring strBufferA; // field A
tstring strBufferB; // field B
LONG lValueA = 0; // numeric value for field A
LONG lValueB = 0; // numeric value for field B
// Validate data
ASSERT(pnResult);
// Check that these cookies are not special cookies
ASSERT(IS_SPECIAL_COOKIE(cookieA) == FALSE);
ASSERT(IS_SPECIAL_COOKIE(cookieB) == FALSE);
// Cast the cookies into snapin items
pitemA = reinterpret_cast<CBaseSnapinItem *>(cookieA);
pitemB = reinterpret_cast<CBaseSnapinItem *>(cookieB);
// Get the fields from the snapin items
sc = pitemA->ScGetField(pitemA->PcolinfoexDisplay(nColumn)->Dat(), strBufferA);
if (sc)
goto Error;
sc = pitemB->ScGetField(pitemB->PcolinfoexDisplay(nColumn)->Dat(), strBufferB);
if (sc)
goto Error;
ASSERT(FALSE && "Use Dat and compare data type properly");
// Use the default string compare (case-insensitive)
*pnResult = _tcsicmp(strBufferA.data(), strBufferB.data());
if (*pnResult < 0)
*pnResult = -1; // string A < string B
else if (*pnResult > 0)
*pnResult = 1;
else
*pnResult = 0;
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScCompare()"), sc);
goto Cleanup;
}
/* CBaseMultiSelectSnapinItem::ScCreateMultiSelectionDataObject
*
* PURPOSE: Creates a multiselect data object - we store a list of selected object in this special object.
*
* PARAMETERS:
* LPDATAOBJECT * ppDataObject Pointer to a pointer to the multiselect snapin item to create.
* CComponent * pComponent Pointer to the component object.
*
* RETURNS:
* SC Execution code
*/
SC
CBaseSnapin::ScCreateMultiSelectionDataObject(LPDATAOBJECT * ppDataObject, CComponent * pComponent)
{
// Declarations
SC sc ; // execution code
HRESULT hr = S_FALSE; // local execution code
RESULTDATAITEM rdi; // a selected item
BOOL fFoundASelection = FALSE; // did we find at least one selected item
CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL; // multiselect dataobject
// are we processing the first object of the selected object set
// Data validation
ASSERT(ppDataObject);
ASSERT(*ppDataObject == NULL);
ASSERT(pComponent);
// Allocate a typed multiselection data object
sc = ScAllocateMultiSelectionDataObject(&pBaseMultiSelectSnapinItem);
if (sc)
goto Error;
ASSERT(pBaseMultiSelectSnapinItem);
// Assign the snapin - important for some clipboard formats
pBaseMultiSelectSnapinItem->SetSnapin(this);
// Identify the selected items
::ZeroMemory(&rdi, sizeof(rdi));
rdi.nIndex = -1; // first item requested
rdi.nState = LVIS_SELECTED; // only the selected items requested
rdi.mask = RDI_STATE | RDI_INDEX | RDI_PARAM; // state, cookie and index
// Get the result data interface
ASSERT(pComponent->IpResultData()); // verify we have an IResultData interface
while (S_OK == (hr = pComponent->IpResultData()->GetNextItem(&rdi)))
{
// Local declarations
CBaseSnapinItem * pitem = NULL;
// Make sure we got a cookie for the item
ASSERT(rdi.lParam);
pitem = reinterpret_cast<CBaseSnapinItem *>(rdi.lParam);
ASSERT(pitem);
// Add the item to the list managed by our multiselect data object
ASSERT(pBaseMultiSelectSnapinItem->PivSelectedItems());
pBaseMultiSelectSnapinItem->PivSelectedItems()->push_back(pitem);
// Remember we found a selected object
fFoundASelection = TRUE;
}
if (FAILED(hr))
{
sc = hr;
goto Error;
}
// Let the component it is in multiselect mode
*(pComponent->PpMultiSelectSnapinItem()) = pBaseMultiSelectSnapinItem;
// Make sure we found at least one selected object, otherwise we should never have been called in the first place
ASSERT(fFoundASelection);
// Set the result
*ppDataObject = pBaseMultiSelectSnapinItem;
Cleanup:
return sc;
Error:
if (pBaseMultiSelectSnapinItem)
delete pBaseMultiSelectSnapinItem;
pBaseMultiSelectSnapinItem = NULL;
TraceError(_T("CBaseSnapin::ScCreateMultiSelectionDataObject()"), sc);
goto Cleanup;
}
/* CBaseMultiSelectSnapinItem::ScAllocateMultiSelectionDataObject
*
* PURPOSE: Allocates a multiselect data object - we store a list of selected object in this special object.
*
* PARAMETERS:
* CBaseMultiSelectSnapinItem ** ppBaseMultiSelectSnapinItem Pointer to a pointer to the multiselect snapin item to allocate.
*
* RETURNS:
* SC Execution code
*/
SC
CBaseSnapin::ScAllocateMultiSelectionDataObject(CBaseMultiSelectSnapinItem ** ppBaseMultiSelectSnapinItem)
{
// Declarations
SC sc ;
t_itemBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL; // create multiselect snapin item
// Data validation
ASSERT(ppBaseMultiSelectSnapinItem);
ASSERT(!*ppBaseMultiSelectSnapinItem);
// Allocate the object
sc = ScCreateItemQuick(&pBaseMultiSelectSnapinItem);
if (sc)
goto Error;
// Assign the result
*ppBaseMultiSelectSnapinItem = pBaseMultiSelectSnapinItem;
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScAllocateMultiSelectionDataObject()"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Returns the version information string for the snapin.
// The output string must be allocated with CoTaskMemAlloc.
//
SC CBaseSnapin::ScGetSnapinVersion(LPOLESTR *lpVersion)
{
DECLARE_SC(sc, _T("CBaseSnapin::ScGetSnapinVersion"));
sc = ScCheckPointers(lpVersion);
if (sc)
return sc;
*lpVersion = CoTaskDupString(L"");
if ((*lpVersion) == NULL)
return (E_OUTOFMEMORY);
return sc;
}
SC CBaseSnapin::ScGetProvider(LPOLESTR *lpName)
{
DECLARE_SC(sc, _T("CBaseSnapin::ScGetProvider"));
sc = ScCheckPointers(lpName);
if (sc)
return sc;
*lpName = CoTaskDupString(L"Microsoft");
if ((*lpName) == NULL)
return (E_OUTOFMEMORY);
return sc;
}
// -----------------------------------------------------------------------------
// Creates an ATL Registrar script for the snapin and registers/unregisters it.
// If fRegister is TRUE then we are registering, FALSE we are unregistering.
//
SC CBaseSnapin::ScRegister(BOOL fRegister)
{
SC sc ;
HRESULT hr = S_OK;
INT i = 0;
const INT cchMaxLen = 256;
TCHAR szFileName[cchMaxLen];
CStr cstrTemp;
tstring strVersion;
const INT cchMaxRegScript = 10000;
tstring strRegScript;
tstring strFmtSnapinRegScript;
tstring strSnapinAboutRegScript;
tstring strSnapinNodeTypes;
tstring strExtensionScript;
tstring strPropertySheetScript;
tstring strToolBarScript;
tstring strNameSpaceScript;
tstring strContextMenuScript;
tstring strTemp;
tstring strSnapinName;
tstring strStandalone;
// Hacks for version, snapin name.
// Version number eg 6.3523.0.0
strVersion = _T("6.3523.0.0");
strSnapinAboutRegScript = szSnapinAboutRegScript + strVersion;
cstrTemp.Format(szSnapinAboutRegScript, strVersion.data());
strSnapinAboutRegScript = cstrTemp;
strSnapinName.LoadString(_Module.GetModuleInstance(), IdsName());
// strSnapinName = _T("Sample Framework Snapin");
GetModuleFileName(_Module.GetModuleInstance(), szFileName, cchMaxLen);
// Create the Standalone key only if we're a standalone snapin.
if (FStandalone())
strStandalone = szStandalone;
// Format all the extension node stuff.
for (i = 0; i<Csnr(); i++)
{
tstring strNodeTypeName;
CNodeType *pnodetype = Psnr()[i].pnodetype;
SNRTypes snrtypes = Psnr()[i].snrtypes;
// Get the name of the node type
if (! pnodetype->StrName().empty())
{
strTemp = pnodetype->StrName();
strNodeTypeName = pnodetype->StrClsidNodeType();
strNodeTypeName += _T(" = s '");
strNodeTypeName += pnodetype->StrName();
strNodeTypeName += _T("'");
}
else
strNodeTypeName = pnodetype->StrClsidNodeType();
// Add the ID of the node to the NodeTypes key if we enumerate it.
tstring strSnapinNodeTypesTemp;
if ( (snrtypes & snrEnumSP) || (snrtypes & snrEnumRP) || (snrtypes & snrEnumSM))
{
// Add the opening brace the first time around.
if (strSnapinNodeTypes.empty())
strSnapinNodeTypes = szSnapinNodeTypeOpen;
cstrTemp.Format(szFmtSnapinNodeType, pnodetype->StrClsidNodeType().data());
strSnapinNodeTypesTemp = cstrTemp;
strSnapinNodeTypes += strSnapinNodeTypesTemp;
}
// Needed because this is a for loop.
strContextMenuScript = _T("");
// Menu extensions
if ( snrtypes & snrExtCM)
{
cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
strContextMenuScript = cstrTemp;
}
// Property Page extensions
strPropertySheetScript = _T("");
if ( snrtypes & snrExtPS)
{
cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
strPropertySheetScript = cstrTemp;
}
// Toolbar extensions
strToolBarScript = _T("");
if ( snrtypes & snrExtTB)
{
cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
strToolBarScript = cstrTemp;
}
// Namespace extensions
strNameSpaceScript = _T("");
if ( snrtypes & snrExtNS)
{
cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
strNameSpaceScript = cstrTemp;
}
cstrTemp.Format(szfmtAllExtensions, strNodeTypeName.data(), strNameSpaceScript.data() , strContextMenuScript.data() , strPropertySheetScript.data() , strToolBarScript.data());
strExtensionScript += cstrTemp;
}
// Add a closing brace to the NodeTypes key if needed
if (! strSnapinNodeTypes.empty())
strSnapinNodeTypes += szSnapinNodeTypeClose;
// Need to concatenate these to form the real fmt string!
strFmtSnapinRegScript = szfmtSnapinRegScript1;
strFmtSnapinRegScript += szfmtSnapinRegScript2;
cstrTemp.Format(strFmtSnapinRegScript.data(), strVersion.data(), strVersion.data(), strStandalone.data(), strSnapinNodeTypes.data(), strExtensionScript.data());
strRegScript = strSnapinAboutRegScript;
strRegScript += cstrTemp;
USES_CONVERSION;
// Set all the replacement parameter values.
// $REVIEW (ptousig) DLLName is always set to Exadmin !!!
sc = Registrar().ClearReplacements( );
sc = Registrar().AddReplacement(szDLLName, L"Snapins");
sc = Registrar().AddReplacement(szModule, T2COLE(szFileName));
sc = Registrar().AddReplacement(szCLSID_Snapin, T2COLE(StrClsidSnapin().data()));
sc = Registrar().AddReplacement(szCLSID_About, T2COLE(StrClsidAbout().data()));
sc = Registrar().AddReplacement(szClassName, T2COLE(StrClassName().data()));
sc = Registrar().AddReplacement(szSnapinName, T2COLE(strSnapinName.data()));
sc = Registrar().AddReplacement(szCLSID_NodeType, L"");
if (fRegister)
{
LPCOLESTR lpOleStr = T2COLE(strRegScript.data());
sc = Registrar().StringRegister(lpOleStr);
if (sc)
goto Error;
}
else
{
hr = Registrar().StringUnregister(strRegScript.data());
if (hr == DISP_E_EXCEPTION)
{
//
// When trying to unregister a snapin that wasn't registered in
// the first place, the Registrar returns a DISP_E_EXCEPTION.
// I don't know why, seems to be a bug in the Registrar. Our
// solution for now is to ignore the error, not very clean but
// effective. We are un-registering a snapin that wasn't registered
// anyway.
//
hr = S_OK;
}
else if (FAILED(hr))
{
//
// Some other error occured
//
sc = hr;
goto Error;
}
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScRegister"), sc);
goto Cleanup;
}
#if 0
#ifdef _DEBUG
// -----------------------------------------------------------------------------
// Displays the Traces menu (in debug only)
//
SC CBaseSnapin::ScOnMenuTraces(void)
{
DoTraceDialog();
return S_OK;
}
// -----------------------------------------------------------------------------
// Provides a description of a given SC Code (in debug only)
//
SC CBaseSnapin::ScOnMenuSCDescription(void)
{
CStr strPrompt(_T("Enter the Status Code (sc)"));
CSTR (strAnswer, 10);
CAskStringDialog dlg;
ID id;
SC sc;
dlg.SetPrompt(&strPrompt);
dlg.SetAnswer(&strAnswer);
strAnswer.BlankString();
id = dlg.IdModal();
if (id != IDOK)
return(sc = S_OK);
//
// Convert the text the user entered into a SC.
//
sc = (SC) strAnswer.strtoul(NULL, 16);
MbbErrorBox(sc);
return sc;
}
// -----------------------------------------------------------------------------
// Debug stuff (in debug only)
//
SC CBaseSnapin::ScOnMenuMemoryDiff(void)
{
#ifdef USE_BARFMEM
CBaseWaitCursor wc;
CBarfMemory::DumpMarked();
#endif // USE_BARFMEM
return S_OK;
}
// -----------------------------------------------------------------------------
// Validates Memory (in debug only)
//
SC CBaseSnapin::ScOnMenuValidateMemory(void)
{
#ifdef USE_BARFMEM
CBaseWaitCursor wc;
//Ensure output even if tagMemoryCorruption not turned on
Trace(&tagAlways, _T("CBaseSnapin::ScOnMenuValidateMemory() - Validating memory ..."));
ValidateMemory(&tagAlways);
Trace(&tagAlways, _T("CBaseSnapin::ScOnMenuValidateMemory() - ... Done validating memory."));
#endif // USE_BARFMEM
return S_OK;
}
// -----------------------------------------------------------------------------
// Displays Dialog Box of Total Memory Allocated (in debug only)
//
SC CBaseSnapin::ScOnMenuTotalMemory(void)
{
#ifdef USE_BARFMEM
INT nAlloc;
INT nBytes;
CSTR (str, cchMaxLine);
CBaseWaitCursor wc;
TotalMemory(&nAlloc, &nBytes);
str.Format(_T("Memory currently allocated:\n\n%d allocations\n%d bytes"), nAlloc, nBytes);
MbbErrorBox(str.Sz(), MB_OK | MB_ICONINFORMATION);
#endif // USE_BARFMEM
return S_OK;
}
#endif
#endif //#if 0
// -----------------------------------------------------------------------------
// Given two pointers to dataObjects, are they the same?
// Returns S_OK if objects A and B are the same, S_FALSE if they are different.
//
// $REVIEW (ptousig) Will there ever be a case where two different
// dataobjects should be considered equal ?
//
SC CBaseSnapin::ScCompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
{
SC sc = S_FALSE;
BOOL fOwnedA = FALSE;
BOOL fOwnedB = FALSE;
CNodeType *pnodetypeA = NULL;
CNodeType *pnodetypeB = NULL;
// Check if one of the pointers is NULL.
if (!lpDataObjectA || !lpDataObjectB)
{
// This happens when one of the objects is new.
// See bug 117170.
sc = S_FALSE;
goto Cleanup;
}
if (lpDataObjectA == lpDataObjectB)
{
// If both pointers are the same, then obviously they are
// the same object.
sc = S_OK;
goto Cleanup;
}
// Do we own both dataobjects.
sc = ScIsOwnedDataObject(lpDataObjectA, &fOwnedA, &pnodetypeA);
if (sc)
goto Error;
sc = ScIsOwnedDataObject(lpDataObjectB, &fOwnedB, &pnodetypeB);
if (sc)
goto Error;
if (fOwnedA == FALSE || fOwnedB == FALSE)
{
// We don't own at least of the dataobjects. They are either
// different or we are not qualified to compare them.
sc = S_FALSE;
goto Cleanup;
}
// Since we own both dataobjects, and the pointers are different
// then we can conclude that they represent different objects.
sc = S_FALSE;
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScCompareObjects"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Handler of AddMenuItems we ask the item for its menu items. And in debug
// mode we add debug menu items if the item wants us to.
//
SC CBaseSnapin::ScAddMenuItems(LPDATAOBJECT lpDataObject, LPCONTEXTMENUCALLBACK ipContextMenuCallback, long *pInsertionAllowed)
{
// Declarations
SC sc;
CBaseSnapinItem * pitem = NULL;
CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
// Data validation
ASSERT(lpDataObject);
ASSERT(ipContextMenuCallback);
ASSERT(pInsertionAllowed);
// See if we can extract the multi select data object from the composite data object
sc = CBaseMultiSelectSnapinItem::ScExtractMultiSelectDataObject(this, lpDataObject, &pBaseMultiSelectSnapinItem);
if (sc)
goto Error;
// If we actually had a composite data object and we were able to find our multiselect snapin item
if (pBaseMultiSelectSnapinItem)
{
// Call ScAddMenuItems for the multiselect object for menu merging
sc = pBaseMultiSelectSnapinItem->ScAddMenuItems(this, lpDataObject, ipContextMenuCallback, pInsertionAllowed);
if (sc)
goto Error;
}
else
{
// Handle the normal case - PItem() does more work than a simple cast to verify that the snapin item belongs to the snapin etc.
pitem = Pitem(lpDataObject);
ASSERT(pitem);
sc = ScAddMenuItems(pitem, *pInsertionAllowed, ipContextMenuCallback, pitem->Pmenuitem(), pitem->CMenuItem());
if (sc)
goto Error;
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScAddMenuItems"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Constructor for CSnapinContextMenuItem
//
CSnapinContextMenuItem::CSnapinContextMenuItem(void)
{
// Initialize members
::ZeroMemory(&cm, sizeof(cm));
}
// -----------------------------------------------------------------------------
// Destructor for CSnapinContextMenuItemVectorWrapper
//
CSnapinContextMenuItemVectorWrapper::~CSnapinContextMenuItemVectorWrapper(void)
{
// Declarations
INT nIterator = 0;
// Go through all the referenced CSnapinContextMenuItem objects and delete them
for (nIterator=0; nIterator < cmiv.size(); nIterator++)
{
if (cmiv[nIterator])
{
delete cmiv[nIterator];
cmiv[nIterator] = NULL;
}
}
}
// -----------------------------------------------------------------------------
// Adds menu items to the context menu.
//
SC
CBaseSnapin::ScAddMenuItems(CBaseSnapinItem * pitem, long lInsertionAllowed, LPCONTEXTMENUCALLBACK ipContextMenuCallback, SnapinMenuItem * rgmenuitem, INT cmenuitem)
{
// Declarations
SC sc ;
BOOL fAllowed = TRUE;
INT nIterator = 0;
// Data validation
ASSERT(pitem);
ASSERT(ipContextMenuCallback);
// ASSERT(rgmenuitem); sometimes there is no menu
// Go through the different menu items
for (nIterator=0; nIterator < cmenuitem; nIterator++)
{
// Local declarations
CSnapinContextMenuItem cmi;
// Get the menu item
sc = ScGetMenuItem(&cmi, pitem, &(rgmenuitem[nIterator]), &fAllowed, lInsertionAllowed);
if (sc)
goto Error;
// If the menu item is allowed, then add it
if (fAllowed)
{
sc = ipContextMenuCallback->AddItem(&(cmi.cm));
if (sc)
goto Error;
}
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScAddMenuItems"), sc);
goto Cleanup;
};
/* CBaseSnapin::ScGetMenuItem
*
* PURPOSE: Sets a menu item struct for a particular snapin item and for a particular source menu item of that snapin item.
*
* PARAMETERS:
* CSnapinContextMenuItem * pcmiReturned Menu item struct to set
* CBaseSnapinItem * pitem Snapin item from which the source menu item comes
* MenuItem * pMenuItemSource Source menu item
* BOOL * pfAllowed TRUE if the menu item allowed?
*
* RETURNS:
* SC Execution code
*/
SC
CBaseSnapin::ScGetMenuItem(CSnapinContextMenuItem * pcmiReturned, CBaseSnapinItem * pitem, SnapinMenuItem * pMenuItemSource, BOOL * pfAllowed, long lInsertionAllowed)
{
// Declarations
SC sc ;
LONG fFlags = 0;
DWORD dwFlagsMenuDisable = 0;
DWORD dwFlagsMenuGray = 0;
DWORD dwFlagsMenuChecked = 0;
// Data validation
ASSERT(pcmiReturned);
ASSERT(pitem);
ASSERT(pMenuItemSource);
ASSERT(pfAllowed);
// Set default
*pfAllowed = TRUE;
// Get the flags from the snapin item
dwFlagsMenuDisable = pitem->DwFlagsMenuDisable();
dwFlagsMenuGray = pitem->DwFlagsMenuGray();
dwFlagsMenuChecked = pitem->DwFlagsMenuChecked();
// Disabled means don't show at all. Not the same as MMC's MF_DISABLED.
if (dwFlagsMenuDisable & pMenuItemSource->dwFlagsDisable)
{
*pfAllowed = FALSE;
goto Cleanup;
}
// Check if the menu item should be allowed
switch (pMenuItemSource->lInsertionPointID)
{
case CCM_INSERTIONPOINTID_PRIMARY_TOP:
*pfAllowed = (lInsertionAllowed & CCM_INSERTIONALLOWED_TOP) != 0;
break;
case CCM_INSERTIONPOINTID_PRIMARY_NEW:
case CCM_INSERTIONPOINTID_3RDPARTY_NEW:
*pfAllowed = ((lInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0) && pitem->FHasComponentData();
break;
case CCM_INSERTIONPOINTID_PRIMARY_TASK:
case CCM_INSERTIONPOINTID_3RDPARTY_TASK:
*pfAllowed = (lInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0;
break;
case CCM_INSERTIONPOINTID_PRIMARY_VIEW:
*pfAllowed = (lInsertionAllowed & CCM_INSERTIONALLOWED_VIEW) != 0;
break;
}
// If the menu item is not to be enabled, then discard
if (!*pfAllowed)
goto Cleanup;
// Set flags
if (dwFlagsMenuGray & pMenuItemSource->dwFlagsGray)
fFlags |= MF_GRAYED;
else
fFlags |= MF_ENABLED;
if (dwFlagsMenuChecked & pMenuItemSource->dwFlagsChecked)
fFlags |= MF_CHECKED;
else
fFlags |= MF_UNCHECKED;
// Set other parameters
if (pMenuItemSource->idsName)
pcmiReturned->strName.LoadString(_Module.GetResourceInstance(), pMenuItemSource->idsName);
if (pMenuItemSource->idsStatusBarText)
pcmiReturned->strStatusBarText.LoadString(_Module.GetResourceInstance(), pMenuItemSource->idsStatusBarText);
pcmiReturned->cm.strName = (LPWSTR)pcmiReturned->strName.data();
pcmiReturned->cm.strStatusBarText = (LPWSTR)pcmiReturned->strStatusBarText.data();
pcmiReturned->cm.lCommandID = pMenuItemSource->lCommandID;
pcmiReturned->cm.lInsertionPointID = pMenuItemSource->lInsertionPointID;
pcmiReturned->cm.fFlags = fFlags;
pcmiReturned->cm.fSpecialFlags = pMenuItemSource->fSpecialFlags;
Cleanup:
return sc;
}
// -----------------------------------------------------------------------------
// Load the icon for the snapin and return it to MMC.
//
SC CBaseSnapin::ScGetSnapinImage(HICON *phAppIcon)
{
SC sc ;
ASSERT(phAppIcon);
if (phAppIcon == NULL)
{
sc = E_INVALIDARG;
goto Error;
}
if (Idi() == 0)
{
// There is no icon for this snapin
*phAppIcon = NULL;
goto Cleanup;
}
*phAppIcon = ::LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(Idi()));
if (*phAppIcon == NULL)
{
sc = ScFromWin32(GetLastError());
goto Error;
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScGetSnapinImage"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Release the given item, but only if it is one of the root items.
// Used during MMCN_REMOVE_CHILDREN. We are being told that the item
// that we are "ghosting" is either being destroyed or all of its children
// are being destroyed. In either case, we don't need the ghost item
// anymore.
//
SC CBaseSnapin::ScReleaseIfRootItem(CBaseSnapinItem *pitem)
{
SC sc ;
ItemList::iterator iter;
ASSERT(pitem);
for (iter = m_ilRootItems.begin(); iter != m_ilRootItems.end(); iter++)
{
if (pitem == (*iter))
{
m_ilRootItems.erase(iter);
static_cast<LPDATAOBJECT>(pitem)->Release();
break;
}
}
return sc;
}
// -----------------------------------------------------------------------------
// Determines whether the specified dataobject is pastable.
//
SC
CBaseSnapin::ScIsPastableDataObject(CBaseSnapinItem * pitemTarget, LPDATAOBJECT lpDataObject, BOOL * pfPastable)
{
// Declarations
SC sc ;
BOOL fPastable = FALSE;
CNodeType * pnodetype = NULL;
CLSID clsid;
INT isnr = 0;
// Validate parameters
ASSERT(pitemTarget);
ASSERT(lpDataObject);
ASSERT(pfPastable);
// Is this an MMC node?
// Get the nodetype, in guid format, of the data object.
sc = CBaseDataObject::ScGetNodeType(lpDataObject, &clsid);
if (sc == DV_E_FORMATETC || sc == E_NOTIMPL)
{
// Not an MMC Node
fPastable = FALSE;
sc = S_FALSE; // override the execution code
goto Cleanup;
}
if (sc)
goto Error;
// Verify that the snapin item class type is acceptable to the destination
for (isnr=0; isnr < Csnr(); isnr++)
{
// Find a class id match
if (IsEqualCLSID(*(Psnr(isnr)->pnodetype->PclsidNodeType()), clsid)) // found the CLSID
{
// SNR verification
SNRTypes snrtypes = Psnr(isnr)->snrtypes;
// $REVIEW (ptousig) So all nodes are pastable ? Sounds to me like
// snrEnumSP and snrEnumRP shouldn't be in here.
if ( (snrtypes & snrEnumSP) || (snrtypes & snrEnumRP) || (snrtypes & snrPaste))
fPastable = TRUE;
break; // exit the loop.
}
}
// If it seems we can paste, ask the target item if we can paste here
if (fPastable)
{
sc = pitemTarget->ScOnQueryPaste(lpDataObject, &fPastable);
if (sc)
goto Error;
}
Cleanup:
// Assign result
*pfPastable = fPastable;
return sc;
Error:
fPastable = FALSE;
TraceError(_T("CBaseSnapin::ScIsPastableDataObject()"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Find out which verb should be the default.
//
MMC_CONSOLE_VERB CBaseSnapin::MmcverbDefault(LPDATAOBJECT lpDataObject)
{
// Ask the item.
return Pitem(lpDataObject)->MmcverbDefault();
}
// -----------------------------------------------------------------------------
// Find out the verbs that are allowed on this item.
//
SC CBaseSnapin::ScGetVerbs(LPDATAOBJECT lpDataObject, DWORD * pdwVerbs)
{
// Ask the item.
return Pitem(lpDataObject)->ScGetVerbs(pdwVerbs);
}
// -----------------------------------------------------------------------------
// Returns the path to the help file for this snapin.
//
SC CBaseSnapin::ScGetHelpTopic(tstring& strCompiledHelpFile)
{
DECLARE_SC(sc, _T("CBaseSnapin::ScGetHelpTopic"));
DWORD dwLen = 0;
const int cchMaxLen = 256;
TCHAR szFileName[cchMaxLen];
//
// Get the full path to the current module
//
dwLen = ::GetModuleFileName(_Module.GetModuleInstance() , szFileName, cchMaxLen);
if (dwLen == 0)
return (ScFromWin32(GetLastError()));
strCompiledHelpFile = szFileName;
//
// Replace the extension with .CHM
//
int nDotPos = strCompiledHelpFile.rfind(_T("."));
strCompiledHelpFile.erase(nDotPos);
strCompiledHelpFile += _T(".CHM");
return sc;
}
// -----------------------------------------------------------------------------
// We are being told that something has changed on the item pointed
// by lParam.
//
SC CBaseSnapin::ScOnPropertyChange(BOOL fScope, LPARAM lParam, IConsoleNameSpace *ipConsoleNameSpace, IConsole *ipConsole)
{
SC sc ;
LPDATAOBJECT pdataobject = NULL;
CBaseSnapinItem * pitem = NULL;
pdataobject = reinterpret_cast<LPDATAOBJECT>(lParam);
ASSERT(pdataobject);
pitem = Pitem(pdataobject);
ASSERT(pitem);
sc = pitem->ScOnPropertyChange();
if (sc)
goto Error;
if (pitem->FIsContainer())
{
// Container items should be updated just once.
sc = pitem->ScUpdateScopeItem(ipConsoleNameSpace);
if (sc)
goto Error;
}
else
{
// Result item. Need to update the item in all views.
// Call out to all the views to update themselves.
sc = ipConsole->UpdateAllViews(pdataobject, 0, ONVIEWCHANGE_UPDATERESULTITEM);
if (sc)
goto Error;
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScOnPropertyChange"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// The user has changed the name of an item.
//
SC CBaseSnapin::ScOnRename(LPDATAOBJECT lpDataObject, const tstring& strNewName, IConsole *ipConsole)
{
SC sc= S_FALSE;
CBaseSnapinItem *pitem = NULL;
ASSERT(lpDataObject);
pitem = Pitem(lpDataObject);
ASSERT(pitem);
if (strNewName.empty())
{
// ScOnQueryPaste should prevent this from ever happening
sc = E_UNEXPECTED;
goto Error;
}
if (strNewName.length() == 0)
goto Cleanup;
// Tell the object to rename
// If it returns S_FALSE, the rename was not done.
sc = pitem->ScOnRename(strNewName);
if (sc)
goto Error;
if (sc == S_OK)
{
// If this was renamed, reload our children
sc = ipConsole->UpdateAllViews(static_cast<IDataObject *>(pitem), 0, ONVIEWCHANGE_REFRESHCHILDREN);
if (sc)
goto Error;
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScOnRename"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// Received on a paste command.
//
// lpDataObject is the node receiving the past command.
// lpDataObjectList are the nodes being pasted.
// ppDataObjectPasted is where we answer the list of nodes that were successfully pasted.
//
SC CBaseSnapin::ScOnPaste(LPDATAOBJECT lpDataObject, LPDATAOBJECT lpDataObjectList, LPDATAOBJECT * ppDataObjectPasted, IConsole * ipConsole)
{
// Declarations
SC sc ;
CBaseSnapinItem * pitemTarget = NULL;
DWORD dwCanCopyCut = 0;
BOOL fPasted = FALSE;
CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
// Handle special case
if (!lpDataObjectList)
{
// ScOnQueryPaste should prevent this from ever happening
sc = E_UNEXPECTED;
goto Error;
}
// Data validation
ASSERT(lpDataObject);
ASSERT(lpDataObjectList);
ASSERT(ipConsole);
// other parameters can not be ASSERTed
// Get the target item
pitemTarget = Pitem(lpDataObject);
ASSERT(pitemTarget);
// Determine if this is a multiselect data object
sc = CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(lpDataObjectList, &pBaseMultiSelectSnapinItem);
if (sc)
goto Error;
// If we received a multiselect snapin item
if (pBaseMultiSelectSnapinItem)
{
// Call ScOnPaste for the multiselect object for dispatch
sc = pBaseMultiSelectSnapinItem->ScOnPaste(this, pitemTarget, lpDataObjectList, ppDataObjectPasted, ipConsole);
if (sc)
goto Error;
}
else
{
// Ask the item to copy the underlying object
sc = pitemTarget->ScOnPaste(lpDataObjectList, ppDataObjectPasted ? TRUE : FALSE, &fPasted);
if (sc)
goto Error;
// If the object was pasted
if (fPasted)
{
// If this was a cut, we need to return to MMC the items that were pasted
// (do not delete the dropped item if we are just adding it to a policy)
if (ppDataObjectPasted && !pitemTarget->FIsPolicy())
{
*ppDataObjectPasted = lpDataObjectList;
(*ppDataObjectPasted)->AddRef();
}
// Reload our children
sc = ipConsole->UpdateAllViews(static_cast<IDataObject *>(pitemTarget), 0, ONVIEWCHANGE_REFRESHCHILDREN);
if (sc)
goto Error;
}
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScOnPaste"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// We need to figure out whether we will allow pasting of this object.
// lpDataObject is the target object.
// lpDataObjectList are the objects being pasted.
//
SC CBaseSnapin::ScOnQueryPaste(LPDATAOBJECT lpDataObject, LPDATAOBJECT lpDataObjectList, LPDWORD pdwFlags)
{
// Declarations
SC sc ;
CBaseSnapinItem * pitemTarget = NULL;
BOOL fCanPaste = FALSE;
CNodeType * pnodetype = NULL;
CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
// Data validation
ASSERT(lpDataObject);
ASSERT(lpDataObjectList);
ASSERT(pdwFlags);
// Get the target item
pitemTarget = Pitem(lpDataObject);
ASSERT(pitemTarget);
// Determine if this is a multiselect data object
// Determine if this is a multiselect data object
sc = CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(lpDataObjectList, &pBaseMultiSelectSnapinItem);
if (sc == SC(DV_E_FORMATETC) )
{
sc = S_FALSE; // Cant paste.
return sc;
}
if (sc)
goto Error;
// If we received a multiselect snapin item
if (pBaseMultiSelectSnapinItem)
{
// Call ScOnCutOrMove for the multiselect object for dispatch
sc = pBaseMultiSelectSnapinItem->ScIsPastableDataObject(this, pitemTarget, lpDataObjectList, &fCanPaste);
if (sc)
goto Error;
}
else
{
// Determine if the parse operation is acceptable
// Here lpDataObjectList is only one item
sc = ScIsPastableDataObject(pitemTarget, lpDataObjectList, &fCanPaste);
if (sc)
goto Error;
}
// Determine if we can paste
if (!fCanPaste)
sc = S_FALSE; // indicate no pasting
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScOnQueryPaste()"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// We need to figure out whether we can handle the given dataobject that is from
// different process.
// lpDataObject is the target object.
// lpDataObjectList are the objects being pasted.
//
SC CBaseSnapin::ScOnCanPasteOutOfProcDataObject(LPBOOL pbCanHandle)
{
// Declarations
DECLARE_SC(sc, TEXT("CBaseSnapin::ScOnCanPasteOutOfProcDataObject"));
sc = ScCheckPointers(pbCanHandle);
if (sc)
return sc;
*pbCanHandle = TRUE;
return sc;
}
// -----------------------------------------------------------------------------
SC CBaseSnapin::ScOnCutOrMove(LPDATAOBJECT lpDataObjectList, IConsoleNameSpace * ipConsoleNameSpace, IConsole * ipConsole)
{
// Declarations
SC sc ;
CBaseSnapinItem * pitem = NULL;
CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
// Data validation
ASSERT(lpDataObjectList);
ASSERT(ipConsoleNameSpace);
ASSERT(ipConsole);
// Determine if this is a multiselect data object
sc = CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(lpDataObjectList, &pBaseMultiSelectSnapinItem);
if (sc)
goto Error;
// If we received a multiselect snapin item
if (pBaseMultiSelectSnapinItem)
{
// Call ScOnCutOrMove for the multiselect object for dispatch
sc = pBaseMultiSelectSnapinItem->ScOnCutOrMove(this, lpDataObjectList, ipConsoleNameSpace, ipConsole);
if (sc)
goto Error;
}
else
{
// Handle the normal case - PItem() does more work than a simple cast to verify that the snapin item belongs to the snapin etc.
pitem = Pitem(lpDataObjectList);
ASSERT(pitem);
// Ask the item to delete the underlying object.
sc = pitem->ScOnCutOrMove();
if (sc)
goto Error;
if (sc == S_FALSE)
goto Cleanup;
if (pitem->FIsContainer())
{
// Container items need to be deleted from the document
// Delete the item and everything below it.
if (pitem->Hscopeitem())
{
sc = ipConsoleNameSpace->DeleteItem(pitem->Hscopeitem(), TRUE);
if (sc)
goto Error;
pitem->SetHscopeitem(0);
}
}
else
{
// Leaf items need to be deleted from the views.
sc = ipConsole->UpdateAllViews(lpDataObjectList, 0, ONVIEWCHANGE_DELETESINGLEITEM);
if (sc)
goto Error;
}
// Delete this item, MMC is still using it. Below ScDeleteSubTree
// will release the object so Addref it. We got this through
// the Pitem() call which just type cast the dataobject.
pitem->AddRef();
sc = pitem->ScDeleteSubTree(TRUE);
if (sc)
goto Error;
}
Cleanup:
return sc;
Error:
TraceError(_T("CBaseSnapin::ScOnCutOrMove"), sc);
goto Cleanup;
}
// -----------------------------------------------------------------------------
// This method allows a CComponentData to tell us it is being
// destroyed. Any item referring to this CD as its owner will
// have their owner pointer nulled.
SC CBaseSnapin::ScOwnerDying(CComponentData *pComponentData)
{
ItemList::iterator iter;
for (iter = m_ilRootItems.begin(); iter != m_ilRootItems.end(); iter++)
{
if ((*iter)->FHasComponentData() && (*iter)->PComponentData() == pComponentData)
(*iter)->SetComponentData(NULL);
}
return S_OK;
}