COMPDATA.CPP

///////////////////////////////////////////////////////////////////////////// 
// compdata.cpp : IComponentData Interface to communicate with MMC for
// scope pane use
//
// This is a part of the MMC SDK.
// Copyright (C) 1997 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// MMC SDK Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// MMC Library product.
//

#include "stdafx.h"
#include <mmc.h> // Copy from MMC.SDK
#include "disk.h"
#include "globals.h" // Helper functions
#include "comp.h"
#include "compdata.h"

/////////////////////////////////////////////////////////////////////////////
// CComponentData - This class is the interface to handle anything to do
// with the scope pane. MMC calls the IComponent interfaces.
// This class keeps a few pointers to interfaces that MMC
// implements.


CComponentData::CComponentData()
{
m_ipConsoleNameSpace = NULL;
m_ipConsole = NULL;
}

CComponentData::~CComponentData()
{
// We release the cached interface pointers in Destroy()
}


/////////////////////////////////////////////////////////////////////////////
// IComponentData methods
//

//---------------------------------------------------------------------------
// We get here only once, when the user clicks on the snapin.
//
// This method should not change as we progress through further steps.
// Here we get a chance to get pointer to some interfaces MMC provides.
// We QueryInterface for pointers to the name space and console, which
// we cache in local variables
// The other task to acomplish here is the adding of a bitmap that contains
// the icons to be used in the scope pane.
//
STDMETHODIMP
CComponentData::Initialize
(
LPUNKNOWN pUnknown // [in] Pointer to the IConsole s IUnknown interface
)
{
HRESULT hr;
LPIMAGELIST lpScopeImage;

_ASSERT( NULL != pUnknown );

// MMC should only call ::Initialize once!
_ASSERT( NULL == m_ipConsoleNameSpace );

//
// Get pointer to name space interface
//
hr = pUnknown->QueryInterface(IID_IConsoleNameSpace, (VOID**)(&m_ipConsoleNameSpace));
_ASSERT( S_OK == hr );

//
// Get pointer to console interface
//
hr = pUnknown->QueryInterface(IID_IConsole, (VOID**)(&m_ipConsole));
_ASSERT( S_OK == hr );


//
// Add the images for the scope tree
//
hr = m_ipConsole->QueryScopeImageList(&lpScopeImage);
_ASSERT( S_OK == hr );

// Load the bitmaps from the dll
m_hbmp16x16 = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_SCOPE_16x16));
_ASSERT( NULL != m_hbmp16x16 );

// Set the images
hr = lpScopeImage->ImageListSetStrip( (long*)m_hbmp16x16,
(long*)m_hbmp16x16,
0,
RGB(0,255,0)
);
_ASSERT( S_OK == hr );

lpScopeImage->Release();

return S_OK;

} // end Initialize()


//---------------------------------------------------------------------------
// Release interfaces and clean up objects which allocated memory
//
STDMETHODIMP
CComponentData::Destroy()
{
// Free interfaces
m_ipConsoleNameSpace->Release();
m_ipConsoleNameSpace = NULL;

m_ipConsole->Release();
m_ipConsole = NULL;

_ASSERT( DeleteObject(m_hbmp16x16) );

return S_OK;

} // end Destroy()


//---------------------------------------------------------------------------
// Come in here once right after Initialize. MMC wants a pointer to the
// IComponent interface.
//
STDMETHODIMP
CComponentData::CreateComponent
(
LPCOMPONENT* ppComponent // [out] Pointer to the location that stores
) // the newly created pointer to IComponent
{
CComObject<CComponent>* pObject;

//
// MMC asks us for a pointer to the IComponent interface
//
// For those getting up to speed with COM...
// If we had implemented IUnknown with its methods QueryInterface, AddRef,
// and Release in our CComponent class...
// The following line would have worked
//
// pNewSnapin = new CComponent(this);
//
// In this code we will have ATL take care of IUnknown for us and create
// an object in the following manner...

_ASSERT( NULL != ppComponent );

CComObject<CComponent>::CreateInstance( &pObject );
_ASSERT( NULL != pObject );

// Step2: Store IComponentData.
// Can't have a constructor with parameters, so pass it in this way.
pObject->SetIComponentData( this );

return pObject->QueryInterface( IID_IComponent,
reinterpret_cast<void**>(ppComponent)
);
} // end CreateComponent()


