|
|
#include "pch.h"
#include "stddef.h"
#pragma hdrstop
// free a DSA
int _DestroyCB(LPVOID pItem, LPVOID pData) { DATAOBJECTITEM *pdoi = (DATAOBJECTITEM*)pItem; LocalFreeStringW(&pdoi->pszPath); LocalFreeStringW(&pdoi->pszObjectClass); return 1; }
STDAPI_(void) FreeDataObjectDSA(HDSA hdsaObjects) { DSA_DestroyCallback(hdsaObjects, _DestroyCB, NULL); }
// IDataObject stuff
CLIPFORMAT g_cfDsObjectNames = 0;
typedef struct { UINT cfFormat; STGMEDIUM medium; } OTHERFMT;
class CDataObject : public IDataObject { public: CDataObject(HDSA hdsaObjects, BOOL fAdmin); ~CDataObject();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)();
// IDataObject
STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium); STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) { return E_NOTIMPL; } STDMETHODIMP QueryGetData(FORMATETC *pformatetc); STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) { return DATA_S_SAMEFORMATETC; } STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease); STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) { return E_NOTIMPL; } STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) { return OLE_E_ADVISENOTSUPPORTED; } STDMETHODIMP DUnadvise(DWORD dwConnection) { return OLE_E_ADVISENOTSUPPORTED; } STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) { return OLE_E_ADVISENOTSUPPORTED; }
private: LONG _cRef;
BOOL _fAdmin; HDSA _hdsaObjects; // array of the objects
HDSA _hdsaOtherFmt;
static INT s_OtherFmtDestroyCB(LPVOID pVoid, LPVOID pData);
void _RegisterClipFormats(void); HRESULT _GetDsObjectNames(FORMATETC* pFmt, STGMEDIUM* pMedium); };
STDAPI CDataObject_CreateInstance(HDSA dsaObjects, BOOL fAdmin, REFIID riid, void **ppv) { CDataObject *pdo = new CDataObject(dsaObjects, fAdmin); if (!pdo) return E_OUTOFMEMORY;
HRESULT hr = pdo->QueryInterface(riid, ppv); pdo->Release(); return hr; }
// IDataObject implementation
void CDataObject::_RegisterClipFormats(void) { if (!g_cfDsObjectNames) g_cfDsObjectNames = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES); }
CDataObject::CDataObject(HDSA dsaObjects, BOOL fAdmin) : _hdsaObjects(dsaObjects), _fAdmin(fAdmin), _cRef(1) { DllAddRef(); _RegisterClipFormats(); // ensure our private formats are registered
}
// destruction
INT CDataObject::s_OtherFmtDestroyCB(LPVOID pVoid, LPVOID pData) { OTHERFMT *pOtherFmt = (OTHERFMT*)pVoid; ReleaseStgMedium(&pOtherFmt->medium); return 1; }
CDataObject::~CDataObject() { FreeDataObjectDSA(_hdsaObjects);
if ( _hdsaOtherFmt ) DSA_DestroyCallback(_hdsaOtherFmt, s_OtherFmtDestroyCB, NULL);
DllRelease(); }
// QI handling
ULONG CDataObject::AddRef() { return InterlockedIncrement(&_cRef); }
ULONG CDataObject::Release() { if (InterlockedDecrement(&_cRef)) return _cRef;
delete this; return 0; }
HRESULT CDataObject::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CDataObject, IDataObject), // IID_IDataObject
{0, 0 }, }; return QISearch(this, qit, riid, ppv); }
// fetch the object names from the IDataObject
HRESULT CDataObject::_GetDsObjectNames(FORMATETC* pFmt, STGMEDIUM* pMedium) { IDsDisplaySpecifier *pdds; HRESULT hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&pdds); if (SUCCEEDED(hr)) { int count = DSA_GetItemCount(_hdsaObjects); int i;
// lets walk the array of items trying to determine which items
// are to be returned to the caller.
DWORD cbStruct = SIZEOF(DSOBJECTNAMES); DWORD offset = SIZEOF(DSOBJECTNAMES);
for (i = 0 ; i < count; i++) { DATAOBJECTITEM* pdoi = (DATAOBJECTITEM*)DSA_GetItemPtr(_hdsaObjects, i);
// string offset is offset by the number of structures
offset += SIZEOF(DSOBJECT);
// adjust the size of the total structure
cbStruct += SIZEOF(DSOBJECT); cbStruct += StringByteSizeW(pdoi->pszPath); cbStruct += StringByteSizeW(pdoi->pszObjectClass); }
// we have walked the structure, we know the size so lets return
// the structure to the caller.
DSOBJECTNAMES *pDsObjectNames; hr = AllocStorageMedium(pFmt, pMedium, cbStruct, (LPVOID*)&pDsObjectNames); if (SUCCEEDED(hr)) { pDsObjectNames->clsidNamespace = CLSID_MicrosoftDS; pDsObjectNames->cItems = count;
for (i = 0 ; i < count; i++) { DATAOBJECTITEM* pdoi = (DATAOBJECTITEM*)DSA_GetItemPtr(_hdsaObjects, i);
// is this class a conatiner, if so then lets return that to the caller
if (pdoi->fIsContainer) pDsObjectNames->aObjects[i].dwFlags |= DSOBJECT_ISCONTAINER;
if (_fAdmin) pDsObjectNames->aObjects[i].dwProviderFlags = DSPROVIDER_ADVANCED;
// copy the strings to the buffer
pDsObjectNames->aObjects[i].offsetName = offset; StringByteCopyW(pDsObjectNames, offset, pdoi->pszPath); offset += StringByteSizeW(pdoi->pszPath);
pDsObjectNames->aObjects[i].offsetClass = offset; StringByteCopyW(pDsObjectNames, offset, pdoi->pszObjectClass); offset += StringByteSizeW(pdoi->pszObjectClass); }
if ( FAILED(hr) ) ReleaseStgMedium(pMedium); }
pdds->Release(); } return hr; }
// IDataObject methods
STDMETHODIMP CDataObject::GetData(FORMATETC* pFmt, STGMEDIUM* pMedium) { int i; HRESULT hr = S_OK;
TraceEnter(TRACE_DATAOBJ, "CDataObject::GetData");
if ( !pFmt || !pMedium ) ExitGracefully(hr, E_INVALIDARG, "Bad arguments to GetData");
if ( pFmt->cfFormat == g_cfDsObjectNames ) { hr = _GetDsObjectNames(pFmt, pMedium); FailGracefully(hr, "Failed when build CF_DSOBJECTNAMES"); } else { hr = DV_E_FORMATETC; // failed
for ( i = 0 ; _hdsaOtherFmt && (i < DSA_GetItemCount(_hdsaOtherFmt)); i++ ) { OTHERFMT *pOtherFmt = (OTHERFMT*)DSA_GetItemPtr(_hdsaOtherFmt, i); TraceAssert(pOtherFmt);
if ( pOtherFmt->cfFormat == pFmt->cfFormat ) { hr = CopyStorageMedium(pFmt, pMedium, &pOtherFmt->medium); FailGracefully(hr, "Failed to copy the storage medium"); } } }
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDataObject::QueryGetData(FORMATETC* pFmt) { HRESULT hr; INT i; BOOL fSupported = FALSE;
TraceEnter(TRACE_DATAOBJ, "CDataObject::QueryGetData");
// check the valid clipboard formats either the static list, or the
// DSA which contains the ones we have been set with.
if (pFmt->cfFormat == g_cfDsObjectNames) { fSupported = TRUE; } else { for ( i = 0 ; !fSupported && _hdsaOtherFmt && (i < DSA_GetItemCount(_hdsaOtherFmt)) ; i++ ) { OTHERFMT *pOtherFmt = (OTHERFMT*)DSA_GetItemPtr(_hdsaOtherFmt, i); TraceAssert(pOtherFmt);
if ( pOtherFmt->cfFormat == pFmt->cfFormat ) { TraceMsg("Format is supported (set via ::SetData"); fSupported = TRUE; } } }
if ( !fSupported ) ExitGracefully(hr, DV_E_FORMATETC, "Bad format passed to QueryGetData");
// format looks good, lets check the other parameters
if ( !( pFmt->tymed & TYMED_HGLOBAL ) ) ExitGracefully(hr, E_INVALIDARG, "Non HGLOBAL StgMedium requested");
if ( ( pFmt->ptd ) || !( pFmt->dwAspect & DVASPECT_CONTENT) || !( pFmt->lindex == -1 ) ) ExitGracefully(hr, E_INVALIDARG, "Bad format requested");
hr = S_OK; // successs
exit_gracefully:
TraceLeaveResult(hr); }
STDMETHODIMP CDataObject::SetData(FORMATETC* pFmt, STGMEDIUM* pMedium, BOOL fRelease) { HRESULT hr; INT i; OTHERFMT otherfmt = { 0 }; USES_CONVERSION;
TraceEnter(TRACE_DATAOBJ, "CDataObject::SetData");
// All the user to store data with our DataObject, however we are
// only interested in allowing them to this with particular clipboard formats
if ( fRelease && !( pFmt->tymed & TYMED_HGLOBAL ) ) ExitGracefully(hr, E_INVALIDARG, "fRelease == TRUE, but not a HGLOBAL allocation");
if ( !_hdsaOtherFmt ) { _hdsaOtherFmt = DSA_Create(SIZEOF(OTHERFMT), 4); TraceAssert(_hdsaOtherFmt);
if ( !_hdsaOtherFmt ) ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate the DSA for items"); }
// if there is another copy of this data in the IDataObject then lets discard it.
for ( i = 0 ; i < DSA_GetItemCount(_hdsaOtherFmt) ; i++ ) { OTHERFMT *pOtherFmt = (OTHERFMT*)DSA_GetItemPtr(_hdsaOtherFmt, i); TraceAssert(pOtherFmt);
if ( pOtherFmt->cfFormat == pFmt->cfFormat ) { Trace(TEXT("Discarding previous entry for this format at index %d"), i); ReleaseStgMedium(&pOtherFmt->medium); DSA_DeleteItem(_hdsaOtherFmt, i); break; } }
// now put a copy of the data passed to ::SetData into the DSA.
otherfmt.cfFormat = pFmt->cfFormat;
hr = CopyStorageMedium(pFmt, &otherfmt.medium, pMedium); FailGracefully(hr, "Failed to copy the STORAGEMEIDUM"); if ( -1 == DSA_AppendItem(_hdsaOtherFmt, &otherfmt) ) { ReleaseStgMedium(&otherfmt.medium); ExitGracefully(hr, E_OUTOFMEMORY, "Failed to add the data to the DSA"); }
hr = S_OK; // success
exit_gracefully:
TraceLeaveResult(hr); }
|