mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
803 lines
23 KiB
803 lines
23 KiB
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#include "dsdata.h"
|
|
|
|
UINT g_acfDS_IDLData[ICF_DSMAX] = { CF_DSHDROP, 0 };
|
|
|
|
#define CFSTR_DS_OURHDROP TEXT("DS Disguised HDROP")
|
|
#define CFSTR_DS_SHELLIDLIST TEXT("DS Shell IDList Array")
|
|
|
|
const TCHAR c_szDS_HDrop[] = CFSTR_DS_OURHDROP;
|
|
const TCHAR c_szDS_ShellIDList[] = CFSTR_DS_SHELLIDLIST;
|
|
const TCHAR c_szDS_ShellIDListOffset[] = CFSTR_SHELLIDLISTOFFSET;
|
|
|
|
void WINAPI DS_IDLData_InitializeClipboardFormats(void)
|
|
{
|
|
if (g_cfDS_HIDA == 0)
|
|
{
|
|
g_cfDS_HDROP = RegisterClipboardFormat(c_szDS_HDrop);
|
|
g_cfDS_HIDA = RegisterClipboardFormat(c_szDS_ShellIDList);
|
|
g_cfDS_OFFSETS = RegisterClipboardFormat(c_szDS_ShellIDListOffset);
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// CDS_IDLData : Class definition (for subclass)
|
|
//===========================================================================
|
|
|
|
#define MAX_FORMATS ICF_DSMAX
|
|
|
|
typedef struct _DS_IDLData // idt
|
|
{
|
|
IDataObject dtobj;
|
|
UINT cRef;
|
|
|
|
LPDATAOBJECT _pdtInner;
|
|
BOOL _fEnumFormatCalled; // TRUE once called.
|
|
|
|
FORMATETC fmte[MAX_FORMATS];
|
|
STGMEDIUM medium[MAX_FORMATS];
|
|
BOOL _fhDrop_Enabled;
|
|
} CDS_IDLData;
|
|
|
|
|
|
//===========================================================================
|
|
// CDS_IDLData : Vtable
|
|
//===========================================================================
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
IDataObjectVtbl c_CDS_IDLDataVtbl = {
|
|
CDS_IDLData_QueryInterface,
|
|
CDS_IDLData_AddRef,
|
|
CDS_IDLData_Release,
|
|
CDS_IDLData_GetData,
|
|
CDS_IDLData_GetDataHere,
|
|
CDS_IDLData_QueryGetData,
|
|
CDS_IDLData_GetCanonicalFormatEtc,
|
|
CDS_IDLData_SetData,
|
|
CDS_IDLData_EnumFormatEtc,
|
|
CDS_IDLData_Advise,
|
|
CDS_IDLData_Unadvise,
|
|
CDS_IDLData_EnumAdvise
|
|
};
|
|
#pragma data_seg()
|
|
|
|
//
|
|
// We can't just compare the Vtable pointer, because we have subclasses.
|
|
//
|
|
#define ISIDLDATA(pdtobj) (pdtobj->lpVtbl->Release == CDS_IDLData_Release)
|
|
|
|
//
|
|
// Create an instance of CDS_IDLData with specified Vtable pointer.
|
|
//
|
|
HRESULT CDS_IDLData_CreateInstance(IDataObjectVtbl *lpVtbl, IDataObject **ppdtobj, IDataObject *pdtInner)
|
|
{
|
|
CDS_IDLData *pidt = (void*)LocalAlloc(LPTR, SIZEOF(CDS_IDLData));
|
|
if (pidt)
|
|
{
|
|
pidt->dtobj.lpVtbl = lpVtbl ? lpVtbl : &c_CDS_IDLDataVtbl;
|
|
pidt->cRef = 1;
|
|
pidt->_pdtInner = pdtInner;
|
|
if (pdtInner) {
|
|
pdtInner->lpVtbl->AddRef(pdtInner);
|
|
}
|
|
*ppdtobj = &pidt->dtobj;
|
|
pidt->_fhDrop_Enabled = FALSE; // used to support std prop sheet itf
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppdtobj = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
// CDS_IDLData : Members
|
|
//===========================================================================
|
|
//
|
|
// Member: CDS_IDLData::QueryInterface
|
|
//
|
|
STDMETHODIMP CDS_IDLData_QueryInterface(IDataObject * pdtobj, REFIID riid, LPVOID *ppvObj)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
|
|
if (IsEqualIID(riid, &IID_IDataObject) || IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObj = this;
|
|
this->cRef++;
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::AddRef
|
|
//
|
|
STDMETHODIMP_(ULONG) CDS_IDLData_AddRef(IDataObject *pdtobj)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
|
|
this->cRef++;
|
|
return this->cRef;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::Release
|
|
//
|
|
STDMETHODIMP_(ULONG) CDS_IDLData_Release(IDataObject *pdtobj)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
int i;
|
|
|
|
if (InterlockedDecrement(&this->cRef))
|
|
return this->cRef;
|
|
|
|
for (i = 0; i < MAX_FORMATS; i++)
|
|
{
|
|
if (this->medium[i].hGlobal)
|
|
SHReleaseStgMedium(&this->medium[i]);
|
|
}
|
|
|
|
if (this->_pdtInner)
|
|
this->_pdtInner->lpVtbl->Release(this->_pdtInner);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::GetData
|
|
//
|
|
STDMETHODIMP CDS_IDLData_GetData(IDataObject * pdtobj, LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
HRESULT hres = E_INVALIDARG;
|
|
if ((pformatetcIn->cfFormat == g_cfDS_HDROP && (pformatetcIn->tymed & TYMED_HGLOBAL)) ||
|
|
(pformatetcIn->cfFormat == CF_HDROP && (pformatetcIn->tymed & TYMED_HGLOBAL) &&
|
|
(this->_fhDrop_Enabled)))
|
|
{
|
|
hres = CDS_IDLData_GetHDrop(pdtobj, pmedium,
|
|
pformatetcIn->dwAspect == DVASPECT_SHORTNAME);
|
|
}
|
|
else
|
|
{
|
|
|
|
int i;
|
|
|
|
pmedium->hGlobal = NULL;
|
|
pmedium->pUnkForRelease = NULL;
|
|
|
|
// BUGBUG (Davepl) Does this need to keep looping after it finds the right one?
|
|
|
|
for (i = 0; i < MAX_FORMATS; i++)
|
|
{
|
|
if ((this->fmte[i].cfFormat == pformatetcIn->cfFormat) &&
|
|
(this->fmte[i].tymed & pformatetcIn->tymed))
|
|
{
|
|
*pmedium = this->medium[i];
|
|
|
|
if ((pmedium->tymed == TYMED_HGLOBAL) &&
|
|
(pmedium->hGlobal == NULL))
|
|
{
|
|
// might be render on demand clipboard format
|
|
|
|
}
|
|
|
|
if (pmedium->hGlobal)
|
|
{
|
|
// Indicate that the caller should not release hmem.
|
|
this->cRef++;
|
|
pmedium->pUnkForRelease = (IUnknown*)&this->dtobj;
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hres==E_INVALIDARG && this->_pdtInner) {
|
|
hres = this->_pdtInner->lpVtbl->GetData(this->_pdtInner, pformatetcIn, pmedium);
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::GetDataHere
|
|
//
|
|
STDMETHODIMP CDS_IDLData_GetDataHere(IDataObject * pdtobj, LPFORMATETC pformatetc, LPSTGMEDIUM pmedium )
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
HRESULT hres = E_NOTIMPL;
|
|
if (this->_pdtInner) {
|
|
hres = this->_pdtInner->lpVtbl->GetDataHere(this->_pdtInner, pformatetc, pmedium);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::QueryGetData
|
|
//
|
|
STDMETHODIMP CDS_IDLData_QueryGetData(IDataObject * pdtobj, LPFORMATETC pformatetcIn)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
HRESULT hres;
|
|
int i;
|
|
if ((pformatetcIn->cfFormat == g_cfDS_HDROP) &&
|
|
(pformatetcIn->tymed & TYMED_HGLOBAL))
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < MAX_FORMATS; i++)
|
|
{
|
|
if ((this->fmte[i].cfFormat == pformatetcIn->cfFormat) &&
|
|
(this->fmte[i].tymed & pformatetcIn->tymed))
|
|
return S_OK;
|
|
}
|
|
|
|
hres = S_FALSE;
|
|
if (this->_pdtInner) {
|
|
hres = this->_pdtInner->lpVtbl->QueryGetData(this->_pdtInner, pformatetcIn);
|
|
}
|
|
return hres;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::GetCanonicalFormatEtc
|
|
//
|
|
STDMETHODIMP CDS_IDLData_GetCanonicalFormatEtc(IDataObject *pdtobj, LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
|
|
{
|
|
//
|
|
// This is the simplest implemtation. It means we always return
|
|
// the data in the format requested.
|
|
//
|
|
return DATA_S_SAMEFORMATETC;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::SetData
|
|
//
|
|
STDMETHODIMP CDS_IDLData_SetData(IDataObject *pdtobj, FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
HRESULT hres;
|
|
|
|
Assert(pformatetc->tymed == pmedium->tymed);
|
|
|
|
if (fRelease)
|
|
{
|
|
int i;
|
|
|
|
// first add it if that format is already present
|
|
// on a NULL medium (render on demand)
|
|
for (i = 0; i < MAX_FORMATS; i++)
|
|
{
|
|
if ((this->fmte[i].cfFormat == pformatetc->cfFormat) &&
|
|
(this->fmte[i].tymed == pformatetc->tymed))
|
|
{
|
|
//
|
|
// We are simply adding a format, ignore.
|
|
//
|
|
if (pmedium->hGlobal==NULL) {
|
|
return S_OK;
|
|
}
|
|
|
|
// if we are set twice on the same object
|
|
if (this->medium[i].hGlobal)
|
|
SHReleaseStgMedium(&this->medium[i]);
|
|
|
|
this->medium[i] = *pmedium;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// now look for a free slot
|
|
for (i = 0; i < MAX_FORMATS; i++)
|
|
{
|
|
if (this->fmte[i].cfFormat == 0)
|
|
{
|
|
// found a free slot
|
|
this->medium[i] = *pmedium;
|
|
this->fmte[i] = *pformatetc;
|
|
return S_OK;
|
|
}
|
|
}
|
|
// fixed size table
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
hres = E_INVALIDARG;
|
|
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::EnumFormatEtc
|
|
//
|
|
STDMETHODIMP CDS_IDLData_EnumFormatEtc(IDataObject *pdtobj, DWORD dwDirection, LPENUMFORMATETC *ppenumFormatEtc)
|
|
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
UINT cfmt;
|
|
|
|
//
|
|
// If this is the first time, build the format list by calling
|
|
// QueryGetData with each clipboard format.
|
|
//
|
|
if (!this->_fEnumFormatCalled)
|
|
{
|
|
UINT ifmt;
|
|
FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
STGMEDIUM medium = { TYMED_HGLOBAL, (HGLOBAL)NULL, (LPUNKNOWN)NULL };
|
|
for (ifmt = 0; ifmt < ICF_DSMAX; ifmt++)
|
|
{
|
|
fmte.cfFormat = g_acfDS_IDLData[ifmt];
|
|
if (pdtobj->lpVtbl->QueryGetData(pdtobj, &fmte) == S_OK) {
|
|
pdtobj->lpVtbl->SetData(pdtobj, &fmte, &medium, TRUE);
|
|
}
|
|
}
|
|
this->_fEnumFormatCalled = TRUE;
|
|
}
|
|
|
|
// Get the number of formatetc
|
|
for (cfmt = 0; cfmt < MAX_FORMATS; cfmt++)
|
|
{
|
|
if (this->fmte[cfmt].cfFormat == 0)
|
|
break;
|
|
}
|
|
|
|
return SHCreateStdEnumFmtEtcEx(cfmt, this->fmte, this->_pdtInner,
|
|
ppenumFormatEtc);
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::Advise
|
|
//
|
|
STDMETHODIMP CDS_IDLData_Advise(IDataObject *pdtobj, FORMATETC * pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection)
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::Unadvise
|
|
//
|
|
STDMETHODIMP CDS_IDLData_Unadvise(IDataObject *pdtobj, DWORD dwConnection)
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Member: CDS_IDLData::EnumAdvise
|
|
//
|
|
STDMETHODIMP CDS_IDLData_EnumAdvise(IDataObject *pdtobj, LPENUMSTATDATA *ppenumAdvise)
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
LPVOID DSDataObj_SaveShellData(IDataObject *pdtobj, BOOL fShared)
|
|
{
|
|
UINT fmts[2];
|
|
// UINT fmts[1];
|
|
|
|
DS_IDLData_InitializeClipboardFormats(); // init our registerd data formats
|
|
|
|
fmts[0] = g_cfDS_HIDA;
|
|
fmts[1] = g_cfOFFSETS;
|
|
|
|
return DataObj_SaveToMemory(pdtobj, ARRAYSIZE(fmts), fmts, fShared);
|
|
}
|
|
|
|
|
|
//
|
|
// marshal a set of clipboard formats into a memory block in the form of
|
|
//
|
|
|
|
typedef struct {
|
|
ULONG offVtbl;
|
|
UINT iNumFormats;
|
|
// UINT cfFormat
|
|
// UINT cbFormat
|
|
// BYTE data[]
|
|
// ...
|
|
} MEM_CRAP;
|
|
|
|
LPVOID DSDataObj_SaveToMemory(IDataObject *pdtobj, UINT cntFmt, UINT fmts[], BOOL fShared)
|
|
{
|
|
MEM_CRAP *pmem = NULL; // assume error
|
|
UINT cbDataSize = 0;
|
|
UINT iNumFormats = 0;
|
|
UINT i;
|
|
|
|
if (!ISIDLDATA(pdtobj))
|
|
return NULL;
|
|
|
|
for (i = 0; i < cntFmt; i++)
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = {fmts[i], NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (SUCCEEDED(pdtobj->lpVtbl->GetData(pdtobj, &fmte, &medium)))
|
|
{
|
|
cbDataSize += GlobalSize(medium.hGlobal);
|
|
iNumFormats++;
|
|
SHReleaseStgMedium(&medium);
|
|
}
|
|
}
|
|
|
|
if (cbDataSize)
|
|
{
|
|
UINT cbTotal = SIZEOF(MEM_CRAP) +
|
|
(iNumFormats * SIZEOF(UINT) * 2) + // cfFormat, cbFormat
|
|
cbDataSize;
|
|
|
|
pmem = fShared ? Alloc(cbTotal) : GlobalAlloc(GPTR, cbTotal);
|
|
if (pmem)
|
|
{
|
|
UNALIGNED UINT *pdata = (UNALIGNED UINT *)((LPBYTE)pmem + SIZEOF(MEM_CRAP));
|
|
|
|
pmem->iNumFormats = iNumFormats;
|
|
// ultra cool HACK....
|
|
pmem->offVtbl = (ULONG)pdtobj->lpVtbl - (ULONG)&c_CDS_IDLDataVtbl;
|
|
|
|
for (i = 0; i < cntFmt; i++)
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = {fmts[i], NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (SUCCEEDED(pdtobj->lpVtbl->GetData(pdtobj, &fmte, &medium)))
|
|
{
|
|
UINT cbData = GlobalSize(medium.hGlobal);
|
|
*pdata++ = fmts[i];
|
|
*pdata++ = cbData;
|
|
hmemcpy(pdata, (LPVOID)medium.hGlobal, cbData);
|
|
|
|
pdata = (UNALIGNED UINT *)((LPBYTE)pdata + cbData);
|
|
|
|
SHReleaseStgMedium(&medium);
|
|
|
|
Assert(((UINT)pdata - (UINT)pmem) <= cbTotal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pmem;
|
|
}
|
|
|
|
// This function creates an instance of CDS_IDLData from a block of memory
|
|
// which is created by CDS_IDLData_SaveToMemory.
|
|
//
|
|
HRESULT DSDataObj_CreateFromMemory(LPVOID pv, IDataObject **ppdtobj)
|
|
{
|
|
MEM_CRAP *pmem = pv;
|
|
HRESULT hres = CDS_IDLData_CreateInstance(
|
|
(IDataObjectVtbl *)((ULONG)&c_CDS_IDLDataVtbl + pmem->offVtbl),
|
|
ppdtobj, NULL);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
UINT i;
|
|
BOOL bSomethingWasAdded = FALSE;
|
|
UNALIGNED UINT *pdata = (UNALIGNED UINT *)((LPBYTE)pmem + SIZEOF(MEM_CRAP));
|
|
|
|
for (i = 0; i < pmem->iNumFormats; i++)
|
|
{
|
|
UINT cfFormat = *pdata++;
|
|
UINT cbData = *pdata++;
|
|
HGLOBAL hglobal = GlobalAlloc(GPTR, cbData);
|
|
if (hglobal)
|
|
{
|
|
CopyMemory(hglobal, pdata, cbData);
|
|
|
|
if (SUCCEEDED(DataObj_SetGlobal(*ppdtobj, cfFormat,
|
|
hglobal)))
|
|
bSomethingWasAdded = TRUE;
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("set data fiailed creating from global"));
|
|
GlobalFree(hglobal);
|
|
}
|
|
}
|
|
pdata = (UNALIGNED UINT *)((LPBYTE)pdata + cbData);
|
|
}
|
|
if (bSomethingWasAdded)
|
|
{
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
(*ppdtobj)->lpVtbl->Release(*ppdtobj);
|
|
*ppdtobj = NULL;
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// Create an instance of CDS_IDLData with specified Vtable pointer.
|
|
//
|
|
HRESULT CDS_IDLData_CreateFromIDArray3(IDataObjectVtbl *lpVtbl,
|
|
LPCITEMIDLIST pidlFolder,
|
|
UINT cidl, LPCITEMIDLIST apidl[],
|
|
LPDATAOBJECT pdtInner,
|
|
IDataObject **ppdtobj)
|
|
{
|
|
HRESULT hres = CDS_IDLData_CreateInstance(lpVtbl, ppdtobj, pdtInner);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// allow empty array to be passed in
|
|
if (apidl)
|
|
{
|
|
HIDA hida = HIDA_Create(pidlFolder, cidl, apidl);
|
|
if (hida)
|
|
{
|
|
// init our registerd data formats
|
|
DS_IDLData_InitializeClipboardFormats();
|
|
hres = DataObj_SetGlobal(*ppdtobj, g_cfDS_HIDA, hida);
|
|
if (FAILED(hres))
|
|
goto SetFailed;
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
SetFailed:
|
|
(*ppdtobj)->lpVtbl->Release(*ppdtobj);
|
|
*ppdtobj = NULL;
|
|
}
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDS_IDLData_CreateFromIDArray2(IDataObjectVtbl *lpVtbl,
|
|
LPCITEMIDLIST pidlFolder,
|
|
UINT cidl, LPCITEMIDLIST apidl[],
|
|
IDataObject **ppdtobj)
|
|
{
|
|
return CDS_IDLData_CreateFromIDArray3(lpVtbl, pidlFolder, cidl, apidl, NULL, ppdtobj);
|
|
}
|
|
//
|
|
// Create an instance of CDS_IDLData with default Vtable pointer.
|
|
//
|
|
HRESULT WINAPI CDS_IDLData_CreateFromIDArray(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[], IDataObject **ppdtobj)
|
|
{
|
|
return CDS_IDLData_CreateFromIDArray3(NULL, pidlFolder, cidl, apidl, NULL, ppdtobj);
|
|
}
|
|
|
|
//
|
|
// Returns: TRUE, if this dataobject is one of ours.
|
|
//
|
|
BOOL CDS_IDLData_IsOurs(LPDATAOBJECT pdtobj)
|
|
{
|
|
if (pdtobj==NULL)
|
|
return FALSE;
|
|
|
|
return (pdtobj->lpVtbl->QueryInterface == CDS_IDLData_QueryInterface);
|
|
}
|
|
|
|
//
|
|
// Returns: TRUE, if this dataobject is one of ours that does not contain
|
|
// any innner dataobject.
|
|
//
|
|
BOOL CDS_IDLData_IsSimple(LPDATAOBJECT pdtobj)
|
|
{
|
|
if (CDS_IDLData_IsOurs(pdtobj))
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pdtobj);
|
|
if (this->_pdtInner)
|
|
{
|
|
return FALSE; // aggregated
|
|
}
|
|
return TRUE; // pure and simple.
|
|
}
|
|
|
|
return FALSE; // not ours
|
|
}
|
|
//
|
|
// Clone DataObject only for MOVE/COPY operation
|
|
//
|
|
HRESULT CDS_IDLData_Clone(LPDATAOBJECT pdtobjIn, UINT acf[], UINT ccf, LPDATAOBJECT *ppdtobjOut)
|
|
{
|
|
HRESULT hres = CDS_IDLData_CreateInstance(NULL, ppdtobjOut, NULL);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
UINT i;
|
|
FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
for (i=0 ; i<ccf ; i++)
|
|
{
|
|
HRESULT hresT;
|
|
STGMEDIUM medium;
|
|
fmte.cfFormat = acf[i];
|
|
hresT = pdtobjIn->lpVtbl->GetData(pdtobjIn, &fmte, &medium);
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
HGLOBAL hmem;
|
|
if (medium.pUnkForRelease)
|
|
{
|
|
// We need to clone the hGlobal.
|
|
UINT cbMem = GlobalSize(medium.hGlobal);
|
|
hmem = GlobalAlloc(GPTR, cbMem);
|
|
if (hmem)
|
|
{
|
|
hmemcpy((LPVOID)hmem, GlobalLock(medium.hGlobal), cbMem);
|
|
GlobalUnlock(medium.hGlobal);
|
|
}
|
|
SHReleaseStgMedium(&medium);
|
|
}
|
|
else
|
|
{
|
|
// We don't need to clone the hGlobal.
|
|
hmem = medium.hGlobal;
|
|
}
|
|
|
|
if (hmem)
|
|
DataObj_SetGlobal(*ppdtobjOut, acf[i], hmem);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
void
|
|
DSDataObj_EnableHDROP(LPDATAOBJECT pDataObj)
|
|
{
|
|
CDS_IDLData * this = IToClass(CDS_IDLData, dtobj, pDataObj);
|
|
this->_fhDrop_Enabled = TRUE;
|
|
}
|
|
|
|
HRESULT CDS_IDLData_CloneForMoveCopy(LPDATAOBJECT pdtobjIn, LPDATAOBJECT *ppdtobjOut)
|
|
{
|
|
UINT acf[] = { g_cfDS_HIDA, g_cfDS_OFFSETS, g_cfDS_HDROP };
|
|
return CDS_IDLData_Clone(pdtobjIn, acf, ARRAYSIZE(acf), ppdtobjOut);
|
|
}
|
|
|
|
LPIDA DataObj_GetDS_HIDA(LPDATAOBJECT pdtobj, STGMEDIUM *pmedium);
|
|
|
|
//
|
|
// Creates a HDROP (Win 3.1 compatible file list) from DS_HIDA.
|
|
//
|
|
//
|
|
HRESULT CDS_IDLData_GetHDrop(IDataObject *pdtobj, STGMEDIUM *pmedium, BOOL fAltName)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
LPITEMIDLIST pidl = NULL; // realloced in HIDA_FillIDList
|
|
STGMEDIUM medium;
|
|
TCHAR szPath[MAX_PATH];
|
|
UINT i, cbAlloc = SIZEOF(DROPFILES) + SIZEOF(TCHAR); // header + null terminator
|
|
LPIDA pida = DataObj_GetDS_HIDA(pdtobj, &medium);
|
|
|
|
Assert(pida && pida->cidl); // we created this
|
|
|
|
for (i = 0; i < pida->cidl; i++)
|
|
{
|
|
// HIDA_FillIDList may realloc pidl
|
|
LPITEMIDLIST pidlTemp = HIDA_FillIDList(medium.hGlobal, i, pidl);
|
|
if (pidlTemp == NULL)
|
|
{
|
|
// hres = E_OUTOFMEMORY; // already set
|
|
break;
|
|
}
|
|
pidl = pidlTemp;
|
|
|
|
// We may ask for the ALT name even if they did not ask for it in the
|
|
// case where we failed to get the long name...
|
|
if (!SHGetPathFromIDListEx(pidl, szPath, fAltName)
|
|
&& !(!fAltName && (SHGetPathFromIDListEx(pidl, szPath, TRUE))))
|
|
{
|
|
// The path probably exceeds the max lenght, lets Bail...
|
|
DebugMsg(DM_TRACE, TEXT("s.CFSIDLData_GetHDrop: SHGetPathFromIDList failed."));
|
|
hres = E_FAIL;
|
|
goto Abort;
|
|
}
|
|
cbAlloc += lstrlen(szPath) * SIZEOF(TCHAR) + SIZEOF(TCHAR);
|
|
}
|
|
pmedium->hGlobal = GlobalAlloc(GPTR, cbAlloc);
|
|
if (pmedium->hGlobal)
|
|
{
|
|
LPDROPFILES pdf = (LPDROPFILES)pmedium->hGlobal;
|
|
LPTSTR pszFiles = (LPTSTR)(pdf + 1);
|
|
pdf->pFiles = SIZEOF(DROPFILES);
|
|
Assert(pdf->pt.x==0);
|
|
Assert(pdf->pt.y==0);
|
|
Assert(pdf->fNC==FALSE);
|
|
Assert(pdf->fWide==FALSE);
|
|
#ifdef UNICODE
|
|
pdf->fWide = TRUE;
|
|
#endif
|
|
|
|
for (i = 0; i < pida->cidl; i++)
|
|
{
|
|
LPITEMIDLIST pidlTemp = HIDA_FillIDList(medium.hGlobal, i, pidl);
|
|
Assert(pidl == pidlTemp);
|
|
|
|
// Don't read directly into buffer as we my have been forced to use alternate name and the
|
|
// total path we allocated may be smaller than we would tromp on which will screw up the heap.
|
|
if (!SHGetPathFromIDListEx(pidl, szPath, fAltName))
|
|
SHGetPathFromIDListEx(pidl, szPath, TRUE);
|
|
|
|
lstrcpy(pszFiles, szPath);
|
|
pszFiles += lstrlen(pszFiles) + 1;
|
|
|
|
Assert((UINT)((LPBYTE)pszFiles - (LPBYTE)pdf) < cbAlloc);
|
|
}
|
|
Assert((LPTSTR)((LPBYTE)pdf + cbAlloc - SIZEOF(TCHAR)) == pszFiles);
|
|
Assert(*pszFiles == 0); // zero init alloc
|
|
|
|
pmedium->tymed = TYMED_HGLOBAL;
|
|
pmedium->pUnkForRelease = NULL;
|
|
|
|
hres = S_OK;
|
|
}
|
|
Abort:
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
|
|
ILFree(pidl);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
HRESULT FSDS_CreateFSIDArray(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST * apidl,
|
|
LPDATAOBJECT pdtInner, LPDATAOBJECT * pdtobjOut)
|
|
{
|
|
LPCITEMIDLIST pidlAbs;
|
|
TCHAR szPath[MAX_PATH];
|
|
UINT index;
|
|
DWORD dwFlags;
|
|
BOOL fAnyDSObjects = FALSE;
|
|
|
|
for (index = 0; index < cidl; index++) {
|
|
pidlAbs = ILCombine (pidlFolder, apidl[index]);
|
|
SHGetPathFromIDList (pidlAbs, szPath);
|
|
dwFlags = SHGetClassFlags ((LPIDFOLDER)pidlAbs, TRUE);
|
|
if (dwFlags & SHCF_SUPPORTS_IOBJLIFE) {
|
|
fAnyDSObjects = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (fAnyDSObjects) {
|
|
return CDS_IDLData_CreateFromIDArray3(&c_CDS_IDLDataVtbl,
|
|
pidlFolder, cidl, apidl,
|
|
pdtInner, pdtobjOut);
|
|
} else
|
|
{
|
|
return CIDLData_CreateFromIDArray3(&c_CFSIDLDataVtbl,
|
|
pidlFolder, cidl, apidl,
|
|
pdtInner, pdtobjOut);
|
|
}
|
|
}
|
|
|
|
LPIDA DataObj_GetDS_HIDA(LPDATAOBJECT pdtobj, STGMEDIUM *pmedium)
|
|
{
|
|
FORMATETC fmte = {g_cfDS_HIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (pmedium)
|
|
{
|
|
pmedium->pUnkForRelease = NULL;
|
|
pmedium->hGlobal = NULL;
|
|
}
|
|
|
|
if (!pmedium)
|
|
{
|
|
if (SUCCEEDED(pdtobj->lpVtbl->QueryGetData(pdtobj, &fmte)))
|
|
return (LPIDA)TRUE;
|
|
else
|
|
return (LPIDA)FALSE;
|
|
}
|
|
else if (SUCCEEDED(pdtobj->lpVtbl->GetData(pdtobj, &fmte, pmedium)))
|
|
{
|
|
return (LPIDA)GlobalLock(pmedium->hGlobal);
|
|
}
|
|
return NULL;
|
|
}
|