windows-nt/Source/XPSP1/NT/shell/ext/dsui/dsquery/dataobj.cpp
2020-09-26 16:20:57 +08:00

373 lines
10 KiB
C++

#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);
}