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()