/////////////////////////////////////////////////////////////////////////////
// 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;
}