//---------------------------------------------------------------------------
// In this first step, we only implement EXPAND.
// The expand message asks us to populate what is under our root node.
// We just put one item under there.
//
STDMETHODIMP
CComponentData::Notify
(
LPDATAOBJECT lpDataObject, // [in] Points to the selected data object
MMC_NOTIFY_TYPE event, // [in] Identifies action taken by user.
long arg, // [in] Depends on the notification type
long param // [in] Depends on the notification type
)
{
HRESULT hr = S_OK;

switch (event)
{
case MMCN_EXPAND:
ATLTRACE( L"ComponentData::Notify: MMCN_EXPAND\n" );
hr = OnExpand( lpDataObject, arg, param );
break;

case MMCN_DELETE: // Step2: Function not implemented
ATLTRACE( L"CComponentData::Notify: MMCN_DELETE unimplemented\n" );
hr = S_FALSE;
break;

case MMCN_RENAME: // Step2: Function not implemented
ATLTRACE( L"ComponentData::Notify: MMCN_RENAME unimplemented\n" );
hr = S_FALSE;
break;

case MMCN_SELECT: // Step2: Function not implemented
ATLTRACE(_T("ComponentData::Notify: MMCN_SELECT unimplemented\n"));
hr = S_FALSE;
break;

case MMCN_PROPERTY_CHANGE: // Step2: Function not implemented
ATLTRACE(_T("ComponentData::Notify: MMCN_PROPERTY_CHANGE unimplemented\n"));
hr = S_FALSE;
break;

case MMCN_REMOVE_CHILDREN: // Step2: Function not implemented
ATLTRACE(_T("ComponentData::Notify: MMCN_REMOVE_CHILDREN unimplemented\n"));
hr = S_FALSE;
break;

default:
ATLTRACE( L"CComponentData::Notify: unimplemented event %x\n", event );
hr = S_FALSE;
break;
}
return hr;

} // end Notify()


//---------------------------------------------------------------------------
// This is where MMC asks us to provide IDataObjects for every node in the
// scope pane
//
STDMETHODIMP
CComponentData::QueryDataObject
(
long cookie, // [in] Data object's unique identifier
DATA_OBJECT_TYPES type, // [in] Data object's type
LPDATAOBJECT* ppDataObject // [out] Points to the returned data object
)
{
HRESULT hr = S_OK;
CDataObject *pdoNew = NULL;

do
{
pdoNew = new CDataObject;
*ppDataObject = pdoNew;

if (!pdoNew)
{
hr = E_OUTOFMEMORY;
// Use MessageBox() rather than IConsole::MessageBox() here because the
// first time this gets called m_ipConsole is not fully initialized
::MessageBox( NULL,
L"Unable to allocate new data object",
L"CComponentData::QueryDataObject",
MB_OK
);
break;
}

//
// The cookie represents a snapin manager or scope pane item.
//
// If the passed-in cookie is NULL, it is our snapin's root node folder
// We never needed to ask for this to be created. MMC did this for us.
//
// If the passed-in cookie is non-NULL, then it should be one we
// created when we added a node to the scope pane. See OnExpand().
//

if (cookie)
{
// cookie is the lparam field that we passed in SCOPEDATAITEM
// used for the m_ipConsoleNameSpace->InsertItem(&sdi);
pdoNew->SetCookie( cookie, CCT_SCOPE, COOKIE_IS_STATUS );
}
else
{
// In this case the node is our top node, and was placed there for us.
pdoNew->SetCookie( 0, type, COOKIE_IS_ROOT );
}
} while (0);

return hr;

} // end QueryDataObject()


