windows-nt/Source/XPSP1/NT/shell/shell32/bookmk.c
2020-09-26 16:20:57 +08:00

295 lines
7.7 KiB
C

#include "shellprv.h"
#pragma hdrstop
#include "fstreex.h"
#include "bookmk.h"
// *** WARNING ***
//
// Scrap_CreateFromDataObject is a TCHAR export from SHSCRAP.DLL, if you change its calling convention, you
// must modify PFNSCRAPCREATEFROMDATAOBJECT and the wrapper fn. below
//
// *** WARNING ***
typedef HRESULT (CALLBACK *PFNSCRAPCREATEFROMDATAOBJECT)(LPCTSTR pszPath, IDataObject *pDataObj, BOOL fLink, LPTSTR pszNewFile);
STDAPI Scrap_CreateFromDataObject(LPCTSTR pszPath, IDataObject *pDataObj, BOOL fLink, LPTSTR pszNewFile)
{
static PFNSCRAPCREATEFROMDATAOBJECT pfn = (PFNSCRAPCREATEFROMDATAOBJECT)-1;
if (pfn == (PFNSCRAPCREATEFROMDATAOBJECT)-1)
{
HINSTANCE hinst = LoadLibrary(TEXT("shscrap.dll"));
if (hinst)
{
pfn = (PFNSCRAPCREATEFROMDATAOBJECT)GetProcAddress(hinst, "Scrap_CreateFromDataObject");
}
else
{
pfn = NULL;
}
}
if (pfn)
{
return pfn(pszPath, pDataObj, fLink, pszNewFile);
}
// for failure cases just return E_UNEXPECTED;
return E_UNEXPECTED;
}
//
// Parameters:
// pDataObj -- The data object passed from the drag source.
// pt -- Dropped position (in screen coordinate).
// pdwEffect -- Pointer to dwEffect variable to be returned to the drag source.
//
STDAPI SHCreateBookMark(HWND hwnd, LPCTSTR pszPath, IDataObject *pDataObj, POINTL pt, DWORD *pdwEffect)
{
HRESULT hres;
TCHAR szNewFile[MAX_PATH];
DECLAREWAITCURSOR;
// We should have only one bit set.
ASSERT(*pdwEffect==DROPEFFECT_COPY || *pdwEffect==DROPEFFECT_LINK || *pdwEffect==DROPEFFECT_MOVE);
SetWaitCursor();
hres = Scrap_CreateFromDataObject(pszPath, pDataObj, *pdwEffect == DROPEFFECT_LINK, szNewFile);
ResetWaitCursor();
if (SUCCEEDED(hres))
{
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, szNewFile, NULL);
SHChangeNotify(SHCNE_FREESPACE, SHCNF_PATH, szNewFile, NULL);
PositionFileFromDrop(hwnd, szNewFile, NULL);
}
else
{
*pdwEffect = 0;
}
return hres;
}
#define MAX_FORMATS 20
typedef struct
{
IEnumFORMATETC efmt;
LONG cRef;
UINT ifmt;
UINT cfmt;
FORMATETC afmt[1];
} CStdEnumFmt;
// forward
extern const IEnumFORMATETCVtbl c_CStdEnumFmtVtbl;
//===========================================================================
// CStdEnumFmt : Constructor
//===========================================================================
STDAPI SHCreateStdEnumFmtEtc(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **ppenumFormatEtc)
{
CStdEnumFmt * this = (CStdEnumFmt*)LocalAlloc( LPTR, SIZEOF(CStdEnumFmt) + (cfmt-1)*SIZEOF(FORMATETC));
if (this)
{
this->efmt.lpVtbl = &c_CStdEnumFmtVtbl;
this->cRef = 1;
this->cfmt = cfmt;
memcpy(this->afmt, afmt, cfmt * SIZEOF(FORMATETC));
*ppenumFormatEtc = &this->efmt;
return S_OK;
}
*ppenumFormatEtc = NULL;
return E_OUTOFMEMORY;
}
STDAPI SHCreateStdEnumFmtEtcEx(UINT cfmt, const FORMATETC afmt[],
IDataObject *pdtInner, IEnumFORMATETC **ppenumFormatEtc)
{
HRESULT hres;
FORMATETC *pfmt;
UINT cfmtTotal;
if (pdtInner)
{
IEnumFORMATETC *penum;
hres = pdtInner->lpVtbl->EnumFormatEtc(pdtInner, DATADIR_GET, &penum);
if (SUCCEEDED(hres))
{
UINT cfmt2, cGot;
FORMATETC fmte;
for (cfmt2 = 0; penum->lpVtbl->Next(penum, 1, &fmte, &cGot) == S_OK; cfmt2++)
{
// count up the number of FormatEnum in cfmt2
SHFree(fmte.ptd);
}
penum->lpVtbl->Reset(penum);
cfmtTotal = cfmt + cfmt2;
// Allocate the buffer for total
pfmt = (FORMATETC *)LocalAlloc(LPTR, SIZEOF(FORMATETC) * cfmtTotal);
if (pfmt)
{
UINT i;
// Get formatetcs from the inner object
for (i = 0; i < cfmt2; i++)
{
penum->lpVtbl->Next(penum, 1, &pfmt[i], &cGot);
// NOTE! We do not support inner objects with non-NULL ptd
ASSERT(pfmt[i].ptd == NULL);
SHFree(pfmt[i].ptd);
pfmt[i].ptd = NULL;
}
// Copy the rest
if (cfmt)
{
#ifdef DEBUG
UINT ifmt;
for (ifmt = 0; ifmt < cfmt; ifmt++) {
// NOTE! We do not support non-NULL ptd
ASSERT(afmt[ifmt].ptd == NULL);
}
#endif
memcpy(&pfmt[cfmt2], afmt, SIZEOF(FORMATETC) * cfmt);
}
}
else
{
hres = E_OUTOFMEMORY;
}
penum->lpVtbl->Release(penum);
}
}
else
{
hres = E_FAIL; // ptInner == NULL
}
if (FAILED(hres) && hres != E_OUTOFMEMORY)
{
//
// Ignore none fatal error from pdtInner::EnumFormatEtc
// We'll come here if
// 1. pdtInner == NULL or
// 2. pdtInner->EnumFormatEtc failed (except E_OUTOFMEMORY)
//
hres = NOERROR;
pfmt = (FORMATETC *)afmt; // safe const -> non const cast
cfmtTotal = cfmt;
}
if (SUCCEEDED(hres))
{
hres = SHCreateStdEnumFmtEtc(cfmtTotal, pfmt, ppenumFormatEtc);
if (pfmt != afmt)
LocalFree((HLOCAL)pfmt);
}
return hres;
}
STDMETHODIMP CStdEnumFmt_QueryInterface(IEnumFORMATETC *pefmt, REFIID riid, void **ppvObj)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
if (IsEqualIID(riid, &IID_IEnumFORMATETC) || IsEqualIID(riid, &IID_IUnknown))
{
*ppvObj = &this->efmt;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
this->cRef++;
return NOERROR;
}
STDMETHODIMP_(ULONG) CStdEnumFmt_AddRef(IEnumFORMATETC *pefmt)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
return ++this->cRef;
}
STDMETHODIMP_(ULONG) CStdEnumFmt_Release(IEnumFORMATETC *pefmt)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
this->cRef--;
if (this->cRef > 0)
return this->cRef;
LocalFree((HLOCAL)this);
return 0;
}
STDMETHODIMP CStdEnumFmt_Next(IEnumFORMATETC *pefmt, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
UINT cfetch;
HRESULT hres = S_FALSE; // assume less numbers
if (this->ifmt < this->cfmt)
{
cfetch = this->cfmt - this->ifmt;
if (cfetch>=celt)
{
cfetch = celt;
hres = S_OK;
}
memcpy(rgelt, &this->afmt[this->ifmt], cfetch*SIZEOF(FORMATETC));
this->ifmt += cfetch;
}
else
{
cfetch = 0;
}
if (pceltFethed)
*pceltFethed = cfetch;
return hres;
}
STDMETHODIMP CStdEnumFmt_Skip(IEnumFORMATETC *pefmt, ULONG celt)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
this->ifmt += celt;
if (this->ifmt > this->cfmt) {
this->ifmt = this->cfmt;
return S_FALSE;
}
return S_OK;
}
STDMETHODIMP CStdEnumFmt_Reset(IEnumFORMATETC *pefmt)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
this->ifmt = 0;
return S_OK;
}
STDMETHODIMP CStdEnumFmt_Clone(IEnumFORMATETC *pefmt, IEnumFORMATETC ** ppenum)
{
CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt);
return SHCreateStdEnumFmtEtc(this->cfmt, this->afmt, ppenum);
}
const IEnumFORMATETCVtbl c_CStdEnumFmtVtbl = {
CStdEnumFmt_QueryInterface, CStdEnumFmt_AddRef, CStdEnumFmt_Release,
CStdEnumFmt_Next,
CStdEnumFmt_Skip,
CStdEnumFmt_Reset,
CStdEnumFmt_Clone,
};