1502 lines
40 KiB
C++
1502 lines
40 KiB
C++
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: ido.cpp
|
|
//
|
|
// Contents: Special data object implementation to optimize drag/drop
|
|
//
|
|
// Classes: SSharedFormats
|
|
// CDragDataObject
|
|
// CDragEnum
|
|
//
|
|
// Functions: CreateDragDataObject
|
|
// CreateDragDataObject
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 ricksa Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <le2int.h>
|
|
#include <utils.h>
|
|
#include <dragopt.h>
|
|
|
|
// Format for name of shared memory
|
|
OLECHAR szSharedMemoryTemplate[] = OLESTR("DragDrop%lx");
|
|
|
|
// Maximum size of string for name of shared memory. This is the size of the
|
|
// template plus the maximum number of hex digits in a long.
|
|
const int DRAG_SM_NAME_MAX = sizeof(szSharedMemoryTemplate)
|
|
+ sizeof(DWORD) * 2;
|
|
|
|
// Useful function for getting an enumerator
|
|
HRESULT wGetEnumFormatEtc(
|
|
IDataObject *pDataObj,
|
|
DWORD dwDirection,
|
|
IEnumFORMATETC **ppIEnum);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Struct: SSharedFormats
|
|
//
|
|
// Purpose: Is used for accessing formats in shared memory
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 26-Sep-94 ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
struct SSharedFormats
|
|
{
|
|
DWORD _cFormats;
|
|
FORMATETC _FormatEtc[1];
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CDragDataObject
|
|
//
|
|
// Purpose: Server side data object for drag that creates enumerator
|
|
// for shared formats.
|
|
//
|
|
// Interface: QueryInterface
|
|
// AddRef
|
|
// Release
|
|
// GetData
|
|
// GetDataHere
|
|
// QueryGetData
|
|
// GetCanonicalFormatEtc
|
|
// SetData
|
|
// EnumFormatEtc
|
|
// DAdvise
|
|
// DUnadvise
|
|
// EnumDAdvise
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Notes: This class only exists for return the enumerator. For
|
|
// all other operations it will simply pass the operation on
|
|
// to the real data object.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
class CDragDataObject : public IDataObject, public CPrivAlloc
|
|
{
|
|
public:
|
|
CDragDataObject(
|
|
void *pvMarshaledDataObject,
|
|
DWORD dwSmId);
|
|
|
|
~CDragDataObject(void);
|
|
|
|
//
|
|
// IUnknown
|
|
//
|
|
STDMETHODIMP QueryInterface(
|
|
REFIID riid,
|
|
void **ppvObject);
|
|
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
//
|
|
// IDataObject
|
|
//
|
|
STDMETHODIMP GetData(
|
|
FORMATETC *pformatetcIn,
|
|
STGMEDIUM *pmedium);
|
|
|
|
STDMETHODIMP GetDataHere(
|
|
FORMATETC *pformatetc,
|
|
STGMEDIUM *pmedium);
|
|
|
|
STDMETHODIMP QueryGetData(
|
|
FORMATETC *pformatetc);
|
|
|
|
STDMETHODIMP GetCanonicalFormatEtc(
|
|
FORMATETC *pformatectIn,
|
|
FORMATETC *pformatetcOut);
|
|
|
|
STDMETHODIMP SetData(
|
|
FORMATETC *pformatetc,
|
|
STGMEDIUM *pmedium,
|
|
BOOL fRelease);
|
|
|
|
STDMETHODIMP EnumFormatEtc(
|
|
DWORD dwDirection,
|
|
IEnumFORMATETC **ppenumFormatEtc);
|
|
|
|
STDMETHODIMP DAdvise(
|
|
FORMATETC *pformatetc,
|
|
DWORD advf,
|
|
IAdviseSink *pAdvSink,
|
|
DWORD *pdwConnection);
|
|
|
|
STDMETHODIMP DUnadvise(DWORD dwConnection);
|
|
|
|
STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
|
|
|
|
private:
|
|
|
|
IDataObject * GetRealDataObjPtr(void);
|
|
|
|
ULONG _cRefs;
|
|
|
|
void * _pvMarshaledDataObject;
|
|
|
|
IDataObject * _pIDataObject;
|
|
|
|
DWORD _dwSmId;
|
|
};
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CDragEnum
|
|
//
|
|
// Purpose: Enumerator created above to enumerate shared formats.
|
|
//
|
|
// Interface: QueryInterface
|
|
// AddRef
|
|
// Release
|
|
// Next
|
|
// Skip
|
|
// Reset
|
|
// Clone
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Notes: This class only enumerates things from shared memory
|
|
// when the drag/drop operation was started.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
class CDragEnum : public IEnumFORMATETC, public CPrivAlloc
|
|
{
|
|
public:
|
|
|
|
//
|
|
// IUnknown
|
|
//
|
|
STDMETHODIMP QueryInterface(
|
|
REFIID riid,
|
|
void **ppvObject);
|
|
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
//
|
|
// IEnumFORMATETC
|
|
//
|
|
STDMETHODIMP Next(
|
|
ULONG celt,
|
|
FORMATETC *rgelt,
|
|
ULONG *pceltFetched);
|
|
|
|
STDMETHODIMP Skip(ULONG celt);
|
|
|
|
STDMETHODIMP Reset(void);
|
|
|
|
STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
|
|
|
|
private:
|
|
|
|
friend CDragDataObject;
|
|
|
|
// Used when unmarshaling
|
|
CDragEnum(DWORD dwSharedMemoryId, HRESULT& rhr);
|
|
|
|
// Used by Clone operation
|
|
CDragEnum(
|
|
HANDLE hSharedMemory,
|
|
DWORD _cOffset,
|
|
HRESULT& rhr);
|
|
|
|
~CDragEnum(void);
|
|
|
|
HRESULT MapSharedReadMemory(void);
|
|
|
|
DWORD _cRefs;
|
|
|
|
DWORD _cOffset;
|
|
|
|
SSharedFormats * _pSharedFormats;
|
|
|
|
DWORD _dwSharedMemoryId;
|
|
|
|
HANDLE _hSharedMemory;
|
|
};
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::CDragDataObject
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDragDataObject::CDragDataObject(void *pvMarshaledDataObject, DWORD dwSmId)
|
|
: _cRefs(1), _pvMarshaledDataObject(pvMarshaledDataObject), _dwSmId(dwSmId),
|
|
_pIDataObject(NULL)
|
|
{
|
|
// Header does all the work
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::~CDragDataObject
|
|
//
|
|
// Synopsis: Free any resources connected with this object
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDragDataObject::~CDragDataObject(void)
|
|
{
|
|
// Release held pointer since we no longer need it.
|
|
if (_pIDataObject)
|
|
{
|
|
_pIDataObject->Release();
|
|
}
|
|
|
|
// this memory was allocated in RemPrivDragDrop, getif.cxx
|
|
if( _pvMarshaledDataObject )
|
|
{
|
|
PrivMemFree(_pvMarshaledDataObject);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::GetRealDataObjPtr
|
|
//
|
|
// Synopsis: Get the pointer to the real data object from the client
|
|
//
|
|
// Returns: NULL - could not unmarshal drag source's data object
|
|
// ~NULL - pointer to drag source's data object
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
IDataObject *CDragDataObject::GetRealDataObjPtr(void)
|
|
{
|
|
if (_pIDataObject == NULL)
|
|
{
|
|
_pIDataObject = UnmarshalDragDataObject(_pvMarshaledDataObject);
|
|
|
|
LEERROR(!_pIDataObject, "Unable to unmarshal dnd data object");
|
|
}
|
|
|
|
return _pIDataObject;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::QueryInterface
|
|
//
|
|
// Synopsis: Get new interface
|
|
//
|
|
// Arguments: [riid] - interface id of requested interface
|
|
// [ppvObject] - where to put the new interface pointer
|
|
//
|
|
// Returns: NOERROR - interface was instantiated
|
|
// E_FAIL - could not unmarshal source's data object
|
|
// other - some error occurred.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::QueryInterface(
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
if(IsEqualIID(riid, IID_IDataObject))
|
|
{
|
|
*ppvObject = this;
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->QueryInterface(riid, ppvObject)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::AddRef
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Returns: Current reference count
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CDragDataObject::AddRef(void)
|
|
{
|
|
DDDebugOut((DEB_ITRACE, "ADDREF == %d\n", _cRefs + 1));
|
|
return ++_cRefs;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::Release
|
|
//
|
|
// Synopsis: Decrement reference count to the object
|
|
//
|
|
// Returns: Current reference count to the object
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CDragDataObject::Release(void)
|
|
{
|
|
ULONG cRefs = --_cRefs;
|
|
|
|
DDDebugOut((DEB_ITRACE, "RELEASE == %d\n", cRefs));
|
|
|
|
if (cRefs == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRefs;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::GetData
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [pformatetcIn] - format for requested data
|
|
// [pmedium] - storage medium
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::GetData(
|
|
FORMATETC *pformatetcIn,
|
|
STGMEDIUM *pmedium)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->GetData(pformatetcIn, pmedium)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::GetDataHere
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [pformatetc] - format for requested data
|
|
// [pmedium] - storage medium
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::GetDataHere(
|
|
FORMATETC *pformatetc,
|
|
STGMEDIUM *pmedium)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->GetDataHere(pformatetc, pmedium)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::QueryGetData
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [pformatetc] - format to verify
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::QueryGetData(FORMATETC *pformatetc)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->QueryGetData(pformatetc)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::GetCanonicalFormatEtc
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [pformatetcIn] - input format
|
|
// [pformatetcOut] - output format
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::GetCanonicalFormatEtc(
|
|
FORMATETC *pformatetcIn,
|
|
FORMATETC *pformatetcOut)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->GetCanonicalFormatEtc(pformatetcIn, pformatetcOut)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::SetData
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [pformatetc] - format for set
|
|
// [pmedium] - medium to use
|
|
// [fRelease] - who releases
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::SetData(
|
|
FORMATETC *pformatetc,
|
|
STGMEDIUM *pmedium,
|
|
BOOL fRelease)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->SetData(pformatetc, pmedium, fRelease)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::EnumFormatEtc
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [dwDirection] - direction of formats either set or get
|
|
// [ppenumFormatEtc] - where to put enumerator
|
|
//
|
|
// Returns: NOERROR - operation succeeded.
|
|
//
|
|
// Algorithm: If format enumerator requested is for a data get, the
|
|
// create our private enumerator object otherwise pass
|
|
// the request to the real data object.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: For the data set direction, we just use the data object of
|
|
// the drop source.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::EnumFormatEtc(
|
|
DWORD dwDirection,
|
|
IEnumFORMATETC **ppenumFormatEtc)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Create our enumerator
|
|
if (dwDirection == DATADIR_GET)
|
|
{
|
|
// In the data get case we use our overridden enumerator.
|
|
// This s/b the typical case with Drag and Drop.
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
CDragEnum *pDragEnum = new CDragEnum(_dwSmId, hr);
|
|
|
|
if (hr == NOERROR)
|
|
{
|
|
*ppenumFormatEtc = pDragEnum;
|
|
}
|
|
else
|
|
{
|
|
delete pDragEnum;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Call through to the real data object because this is the
|
|
// set case. In general, this won't happen during Drag and Drop.
|
|
hr = (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->EnumFormatEtc(dwDirection, ppenumFormatEtc)
|
|
: E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::DAdvise
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [pformatetc] - format to be advised on
|
|
// [advf] - type of advise
|
|
// [pAdvSink] - advise to notify
|
|
// [pdwConnection] - connection id for advise
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::DAdvise(
|
|
FORMATETC *pformatetc,
|
|
DWORD advf,
|
|
IAdviseSink *pAdvSink,
|
|
DWORD *pdwConnection)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->DAdvise(pformatetc, advf, pAdvSink, pdwConnection)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::DUnadvise
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [dwConnection] - connection id for advise
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::DUnadvise(DWORD dwConnection)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->DUnadvise(dwConnection)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragDataObject::EnumDAdvise
|
|
//
|
|
// Synopsis: Create server side object for drag
|
|
//
|
|
// Arguments: [ppenumAdvise] - where to put the enumerator
|
|
//
|
|
// Returns: NOERROR - operation was successful
|
|
// Other - operation failed
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note: This just forwards the operation to the source data object
|
|
// if possible.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
|
|
{
|
|
return (GetRealDataObjPtr() != NULL)
|
|
? _pIDataObject->EnumDAdvise(ppenumAdvise)
|
|
: E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::CDragEnum
|
|
//
|
|
// Synopsis: Create enumerator object from server data object
|
|
//
|
|
// Arguments: [dwSharedMemoryId] - shared memory id
|
|
// [rhr] - error result
|
|
//
|
|
// Algorithm: Initalize the object and then open the shared memory
|
|
// segment and then pass the rest of the work on to
|
|
// MapSharedMemory to get the memory mapped in.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDragEnum::CDragEnum(DWORD dwSharedMemoryId, HRESULT& rhr)
|
|
: _cRefs(1), _cOffset(0), _dwSharedMemoryId(dwSharedMemoryId),
|
|
_hSharedMemory(NULL), _pSharedFormats(NULL)
|
|
{
|
|
// Open the shared memory
|
|
OLECHAR szSharedMemoryName[DRAG_SM_NAME_MAX];
|
|
|
|
wsprintf(szSharedMemoryName, szSharedMemoryTemplate, dwSharedMemoryId);
|
|
|
|
// Create the shared memory object
|
|
_hSharedMemory = OpenFileMapping(FILE_MAP_READ, FALSE, szSharedMemoryName);
|
|
|
|
rhr = MapSharedReadMemory();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::CDragEnum
|
|
//
|
|
// Synopsis: Create enumerator for Clone operation
|
|
//
|
|
// Arguments: [hSharedMemory] - handle to shared memory for formats
|
|
// [cOffset] - current offset in the enumeration
|
|
// [rhr] - error result if any
|
|
//
|
|
// Algorithm: Initialize the object and then dupicate the input handle.
|
|
// Then pass the rest of the work on to MapSharedReadMemory
|
|
// to get the memory mapped in.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDragEnum::CDragEnum(HANDLE hSharedMemory, DWORD cOffset, HRESULT& rhr)
|
|
: _cRefs(1), _cOffset(cOffset), _dwSharedMemoryId(0), _hSharedMemory(NULL),
|
|
_pSharedFormats(NULL)
|
|
{
|
|
|
|
// Duplicate the handle
|
|
DuplicateHandle(GetCurrentProcess(), hSharedMemory,
|
|
GetCurrentProcess(), &_hSharedMemory, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
|
|
rhr = MapSharedReadMemory();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::~CDragEnum
|
|
//
|
|
// Synopsis: Free reference to memory for formats
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDragEnum::~CDragEnum(void)
|
|
{
|
|
// Free mapped memory if it got mapped.
|
|
if (_pSharedFormats != NULL)
|
|
{
|
|
UnmapViewOfFile(_pSharedFormats);
|
|
}
|
|
|
|
// Close file mapping if it got created.
|
|
if (_hSharedMemory != NULL)
|
|
{
|
|
CloseHandle(_hSharedMemory);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::MapSharedReadMemory
|
|
//
|
|
// Synopsis: Map in the shared memory containing the formats
|
|
//
|
|
// Returns: NOERROR - could map in memory or no formats available
|
|
//
|
|
// Algorithm: If we have a handle to the shared memory, then map the
|
|
// memory in.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDragEnum::MapSharedReadMemory(void)
|
|
{
|
|
if (_hSharedMemory != NULL)
|
|
{
|
|
// Map in the shared memory
|
|
_pSharedFormats = (SSharedFormats *) MapViewOfFile(_hSharedMemory,
|
|
FILE_MAP_READ, 0, 0, 0);
|
|
}
|
|
|
|
// It's OK to have a null shared memory handle (indicates that no
|
|
// formats were available. Not that if we're out of memory, returning
|
|
// NOERROR here is going to mask that condition. However, we'll
|
|
// fail soon enough anyway.
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::QueryInterface
|
|
//
|
|
// Synopsis: Return requested interface
|
|
//
|
|
// Arguments: [riid] - interface id for output interface
|
|
// [ppvObject] - where to put output interface pointer
|
|
//
|
|
// Returns: NOERROR - could return the interface requested
|
|
// E_NOINTERFACE - could not instantiate requested interface.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragEnum::QueryInterface(
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
// Assume error to avoid the implicit goto of an else clause.
|
|
HRESULT hr = E_NOINTERFACE;
|
|
|
|
// Our enumerator only knows about two interfaces.
|
|
if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumFORMATETC))
|
|
{
|
|
*ppvObject = this;
|
|
AddRef();
|
|
hr = NOERROR;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::AddRef
|
|
//
|
|
// Synopsis: Add a reference to the interface
|
|
//
|
|
// Returns: Current count of references
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CDragEnum::AddRef(void)
|
|
{
|
|
return ++_cRefs;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::Release
|
|
//
|
|
// Synopsis: Release a reference to the enumerator
|
|
//
|
|
// Returns: The current reference count
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CDragEnum::Release(void)
|
|
{
|
|
// Remember to copy reference count out because memory might go
|
|
// away on the release.
|
|
ULONG cRefs = --_cRefs;
|
|
|
|
if (cRefs == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRefs;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::Next
|
|
//
|
|
// Synopsis: Return an array of formats requested
|
|
//
|
|
// Arguments: [celt] - number requested to return
|
|
// [rgelt] - array to hold returned items
|
|
// [pceltFetched] - actual number returned.
|
|
//
|
|
// Returns: NOERROR - number requested returned
|
|
// S_FALSE - less than requested returned
|
|
// E_OUTOFMEMORY - could not allocate memory to hold data
|
|
//
|
|
// Algorithm: Validate the input parameters. Then calculate the number
|
|
// to return by taking the minimum of the items left to
|
|
// enumerate and the number of items requested. Then copy
|
|
// all the formatetc's from shared memory to the output
|
|
// buffer. Then for each formatetc that contains a pointer
|
|
// to a DVDEVICETARGET, allocate a new target buffer and
|
|
// then copy the DVDEVICETARGET from shared memory. There
|
|
// is a trick here where in the formatetc in shared memory
|
|
// the ptd field is really an offset from the beginning of
|
|
// shared memory rather than an actual pointer. This is so
|
|
// we don't have to depend on the base of the shared memory.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragEnum::Next(
|
|
ULONG celt,
|
|
FORMATETC *rgelt,
|
|
ULONG *pceltFetched)
|
|
{
|
|
if (celt == 0)
|
|
{
|
|
LEDebugOut((DEB_ERROR,
|
|
"CDragEnum::Next requested entries returned is invalid\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!IsValidPtrOut(rgelt, sizeof(FORMATETC) * celt))
|
|
{
|
|
LEDebugOut((DEB_ERROR,
|
|
"CDragEnum::Next array to return entries invalid\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (pceltFetched)
|
|
{
|
|
if (!IsValidPtrOut(pceltFetched, sizeof(*pceltFetched)))
|
|
{
|
|
LEDebugOut((DEB_ERROR,
|
|
"CDragEnum::Next count to return invalid\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
else if (celt != 1)
|
|
{
|
|
LEDebugOut((DEB_ERROR,
|
|
"CDragEnum::count requested != 1 & count fetched is NULL\n"));
|
|
return E_INVALIDARG;
|
|
|
|
}
|
|
|
|
// handle the case where we have no data
|
|
if( _pSharedFormats == NULL )
|
|
{
|
|
if( pceltFetched )
|
|
{
|
|
*pceltFetched = 0;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
// Calculate the maximum number that we can return
|
|
ULONG cToReturn = (_cOffset < _pSharedFormats->_cFormats)
|
|
? _pSharedFormats->_cFormats - _cOffset
|
|
: 0;
|
|
|
|
// Are we going to return any?
|
|
if (cToReturn != 0)
|
|
{
|
|
// If the number requested is less that the maximum number
|
|
// we can return, the we will return all requested/
|
|
if (celt < cToReturn)
|
|
{
|
|
cToReturn = celt;
|
|
}
|
|
|
|
// Copy the FormatEtcs
|
|
memcpy(&rgelt[0], &_pSharedFormats->_FormatEtc[_cOffset],
|
|
sizeof(FORMATETC) * cToReturn);
|
|
|
|
// Allocate and copy the DVTARGETDEVICE - a side effect of this
|
|
// loop is that our offset pointer gets updated to its value at
|
|
// the completion of the routine.
|
|
for (DWORD i = 0; i < cToReturn; i++, _cOffset++)
|
|
{
|
|
if (_pSharedFormats->_FormatEtc[_cOffset].ptd != NULL)
|
|
{
|
|
// Create a pointer to the device target - Remember when
|
|
// we created the shared memory block we overroad the ptd
|
|
// field of the FORMATETC so that it is now the offset
|
|
// from the beginning of the shared memory. We reverse
|
|
// that here so we can copy the data for the consumer.
|
|
DVTARGETDEVICE *pdvtarget = (DVTARGETDEVICE *)
|
|
((BYTE *) _pSharedFormats
|
|
+ (DWORD) _pSharedFormats->_FormatEtc[_cOffset].ptd);
|
|
|
|
// Allocate a new DVTARGETDEVICE
|
|
DVTARGETDEVICE *pdvtargetNew = (DVTARGETDEVICE *)
|
|
CoTaskMemAlloc(pdvtarget->tdSize);
|
|
|
|
// Did the memory allocation succeed?
|
|
if (pdvtargetNew == NULL)
|
|
{
|
|
// NO! - so clean up. First we free any device targets
|
|
// that we might have allocated.
|
|
for (DWORD j = 0; j < i; j++)
|
|
{
|
|
if (rgelt[j].ptd != NULL)
|
|
{
|
|
CoTaskMemFree(rgelt[j].ptd);
|
|
}
|
|
}
|
|
|
|
// Then we restore the offset to its initial state
|
|
_cOffset -= i;
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Copy the old targetDevice to the new one
|
|
memcpy(pdvtargetNew, pdvtarget, pdvtarget->tdSize);
|
|
|
|
// Update output FORMATETC pointer
|
|
rgelt[i].ptd = pdvtargetNew;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pceltFetched)
|
|
{
|
|
*pceltFetched = cToReturn;
|
|
}
|
|
|
|
return (cToReturn == celt) ? NOERROR : S_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::Skip
|
|
//
|
|
// Synopsis: Skip the input number of entries in the list
|
|
//
|
|
// Arguments: [celt] - count of entries to skip
|
|
//
|
|
// Returns: NOERROR - number could be skipped
|
|
// S_FALSE - skip greater than the end of the list
|
|
//
|
|
// Algorithm: Bump offset by count input. If this is greater than or
|
|
// equal to the number of formats, return S_FALSE otherwise
|
|
// return NOERROR.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragEnum::Skip(ULONG celt)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
_cOffset += celt;
|
|
|
|
if( _pSharedFormats == NULL )
|
|
{
|
|
_cOffset = 0;
|
|
hr = S_FALSE;
|
|
}
|
|
else if (_cOffset >= _pSharedFormats->_cFormats)
|
|
{
|
|
_cOffset = _pSharedFormats->_cFormats;
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::Reset
|
|
//
|
|
// Synopsis: Reset enumeration index to the beginning
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Algorithm: Just set our offset back to 0.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragEnum::Reset(void)
|
|
{
|
|
_cOffset = 0;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDragEnum::Clone
|
|
//
|
|
// Synopsis: Create a duplicate copy of this enumeration.
|
|
//
|
|
// Arguments: [ppenum] - where to return the enumerator
|
|
//
|
|
// Returns: S_OK - could create the enumerator copy
|
|
// E_OUTOFMEMORY - could not create the copy
|
|
//
|
|
// Algorithm: Call constructor for enumerator that dups the handle to the
|
|
// shared memory.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CDragEnum::Clone(IEnumFORMATETC **ppenum)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
CDragEnum *pDragEnum = new CDragEnum(_hSharedMemory, _cOffset, hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CreateDragDataObject
|
|
//
|
|
// Synopsis: Create the server side data object for format enumeration
|
|
//
|
|
// Arguments: [pvMarshaledDataObject] - marshaled real data object buffer
|
|
// [dwSmId] - id for the shared memory
|
|
// [ppIDataObject] - output data object.
|
|
//
|
|
// Returns: NOERROR - could create the object
|
|
// E_OUTOFMEMORY - could not create the object
|
|
//
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CreateDragDataObject(
|
|
void *pvMarshaledDataObject,
|
|
DWORD dwSmId,
|
|
IDataObject **ppIDataObject)
|
|
{
|
|
CDragDataObject *pDragDataObject =
|
|
new CDragDataObject(pvMarshaledDataObject, dwSmId);
|
|
|
|
if (pDragDataObject != NULL)
|
|
{
|
|
*ppIDataObject = pDragDataObject;
|
|
}
|
|
|
|
// The only thing that can fail here is the memory allocation of
|
|
// CDragDataObject thus there are only two error returns.
|
|
return (pDragDataObject != NULL) ? NOERROR : E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CreateDragDataObject
|
|
//
|
|
// Synopsis: Put the data formats for the data object in shared memory.
|
|
//
|
|
// Arguments: [pIDataObject] - data object to use for formats.
|
|
//
|
|
// Returns: NULL - could not create enumerator
|
|
// ~NULL - handle to shared memory
|
|
//
|
|
// Algorithm: First calculate the size of the required memory by enumerating
|
|
// the formats. Then allocate the memory and map it into the
|
|
// process. Then enumerate the formats again placing them in
|
|
// the shared memory. Finally, map the memory out of the
|
|
// process and return the handle the file mapping to the
|
|
// caller.
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 30-Sep-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HANDLE CreateSharedDragFormats(IDataObject *pIDataObject)
|
|
{
|
|
|
|
// Handle to the shared memory for formats
|
|
HANDLE hSharedMemory = NULL;
|
|
|
|
// Pointer to share memory
|
|
SSharedFormats *pSharedFormats = NULL;
|
|
|
|
// Size required for the shared memory
|
|
DWORD dwSize = 0;
|
|
|
|
// Count of FORMATETCs contained in the enumerator
|
|
DWORD cFormatEtc = 0;
|
|
|
|
// Buffer for name of shared memory for enumerator
|
|
OLECHAR szSharedMemoryName[DRAG_SM_NAME_MAX];
|
|
|
|
// Work pointer to shared memory for storing FORMATETCs from the enumerator.
|
|
FORMATETC *pFormatEtc;
|
|
|
|
// Work ptr to shared memory for storing DVTARGETDEVICEs from enumerator.
|
|
BYTE *pbDvTarget = NULL;
|
|
|
|
//
|
|
// Calculate the size of the formats
|
|
//
|
|
|
|
// Get the format enumerator
|
|
IEnumFORMATETC *penum = NULL;
|
|
HRESULT hr = wGetEnumFormatEtc(pIDataObject, DATADIR_GET, &penum);
|
|
FORMATETC FormatEtc;
|
|
|
|
if( hr != NOERROR )
|
|
{
|
|
// not all apps support enumerators (yahoo). Also, we may
|
|
// have run out of memory or encountered some other error.
|
|
|
|
DDDebugOut((DEB_WARN, "WARNING: Failed to get formatetc enumerator"
|
|
", error code (%lx)", hr));
|
|
goto exitRtn;
|
|
}
|
|
|
|
// Enumerate the data one at a time because this is a local operation
|
|
// and it make the code simpler.
|
|
while ((hr = penum->Next(1, &FormatEtc, NULL)) == S_OK)
|
|
{
|
|
// Bump the entry count
|
|
cFormatEtc++;
|
|
|
|
// Bump the size by the size of another FORMATETC.
|
|
dwSize += sizeof(FORMATETC);
|
|
|
|
// Is there a device target associated with the FORMATETC?
|
|
if (FormatEtc.ptd != NULL)
|
|
{
|
|
// Bump the size required by the size of the target device
|
|
dwSize += FormatEtc.ptd->tdSize;
|
|
|
|
// Free the target device
|
|
CoTaskMemFree(FormatEtc.ptd);
|
|
}
|
|
}
|
|
|
|
// HRESULT s/b S_FALSE at the end of the enumeration.
|
|
if (hr != S_FALSE)
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// the enumerator may have been empty
|
|
|
|
if( dwSize == 0 )
|
|
{
|
|
DDDebugOut((DEB_WARN, "WARNING: Empty formatetc enumerator"));
|
|
goto exitRtn;
|
|
}
|
|
|
|
|
|
dwSize += sizeof(SSharedFormats); // add space for _cFormats and one exter FORMATETC for FALSE in enumerator.
|
|
|
|
//
|
|
// Create shared memory for the type enumeration
|
|
//
|
|
|
|
// Build name of shared memory - make it unique by using the thread id.
|
|
wsprintf(szSharedMemoryName, szSharedMemoryTemplate, GetCurrentThreadId());
|
|
|
|
// Create the shared memory object
|
|
hSharedMemory = CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL,
|
|
PAGE_READWRITE, 0, dwSize, szSharedMemoryName);
|
|
|
|
// Did the file mapping get created?
|
|
if (hSharedMemory == NULL)
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Map in the memory
|
|
pSharedFormats = (SSharedFormats *) MapViewOfFile(
|
|
hSharedMemory,
|
|
FILE_MAP_WRITE,
|
|
0, // High-order 32 bits of file offset
|
|
0, // Low-order 32 bits of file offset
|
|
0); // Number of bytes to map; 0 means all.
|
|
|
|
// Could we map the memory?
|
|
if (pSharedFormats == NULL)
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// We can initialize the size of the array now.
|
|
pSharedFormats->_cFormats = cFormatEtc;
|
|
|
|
//
|
|
// Copy the formats into the shared memory
|
|
//
|
|
|
|
// Get back to the start of the enumeration
|
|
penum->Reset();
|
|
|
|
// This is the pointer to where we will copy the data from the
|
|
// enumeration.
|
|
pFormatEtc = &pSharedFormats->_FormatEtc[0];
|
|
|
|
// put DvTarget past last valid FormatEtc + 1 to handle S_FALSE enumerator case.
|
|
|
|
pbDvTarget = (BYTE *) (&pSharedFormats->_FormatEtc[cFormatEtc + 1]);
|
|
|
|
// Loop loading the formats into the shared memory.
|
|
while (penum->Next(1, pFormatEtc, NULL) != S_FALSE)
|
|
{
|
|
// Is there a DVTARGETDEVICE?
|
|
if (pFormatEtc->ptd != NULL)
|
|
{
|
|
|
|
// Copy the device target data
|
|
memcpy(pbDvTarget,pFormatEtc->ptd,(pFormatEtc->ptd)->tdSize);
|
|
|
|
// Free the target device data
|
|
CoTaskMemFree(pFormatEtc->ptd);
|
|
|
|
// NOTE: For this shared memory structure, we override the
|
|
// FORMATETC field so that it is that offset to the DVTARGETDEVICE
|
|
// from the beginning of the shared memory rather than a direct
|
|
// pointer to the structure. This is because we can't guarantee
|
|
// the base of shared memory in different processes.
|
|
|
|
pFormatEtc->ptd = (DVTARGETDEVICE *)
|
|
(pbDvTarget - (BYTE *) pSharedFormats);
|
|
|
|
// Bump pointer of where to copy target to next available
|
|
// byte for copy.
|
|
pbDvTarget += ((DVTARGETDEVICE *) pbDvTarget)->tdSize;
|
|
|
|
Assert(dwSize >= (DWORD) (pbDvTarget - (BYTE *) pSharedFormats));
|
|
|
|
}
|
|
|
|
// Bug#18669 - if dwAspect was set to NULL the 16 bit dlls would
|
|
// set it to content.
|
|
if ( (NULL == pFormatEtc->dwAspect) && IsWOWThread() )
|
|
{
|
|
pFormatEtc->dwAspect = DVASPECT_CONTENT;
|
|
pFormatEtc->lindex = -1; // CorelDraw also puts up a lindex of 0
|
|
}
|
|
|
|
// Bump the pointer in the table of FORMATETCs to the next slot
|
|
pFormatEtc++;
|
|
}
|
|
|
|
Assert( dwSize >= (DWORD) ( (BYTE *) pFormatEtc - (BYTE *) pSharedFormats));
|
|
Assert( dwSize >= (DWORD) ( (BYTE *) pbDvTarget - (BYTE *) pSharedFormats));
|
|
|
|
|
|
// Successful enumeration always ends with S_FALSE.
|
|
if (hr == S_FALSE)
|
|
{
|
|
goto exitRtn;
|
|
}
|
|
|
|
errRtn:
|
|
|
|
if (hSharedMemory != NULL)
|
|
{
|
|
CloseHandle(hSharedMemory);
|
|
hSharedMemory = NULL;
|
|
}
|
|
|
|
exitRtn:
|
|
|
|
if( penum )
|
|
{
|
|
// HACK ALERT: Do not release the enumerator if the calling application
|
|
// was Interleaf 6.0, otherwise they will fault in the release call.
|
|
if (!IsTaskName(L"ILEAF6.EXE"))
|
|
{
|
|
penum->Release();
|
|
}
|
|
}
|
|
|
|
if (pSharedFormats != NULL)
|
|
{
|
|
// Only remote clients will use this memory so we unmap it
|
|
// out of our address space.
|
|
UnmapViewOfFile(pSharedFormats);
|
|
}
|
|
|
|
return hSharedMemory;
|
|
}
|