//---------------------------------------------------------------------------
// This is where we provide strings for nodes in the scope pane.
// We only have one node, so this is easy. MMC handles the root node string.
//
STDMETHODIMP
CComponentData::GetDisplayInfo
(
LPSCOPEDATAITEM pItem // [in, out] Points to a SCOPEDATAITEM struct
)
{
_ASSERT( NULL != pItem );
_ASSERT( pItem->mask & SDI_STR );

pItem->displayname = (LPOLESTR)L"Geometry"; // Title to our child folder

return S_OK;

} // end GetDisplayInfo()


//---------------------------------------------------------------------------
// Step2: Here we test two data objects.
//
STDMETHODIMP
CComponentData::CompareObjects
(
LPDATAOBJECT lpDataObjectA, // [in] First data object to compare
LPDATAOBJECT lpDataObjectB // [in] Second data object to compare
)
{
CDataObject *pdoA;
CDataObject *pdoB;

// At least one of these data objects is supposed to be ours, so one
// of the extracted pointers should be non-NULL.
pdoA = ExtractOwnDataObject( lpDataObjectA );
pdoB = ExtractOwnDataObject( lpDataObjectB );
_ASSERT( pdoA || pdoB ); // Assert if we can't get any objects

// If extraction failed for one of them, then that one is foreign and
// can't be equal to the other one. (Or else ExtractOwnDataObject
// returned NULL because it ran out of memory, but the most conservative
// thing to do in that case is say they're not equal.)
if( !pdoA || !pdoB )
{
return S_FALSE;
}

// The cookie type could be COOKIE_IS_ROOT or COOKIE_IS_OBJECT. If they
// differ then the objects refer to different things.
if( pdoA->GetCookieType() != pdoB->GetCookieType() )
{
return S_FALSE;
}

return S_OK;

} // end CompareObjects()


/////////////////////////////////////////////////////////////////////////////
// Methods needed to support IComponentData
//

//---------------------------------------------------------------------------
// Here is our chance to place things under the root node.
// We will put one item under it.
//
HRESULT
CComponentData::OnExpand
(
LPDATAOBJECT pDataObject, // [in] Points to data object
long arg, // [in] TRUE is we are expanding
long param // [in] Points to the HSCOPEITEM
)
{
CDataObject *pdo;
SCOPEDATAITEM sdi;
INT iResult;
HRESULT hr = S_OK;

_ASSERT( NULL != m_ipConsoleNameSpace ); // Make sure we QI'ed for the interface
_ASSERT( NULL != pDataObject ); // Must have valid data object

if (TRUE == arg )
{
pdo = ExtractOwnDataObject( pDataObject );

if( !pdo )
{
hr = m_ipConsole->MessageBox( L"Did not understand the data object.\nNot set up to be an extension",
L"CComponentData::OnExpand",
MB_OK,
&iResult
);
return hr;
}

// Make sure that what we are placing ourselvs under is the root node!
if (pdo->GetCookieType() != COOKIE_IS_ROOT)
return S_FALSE;

_ASSERT( CCT_SCOPE == pdo->GetContext() ); // Scope pane must be current context
_ASSERT( COOKIE_IS_ROOT == pdo->GetCookieType() );

//
// Place our folder into the scope pane
//
ZeroMemory(&sdi, sizeof(SCOPEDATAITEM) );
sdi.mask = SDI_STR | // Displayname is valid
SDI_PARAM | // lParam is valid
SDI_IMAGE | // nImage is valid
SDI_OPENIMAGE | // nOpenImage is valid
SDI_PARENT;
sdi.relativeID = (HSCOPEITEM)param;
sdi.nImage = 0;
sdi.nOpenImage = 1;
sdi.displayname = MMC_CALLBACK;
sdi.lParam = (LPARAM)1; // The cookie

hr = m_ipConsoleNameSpace->InsertItem( &sdi );
}
return hr;

} // end OnExpand()