DATAOBJ.CPP
///////////////////////////////////////////////////////////////////////////// 
// dataobj.cpp : Implementation of IDataObject for data communication 
// 
// 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 "disk.h" 
#include "dataobj.h" 
 
                
// 
// This is the minimum set of clipboard formats we must implement. 
// MMC uses these to get necessary information from our snapin about 
// our nodes. 
// 
UINT CDataObject::s_cfInternal    = 0; 
UINT CDataObject::s_cfDisplayName = 0; 
UINT CDataObject::s_cfNodeType    = 0; 
UINT CDataObject::s_cfSnapinClsid = 0; 
 
// Generated with uuidgen. Each node must have a GUID associated with it. 
// This one is for the main root node. 
const GUID GUID_RootNode = /* 570f713a-0f57-11d1-a194-00c04fc3092f */ 
{ 
    0x570f713a, 
    0x0f57, 
    0x11d1, 
    {0xa1, 0x94, 0x00, 0xc0, 0x4f, 0xc3, 0x09, 0x2f} 
}; 
 
// Generated with uuidgen. Each node must have a GUID associated with it. 
// This one is for the child under the main root node. 
const GUID GUID_MainNode = { /* 50c4fbdc-1f02-11d1-a1ae-00c04fc3092f */ 
    0x50c4fbdc, 
    0x1f02, 
    0x11d1, 
    {0xa1, 0xae, 0x00, 0xc0, 0x4f, 0xc3, 0x09, 0x2f} 
}; 
 
 
#define CF_SNAPIN_INTERNAL L"MMC_SNAPIN_MACHINE_NAME" 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CDataObject - This class is used to pass data back and forth with MMC. It 
//               uses a standard interface, IDataObject to acomplish this. Refer 
//               to OLE documentation for a description of clipboard formats and 
//               the IdataObject interface. 
 
//============================================================================ 
// 
// Constructor and Destructor 
//  
 
 
//---------------------------------------------------------------------------- 
//  CDataObject::CDataObject 
// 
CDataObject::CDataObject() 
{ 
 
  m_ulCookie = 0; 
  m_Context  = CCT_UNINITIALIZED; 
  m_Type     = COOKIE_IS_ROOT; 
 
  // These are the clipboard formats that we must supply at a minimum. 
  // mmc.h actually defined these. We can make up our own to use for 
  // other reasons. We don't need any others at this time. 
  s_cfInternal    = RegisterClipboardFormat(CF_SNAPIN_INTERNAL); 
  s_cfDisplayName = RegisterClipboardFormat(CCF_DISPLAY_NAME); 
  s_cfNodeType    = RegisterClipboardFormat(CCF_NODETYPE); 
  s_cfSnapinClsid = RegisterClipboardFormat(CCF_SNAPIN_CLASSID); 
 
} // end Constructor() 
 
 
 
 
//--------------------------------------------------------------------------- 
//  CDataObject::~CDataObject 
// 
CDataObject::~CDataObject() 
{ 
  if ( COOKIE_IS_STATUS == m_Type ) 
  { 
     _ASSERT(m_ulCookie); 
  } 
} // end Destructor() 
 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// IDataObject implementation 
//  
 
//--------------------------------------------------------------------------- 
//  Fill the hGlobal in pmedium with the requested data 
// 
STDMETHODIMP  
CDataObject::GetDataHere 
( 
  FORMATETC *pFormatEtc,     // [in]  Pointer to the FORMATETC structure  
  STGMEDIUM *pMedium         // [out] Pointer to the STGMEDIUM structure   
) 
{ 
  HRESULT hr = DV_E_FORMATETC;         // Unknown format 
  const   CLIPFORMAT cf = pFormatEtc->cfFormat; 
  IStream *pStream = NULL; 
 
  pMedium->pUnkForRelease = NULL;      // by OLE spec 
 
  do                                   // Write data to the stream based 
  {                                    // of the clipformat 
    hr = CreateStreamOnHGlobal( pMedium->hGlobal, FALSE, &pStream ); 
    if ( FAILED(hr) ) 
      return hr;                       // Minimal error checking 
 
    if (cf == s_cfDisplayName) 
    { 
      hr = _WriteDisplayName( pStream ); 
    } 
    else if (cf == s_cfInternal) 
    { 
      hr = _WriteInternal( pStream ); 
    } 
    else if (cf == s_cfNodeType) 
    { 
      hr = _WriteNodeType( pStream ); 
    } 
    else if (cf == s_cfSnapinClsid) 
    { 
      hr = _WriteClsid( pStream ); 
    } 
  } while (0); 
 
  pStream->Release(); 
 
  return hr; 
 
} // end GetDataHere() 
 
 
///////////////////////////////////////////////////////////////////////////// 
//  Support methods 
// 
 
