452 lines
12 KiB
C++
452 lines
12 KiB
C++
|
/*++
|
|||
|
|
|||
|
<EFBFBD> 1998 Seagate Software, Inc. All rights reserved.
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
MsDatObj.cpp
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Implementation of IDataObject interface for Multi-Select
|
|||
|
Allows MMC to get a list of Node Types
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Art Bragg 28-Aug-1997
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
/////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
//
|
|||
|
/////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include "stdafx.h"
|
|||
|
#include "msdatobj.h"
|
|||
|
|
|||
|
#define BUMP_SIZE 20
|
|||
|
|
|||
|
// Declare Snap-in NodeType formats:
|
|||
|
UINT CMsDataObject::m_cfObjectTypes = RegisterClipboardFormat(CCF_OBJECT_TYPES_IN_MULTI_SELECT);
|
|||
|
|
|||
|
HRESULT
|
|||
|
CMsDataObject::FinalConstruct(
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Called during initial CMsDataObject construction to initialize members.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
S_OK - Initialized correctly.
|
|||
|
|
|||
|
E_xxxxxxxxxxx - Failure occurred.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
WsbTraceIn( L"CMsDataObject::FinalConstruct", L"" );
|
|||
|
|
|||
|
try {
|
|||
|
m_Count = 0;
|
|||
|
|
|||
|
// Allocate initial array of GUIDs
|
|||
|
m_pGUIDArray = (GUID *) malloc (BUMP_SIZE * sizeof(GUID));
|
|||
|
WsbAffirm ((m_pGUIDArray != NULL), E_OUTOFMEMORY);
|
|||
|
ZeroMemory (m_pGUIDArray, (BUMP_SIZE * sizeof(GUID)));
|
|||
|
|
|||
|
m_pUnkNodeArray = (IUnknown **) malloc( BUMP_SIZE * sizeof(IUnknown*) );
|
|||
|
WsbAffirm ((m_pGUIDArray != NULL), E_OUTOFMEMORY);
|
|||
|
ZeroMemory (m_pGUIDArray, (BUMP_SIZE * sizeof(IUnknown*)));
|
|||
|
|
|||
|
m_pObjectIdArray = (GUID *) malloc (BUMP_SIZE * sizeof(GUID));
|
|||
|
WsbAffirm ((m_pObjectIdArray != NULL), E_OUTOFMEMORY);
|
|||
|
ZeroMemory (m_pObjectIdArray, (BUMP_SIZE * sizeof(GUID)));
|
|||
|
|
|||
|
m_ArraySize = BUMP_SIZE;
|
|||
|
|
|||
|
WsbAffirmHr (CComObjectRoot::FinalConstruct( ));
|
|||
|
} WsbCatch (hr);
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::FinalConstruct", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return( hr );
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
CMsDataObject::FinalRelease(
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Called on final release in order to clean up all members.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::FinalRelease", L"" );
|
|||
|
|
|||
|
// Clean up array of GUIDs
|
|||
|
free( m_pGUIDArray );
|
|||
|
|
|||
|
for( DWORD i = 0; i < m_Count; i++ ) {
|
|||
|
|
|||
|
m_pUnkNodeArray[i]->Release();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
free( m_pUnkNodeArray );
|
|||
|
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::FinalRelease", L"" );
|
|||
|
}
|
|||
|
|
|||
|
// IDataObject
|
|||
|
|
|||
|
STDMETHODIMP
|
|||
|
CMsDataObject::GetDataHere(
|
|||
|
LPFORMATETC lpFormatetc,
|
|||
|
LPSTGMEDIUM /*lpMedium*/
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Retrieve information FROM the dataobject and put INTO lpMedium.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpFormatetc - Format to retreive.
|
|||
|
|
|||
|
lpMedium - Storage to put information into.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
S_OK - Storage filled in.
|
|||
|
|
|||
|
E_xxxxxxxxxxx - Failure occurred.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::GetDataHere", L"lpFormatetc->cfFormat = <%ls>", RsClipFormatAsString( lpFormatetc->cfFormat ) );
|
|||
|
|
|||
|
HRESULT hr = E_NOTIMPL;
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::GetDataHere", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return( hr );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP
|
|||
|
CMsDataObject::SetData(
|
|||
|
LPFORMATETC lpFormatetc,
|
|||
|
LPSTGMEDIUM /*lpMedium*/,
|
|||
|
BOOL /*fRelease*/
|
|||
|
)
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::SetData", L"lpFormatetc->cfFormat = <%ls>", RsClipFormatAsString( lpFormatetc->cfFormat ) );
|
|||
|
|
|||
|
HRESULT hr = E_NOTIMPL;
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::SetData", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return( hr );
|
|||
|
}
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////
|
|||
|
// Note - CMsDataObject does not implement these
|
|||
|
///////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
STDMETHODIMP
|
|||
|
CMsDataObject::GetData(
|
|||
|
LPFORMATETC lpFormatetcIn,
|
|||
|
LPSTGMEDIUM lpMedium
|
|||
|
)
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::GetData", L"lpFormatetc->cfFormat = <%ls>", RsClipFormatAsString( lpFormatetcIn->cfFormat ) );
|
|||
|
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
lpMedium->tymed = TYMED_NULL;
|
|||
|
lpMedium->hGlobal = NULL;
|
|||
|
lpMedium->pUnkForRelease = NULL;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// Don't need to throw error if not a format we don't understand -
|
|||
|
// which is currently only CCF_OBJECT_TYPES_IN_MULTI_SELECT
|
|||
|
//
|
|||
|
if( lpFormatetcIn->cfFormat == m_cfObjectTypes ) {
|
|||
|
|
|||
|
//
|
|||
|
// Check to make sure there is data to transfer
|
|||
|
//
|
|||
|
WsbAffirm( ( lpFormatetcIn->tymed & TYMED_HGLOBAL ), DV_E_TYMED );
|
|||
|
|
|||
|
//
|
|||
|
// m_ppDataObjects m_count
|
|||
|
//
|
|||
|
UINT datasize = sizeof(DWORD) + ( sizeof(GUID) * m_Count );
|
|||
|
lpMedium->hGlobal = ::GlobalAlloc( GPTR, datasize );
|
|||
|
WsbAffirmAlloc( lpMedium->hGlobal );
|
|||
|
|
|||
|
//
|
|||
|
// Put the count in the allocated memory
|
|||
|
//
|
|||
|
BYTE* pb = reinterpret_cast<BYTE*>(lpMedium->hGlobal);
|
|||
|
*((DWORD*)lpMedium->hGlobal) = m_Count;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the GUIDs to the allocated memory
|
|||
|
//
|
|||
|
if( m_Count > 0 ) {
|
|||
|
|
|||
|
pb += sizeof(DWORD);
|
|||
|
CopyMemory(pb, m_pGUIDArray, m_Count * sizeof(GUID));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
lpMedium->tymed = TYMED_HGLOBAL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
hr = DATA_E_FORMATETC;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} WsbCatch( hr );
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::GetData", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return( hr );
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP CMsDataObject::EnumFormatEtc(DWORD /*dwDirection*/, LPENUMFORMATETC* /*ppEnumFormatEtc*/)
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::EnumFormatEtc", L"" );
|
|||
|
|
|||
|
HRESULT hr = E_NOTIMPL;
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::EnumFormatEtc", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return( hr );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT CMsDataObject::RetrieveMultiSelectData (LPSTGMEDIUM lpMedium)
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::RetrieveMultiSelectData", L"" );
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
try {
|
|||
|
WsbAffirm( lpMedium != NULL, E_POINTER);
|
|||
|
WsbAffirm( lpMedium->tymed == TYMED_HGLOBAL, E_FAIL );
|
|||
|
|
|||
|
// Create the stream on the hGlobal passed in. When we write to the stream,
|
|||
|
// it simultaneously writes to the hGlobal the same information.
|
|||
|
LPSTREAM lpStream;
|
|||
|
WsbAffirmHr( CreateStreamOnHGlobal(lpMedium->hGlobal, FALSE, &lpStream ));
|
|||
|
|
|||
|
// Write 'len' number of bytes from pBuffer into the stream. When we write
|
|||
|
// to the stream, it simultaneously writes to the global memory we
|
|||
|
// associated it with above.
|
|||
|
ULONG numBytesWritten;
|
|||
|
|
|||
|
// Write the count first
|
|||
|
WsbAffirmHr( lpStream->Write(&m_Count, sizeof (m_Count), &numBytesWritten ));
|
|||
|
|
|||
|
// Write the GUID array
|
|||
|
WsbAffirmHr( lpStream->Write(m_pGUIDArray, m_Count * sizeof (GUID), &numBytesWritten ));
|
|||
|
|
|||
|
// Because we told CreateStreamOnHGlobal with 'FALSE', only the stream is released here.
|
|||
|
// Note - the caller (i.e. snap-in, object) will free the HGLOBAL
|
|||
|
// at the correct time. This is according to the IDataObject specification.
|
|||
|
lpStream->Release();
|
|||
|
|
|||
|
} WsbCatch( hr );
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::RetrieveMultiSelectData", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Data setting method
|
|||
|
// Note that we keep the node array seperate from the GUID array because
|
|||
|
// the GetData interface memory copies the GUID array to the stream.
|
|||
|
|
|||
|
STDMETHODIMP
|
|||
|
CMsDataObject::AddNode (ISakNode *pNode )
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::AddNode", L"pNode = <0x%p>", pNode );
|
|||
|
HRESULT hr = S_OK;
|
|||
|
GUID thisGUID;
|
|||
|
GUID objectId;
|
|||
|
|
|||
|
GUID * pGUIDArray = 0,
|
|||
|
* pObjectIdArray = 0;
|
|||
|
IUnknown ** pUnkNodeArray = 0;
|
|||
|
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// Get the object type GUID
|
|||
|
//
|
|||
|
WsbAffirmHr( pNode->GetNodeType( &thisGUID ) );
|
|||
|
|
|||
|
//
|
|||
|
// Get the unique ID for the engine object (i.e. FsaResource)
|
|||
|
//
|
|||
|
WsbAffirmHr( pNode->GetObjectId( &objectId ) );
|
|||
|
|
|||
|
//
|
|||
|
// Reallocate if we need to
|
|||
|
//
|
|||
|
if( m_Count >= m_ArraySize ) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Allocate new buffer
|
|||
|
//
|
|||
|
m_ArraySize += BUMP_SIZE;
|
|||
|
pGUIDArray = (GUID *) malloc( m_ArraySize * sizeof( GUID ) );
|
|||
|
WsbAffirmAlloc( pGUIDArray );
|
|||
|
pUnkNodeArray = (IUnknown **) malloc( m_ArraySize * sizeof( IUnknown* ) );
|
|||
|
WsbAffirmAlloc( pUnkNodeArray );
|
|||
|
pObjectIdArray = (GUID *) malloc( m_ArraySize * sizeof( GUID ) );
|
|||
|
WsbAffirmAlloc( pObjectIdArray );
|
|||
|
|
|||
|
//
|
|||
|
// copy over old buffer and free
|
|||
|
//
|
|||
|
memcpy( pGUIDArray, m_pGUIDArray, m_Count * sizeof( GUID ) );
|
|||
|
memcpy( pUnkNodeArray, m_pUnkNodeArray, m_Count * sizeof( IUnknown* ) );
|
|||
|
memcpy( pObjectIdArray, m_pObjectIdArray, m_Count * sizeof( GUID ) );
|
|||
|
free( m_pGUIDArray );
|
|||
|
free( m_pUnkNodeArray );
|
|||
|
free( m_pObjectIdArray );
|
|||
|
m_pGUIDArray = pGUIDArray;
|
|||
|
m_pUnkNodeArray = pUnkNodeArray;
|
|||
|
m_pObjectIdArray = pObjectIdArray;
|
|||
|
pGUIDArray = 0;
|
|||
|
pUnkNodeArray = 0;
|
|||
|
pObjectIdArray = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Put the GUID in the array
|
|||
|
//
|
|||
|
m_pGUIDArray[ m_Count ] = thisGUID;
|
|||
|
|
|||
|
//
|
|||
|
// Put the objectId in the array
|
|||
|
//
|
|||
|
m_pObjectIdArray[ m_Count ] = objectId;
|
|||
|
|
|||
|
//
|
|||
|
// Put the unknown pointer (the Cookie) in the array
|
|||
|
//
|
|||
|
CComPtr<IUnknown> pUnkNode;
|
|||
|
WsbAffirmHr( RsQueryInterface( pNode, IUnknown, pUnkNode ) );
|
|||
|
pUnkNode.CopyTo( &m_pUnkNodeArray[ m_Count ] );
|
|||
|
m_Count++;
|
|||
|
|
|||
|
} WsbCatch( hr );
|
|||
|
|
|||
|
if( pGUIDArray ) free( pGUIDArray );
|
|||
|
if( pObjectIdArray ) free( pObjectIdArray );
|
|||
|
if( pUnkNodeArray ) free( pUnkNodeArray );
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::AddNode", L"hr = <%ls>", WsbHrAsString( hr ) );
|
|||
|
return( hr );
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP
|
|||
|
CMsDataObject::GetNodeEnumerator( IEnumUnknown **ppEnum )
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::GetNodeEnumerator", L"ppEnum = <0x%p>", ppEnum );
|
|||
|
|
|||
|
HRESULT hr = S_OK;
|
|||
|
CEnumUnknown * pEnum = 0;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
WsbAffirmPointer( ppEnum );
|
|||
|
*ppEnum = 0;
|
|||
|
|
|||
|
//
|
|||
|
// New an ATL enumerator
|
|||
|
//
|
|||
|
pEnum = new CEnumUnknown;
|
|||
|
WsbAffirm( 0 != pEnum, E_OUTOFMEMORY );
|
|||
|
|
|||
|
//
|
|||
|
// Initialize it to copy the current node interface pointers
|
|||
|
//
|
|||
|
WsbAffirmHr( pEnum->FinalConstruct() );
|
|||
|
WsbAffirmHr( pEnum->Init( &m_pUnkNodeArray[0], &m_pUnkNodeArray[m_Count], NULL, AtlFlagCopy ) );
|
|||
|
WsbAffirmHr( pEnum->QueryInterface( IID_IEnumUnknown, (void**)ppEnum ) );
|
|||
|
|
|||
|
} WsbCatchAndDo( hr,
|
|||
|
|
|||
|
if( pEnum ) delete pEnum;
|
|||
|
|
|||
|
);
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::GetNodeEnumerator", L"hr = <%ls>, *ppEnum = <%ls>", WsbHrAsString( hr ), WsbPtrToPtrAsString( (void**)ppEnum ) );
|
|||
|
return( hr );
|
|||
|
}
|
|||
|
|
|||
|
STDMETHODIMP
|
|||
|
CMsDataObject::GetObjectIdEnumerator( IEnumGUID ** ppEnum )
|
|||
|
{
|
|||
|
WsbTraceIn( L"CMsDataObject::GetObjectIdEnumerator", L"ppEnum = <0x%p>", ppEnum );
|
|||
|
|
|||
|
HRESULT hr = S_OK;
|
|||
|
CEnumGUID * pEnum = 0;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
WsbAffirmPointer( ppEnum );
|
|||
|
*ppEnum = 0;
|
|||
|
|
|||
|
//
|
|||
|
// New an ATL enumerator
|
|||
|
//
|
|||
|
pEnum = new CEnumGUID;
|
|||
|
WsbAffirm( 0 != pEnum, E_OUTOFMEMORY );
|
|||
|
|
|||
|
//
|
|||
|
// Initialize it to copy the current node interface pointers
|
|||
|
//
|
|||
|
WsbAffirmHr( pEnum->FinalConstruct() );
|
|||
|
WsbAffirmHr( pEnum->Init( &m_pObjectIdArray[0], &m_pObjectIdArray[m_Count], NULL, AtlFlagCopy ) );
|
|||
|
WsbAffirmHr( pEnum->QueryInterface( IID_IEnumGUID, (void**)ppEnum ) );
|
|||
|
|
|||
|
} WsbCatchAndDo( hr,
|
|||
|
|
|||
|
if( pEnum ) delete pEnum;
|
|||
|
|
|||
|
);
|
|||
|
|
|||
|
WsbTraceOut( L"CMsDataObject::GetObjectIdEnumerator", L"hr = <%ls>, *ppEnum = <%ls>", WsbHrAsString( hr ), WsbPtrToPtrAsString( (void**)ppEnum ) );
|
|||
|
return( hr );
|
|||
|
}
|