/*++

Copyright (C) 1997-1999 Microsoft Corporation
				
Module Name:

    DATAOBJ.CPP

Abstract:

    Implementation of IDataObject for data communication

--*/

#include "StdAfx.h"
#include "smlogcfg.h"
#include "smnode.h"
#include "dataobj.h"

// MMC uses these to get necessary information from our snapin about
// our nodes.

// Register the clipboard formats
unsigned int CDataObject::s_cfMmcMachineName =
    RegisterClipboardFormat(CF_MMC_SNAPIN_MACHINE_NAME);
unsigned int CDataObject::s_cfDisplayName =
    RegisterClipboardFormat(CCF_DISPLAY_NAME);
unsigned int CDataObject::s_cfNodeType =
    RegisterClipboardFormat(CCF_NODETYPE);
unsigned int CDataObject::s_cfSnapinClsid =
    RegisterClipboardFormat(CCF_SNAPIN_CLASSID);

unsigned int CDataObject::s_cfInternal =
    RegisterClipboardFormat(CF_INTERNAL);

#ifdef _DEBUG                          // For tracking data objects
  static UINT nCount = 0;
  WCHAR wszMsg[64];
#endif

/////////////////////////////////////////////////////////////////////////////
// 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.

//---------------------------------------------------------------------------
// Added some code to check on data objects  
CDataObject::CDataObject()
:   m_cRefs(0),
    m_ulCookie(0),
    m_Context(CCT_UNINITIALIZED),
    m_CookieType(COOKIE_IS_ROOTNODE)
{

#ifdef _DEBUG
  swprintf( wszMsg, L"DATAOBJECT Create %u\n", nCount );
  LOCALTRACE( wszMsg );
  nCount++;
#endif

} // end Constructor()

//---------------------------------------------------------------------------
// Added some code to check on data objects  
//
CDataObject::~CDataObject()
{
  if ( ( COOKIE_IS_COUNTERMAINNODE == m_CookieType )
     || ( COOKIE_IS_TRACEMAINNODE == m_CookieType )
     || ( COOKIE_IS_ALERTMAINNODE == m_CookieType ) )
  {
    ASSERT( m_ulCookie );
  }

#ifdef _DEBUG
  swprintf( wszMsg, L"DATAOBJECT Delete %u\n", nCount );
  LOCALTRACE( wszMsg );
  nCount--;
#endif

} // 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  
)
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState());

  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_cfMmcMachineName)
    {
      hr = WriteMachineName( 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_CookieType )
  {
    case COOKIE_IS_ROOTNODE:
      pGuid = &GUID_RootNode;
      break;

    case COOKIE_IS_COUNTERMAINNODE:
      pGuid = &GUID_CounterMainNode;
      break;

    case COOKIE_IS_TRACEMAINNODE:
      pGuid = &GUID_TraceMainNode;
      break;

    case COOKIE_IS_ALERTMAINNODE:
      pGuid = &GUID_AlertMainNode;
      break;

    default:
     ASSERT( FALSE );
     return E_UNEXPECTED;
  }

  return pStream->Write( (PVOID)pGuid, sizeof(GUID), NULL );

} // end WriteNodeType()


//---------------------------------------------------------------------------
//  Writes the display name to the stream.  This is the name associated 
//  with the root node
// 
HRESULT
CDataObject::WriteDisplayName
(
  IStream* pStream           // [in] Stream we are writing to     
)
{
    CString strName;
    ULONG ulSizeofName;
    ResourceStateManager    rsm;

    if( NULL == m_ulCookie )
    { 
        // Add Local vs machine name when implement machine name override/change.
        // NOTE:  For root node, cookie is either NULL or points to a root node object.
        strName.LoadString( IDS_MMC_DEFAULT_NAME ); 
    } else {
        PSMNODE pTmp = reinterpret_cast<PSMNODE>(m_ulCookie);
//???        strName = *pTmp->GetDisplayName();
        strName = pTmp->GetDisplayName();
    }

    ulSizeofName = strName.GetLength();
    ulSizeofName++;                      // Count null character
    ulSizeofName *= sizeof(WCHAR);

    return pStream->Write((LPCWSTR)strName, ulSizeofName, NULL);

} // end WriteDisplayName()

//---------------------------------------------------------------------------
//  Writes the machine name to the stream.  
// 
HRESULT
CDataObject::WriteMachineName
(
  IStream* pStream           // [in] Stream we are writing to     
)
{
    CString strName;
    ULONG ulSizeOfName;

    if( NULL == m_ulCookie ) {  
        // Cookie is null if not an extension.  In that case, only support
        // local machine.
        strName = L"";  // local
    } else {
        PSMNODE pTmp = reinterpret_cast<PSMNODE>(m_ulCookie);
        strName = pTmp->GetMachineName();
    }

    ulSizeOfName = strName.GetLength();
    ulSizeOfName++;                      // Count null character
    ulSizeOfName *= sizeof(WCHAR);

    return pStream->Write((LPCWSTR)strName, ulSizeOfName, NULL);

} // end WriteMachineName()

//---------------------------------------------------------------------------
//  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 QueryDataObject. Refer to that code.
//
VOID 
CDataObject::SetData
(
  MMC_COOKIE         ulCookie, // [in] Unique indentifier
  DATA_OBJECT_TYPES  Context,  // [in] Context of the caller
  COOKIETYPE         Type      // [in] Type of cookie
)
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState());

  ASSERT( NULL == m_ulCookie );
  m_ulCookie   = ulCookie;
  m_Context    = Context;
  m_CookieType = Type;

} // end SetData()


/////////////////////////////////////////////////////////////////////////////
// IUnknown implementation
// 


//---------------------------------------------------------------------------
//  Standard implementation
//
STDMETHODIMP
CDataObject::QueryInterface
(
  REFIID  riid,
  LPVOID *ppvObj
)
{
  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;

} // end Release()