//--------------------------------------------------------------------------- 
//  Write the appropriate GUID to the stream 
// 
HRESULT 
CDataObject::_WriteNodeType 
( 
  IStream* pStream           // [in] Stream we are writing to 
) 
{ 
  const GUID *pGuid = NULL; 
     
  switch (m_Type) 
  { 
    case COOKIE_IS_ROOT: 
      pGuid = &GUID_RootNode; 
      break; 
 
    case COOKIE_IS_STATUS: 
      pGuid = &GUID_MainNode; 
      break; 
 
    default: 
     _ASSERT( FALSE ); 
     return E_UNEXPECTED; 
  } 
 
  return pStream->Write( (PVOID)pGuid, sizeof(GUID), NULL ); 
 
} // end _WriteNodeType() 
 
 
//--------------------------------------------------------------------------- 
// Writes the display name to the stream 
//  
HRESULT 
CDataObject::_WriteDisplayName 
( 
  IStream* pStream           // [in] Stream we are writing to      
) 
{ 
  LPWSTR  pwszName; 
 
  if (m_ulCookie) 
  { 
    pwszName = L"Change This"; 
  } 
  else                                 // Null cookie is root  
  { 
    pwszName = L"Hello MMC"; 
  } 
 
  ULONG ulSizeofName = wcslen(pwszName); 
  ulSizeofName++;                      // Count null 
  ulSizeofName *= sizeof(WCHAR); 
 
  return pStream->Write(pwszName, ulSizeofName, NULL); 
 
} // end _WriteDisplayName() 
 
 
//--------------------------------------------------------------------------- 
//  Writes a pointer to this data object to the stream 
// 
HRESULT 
CDataObject::_WriteInternal 
( 
  IStream* pStream           // [in] Stream we are writing to  
) 
{ 
  CDataObject *pThis = this; 
  return pStream->Write( &pThis, sizeof(CDataObject*), NULL ); 
 
} // end _WriteInternal 
 
//--------------------------------------------------------------------------- 
//  Writes the Class ID to the stream 
// 
HRESULT 
CDataObject::_WriteClsid 
( 
  IStream* pStream           // [in] Stream we are writing to 
) 
{ 
  return pStream->Write( &CLSID_ComponentData, 
                         sizeof(CLSID_ComponentData), 
                         NULL 
                       ); 
} // end _WriteClsid() 
 
 
//--------------------------------------------------------------------------- 
//  The cookie is what ever we decide it is going to be. 
//  This is being called from QuerDataObject. Refer to that code. 
// 
VOID  
CDataObject::SetCookie 
( 
  ULONG              ulCookie, // [in] Unique indentifier 
  DATA_OBJECT_TYPES  Context,  // [in] Context of the caller 
  COOKIETYPE         Type      // [in] Type of cookie 
) 
{ 
  _ASSERT(!m_ulCookie); 
  m_ulCookie = ulCookie; 
  m_Type = Type; 
  m_Context = Context; 
 
  if (m_Type == COOKIE_IS_STATUS) 
  { 
    _ASSERT(m_ulCookie); 
  } 
} // end SetCookie() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// IUnknown implementation 
//  
 
 
//--------------------------------------------------------------------------- 
//  Standard implementation 
// 
STDMETHODIMP 
CDataObject::QueryInterface 
( 
  REFIID  riid, 
  LPVOID *ppvObj 
) 
{ 
  // TRACE_METHOD(CDataObject, QueryInterface); 
  HRESULT hr = S_OK; 
 
  do 
  { 
    if (NULL == ppvObj) 
    { 
      hr = E_INVALIDARG; 
      break; 
    } 
 
    if (IsEqualIID(riid, IID_IUnknown)) 
    { 
      *ppvObj = (IUnknown *)(IDataObject *)this; 
    } 
    else if (IsEqualIID(riid, IID_IDataObject)) 
    { 
      *ppvObj = (IUnknown *)(IDataObject *)this; 
    } 
    else 
    { 
      hr = E_NOINTERFACE; 
      *ppvObj = NULL; 
      break; 
    } 
 
    //  
    // If we got this far we are handing out a new interface pointer on  
    // this object, so addref it.   
    //  
 
    AddRef(); 
  } while (0); 
 
  return hr; 
 
} // end QueryInterface() 
 
//--------------------------------------------------------------------------- 
//  Standard implementation 
// 
STDMETHODIMP_(ULONG) 
CDataObject::AddRef() 
{ 
  return InterlockedIncrement((LONG *) &m_cRefs); 
} 
 
//--------------------------------------------------------------------------- 
//  Standard implementation 
// 
STDMETHODIMP_(ULONG) 
CDataObject::Release() 
{ 
  ULONG cRefsTemp; 
 
  cRefsTemp = InterlockedDecrement((LONG *)&m_cRefs); 
 
  if (0 == cRefsTemp) 
  { 
    delete this; 
  } 
 
  return cRefsTemp; 
}