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