|
|
#include "local.h"
#include "resource.h"
#include "cachesrch.h"
#include "sfview.h"
#include <shlwapi.h>
#include <limits.h>
#include "chcommon.h"
#include "cafolder.h"
#include <mluisupp.h>
#define DM_HSFOLDER 0
// these are common flags to ShChangeNotify
#ifndef UNIX
#define CHANGE_FLAGS (0)
#else
#define CHANGE_FLAGS SHCNF_FLUSH
#endif
static void _GetFileTypeInternal(LPCEIPIDL pidl, LPUTSTR pszStr, UINT cchStr);
//
// Column definition for the Cache Folder DefView
//
enum { ICOLC_URL_SHORTNAME = 0, ICOLC_URL_NAME, ICOLC_URL_TYPE, ICOLC_URL_SIZE, ICOLC_URL_EXPIRES, ICOLC_URL_MODIFIED, ICOLC_URL_ACCESSED, ICOLC_URL_LASTSYNCED, ICOLC_URL_MAX // Make sure this is the last enum item
};
typedef struct _COLSPEC { short int iCol; short int ids; // Id of string for title
short int cchCol; // Number of characters wide to make column
short int iFmt; // The format of the column;
} COLSPEC;
const COLSPEC s_CacheFolder_cols[] = { {ICOLC_URL_SHORTNAME, IDS_SHORTNAME_COL, 18, LVCFMT_LEFT}, {ICOLC_URL_NAME, IDS_NAME_COL, 30, LVCFMT_LEFT}, {ICOLC_URL_TYPE, IDS_TYPE_COL, 15, LVCFMT_LEFT}, {ICOLC_URL_SIZE, IDS_SIZE_COL, 8, LVCFMT_RIGHT}, {ICOLC_URL_EXPIRES, IDS_EXPIRES_COL, 18, LVCFMT_LEFT}, {ICOLC_URL_MODIFIED, IDS_MODIFIED_COL, 18, LVCFMT_LEFT}, {ICOLC_URL_ACCESSED, IDS_ACCESSED_COL, 18, LVCFMT_LEFT}, {ICOLC_URL_LASTSYNCED, IDS_LASTSYNCED_COL, 18, LVCFMT_LEFT} };
//////////////////////////////////////////////////////////////////////
LPCEIPIDL _CreateBuffCacheFolderPidl(DWORD cbSize, LPINTERNET_CACHE_ENTRY_INFO pcei) {
DWORD cbTotalSize = sizeof(CEIPIDL) + cbSize - sizeof(INTERNET_CACHE_ENTRY_INFO);
LPCEIPIDL pceip = (LPCEIPIDL)OleAlloc(cbTotalSize); if (pceip) { ZeroMemory(pceip, cbTotalSize); pceip->cb = (USHORT)(cbTotalSize - sizeof(USHORT)); pceip->usSign = CEIPIDL_SIGN; _CopyCEI(&pceip->cei, pcei, cbSize); } return pceip; }
HRESULT CacheFolderView_MergeMenu(UINT idMenu, LPQCMINFO pqcm) { HMENU hmenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(idMenu)); if (hmenu) { MergeMenuHierarchy(pqcm->hmenu, hmenu, pqcm->idCmdFirst, pqcm->idCmdLast); DestroyMenu(hmenu); } return S_OK; }
HRESULT CacheFolderView_DidDragDrop(IDataObject *pdo, DWORD dwEffect) { if (dwEffect & DROPEFFECT_MOVE) { CCacheItem *pCItem; BOOL fBulkDelete;
if (SUCCEEDED(pdo->QueryInterface(IID_ICache, (void **)&pCItem))) { fBulkDelete = pCItem->_cItems > LOTS_OF_FILES; for (UINT i = 0; i < pCItem->_cItems; i++) { if (DeleteUrlCacheEntry(CPidlToSourceUrl((LPCEIPIDL)pCItem->_ppidl[i]))) { if (!fBulkDelete) { _GenerateEvent(SHCNE_DELETE, pCItem->_pCFolder->_pidl, pCItem->_ppidl[i], NULL); } } } if (fBulkDelete) { _GenerateEvent(SHCNE_UPDATEDIR, pCItem->_pCFolder->_pidl, NULL, NULL); } SHChangeNotifyHandleEvents(); pCItem->Release(); return S_OK; } } return E_FAIL; }
// There are copies of exactly this function in SHELL32
// Add the File Type page
HRESULT CacheFolderView_OnAddPropertyPages(DWORD pv, SFVM_PROPPAGE_DATA * ppagedata) { IShellPropSheetExt * pspse; HRESULT hr = CoCreateInstance(CLSID_FileTypes, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellPropSheetExt, &pspse)); if (SUCCEEDED(hr)) { hr = pspse->AddPages(ppagedata->pfn, ppagedata->lParam); pspse->Release(); } return hr; }
HRESULT CacheFolderView_OnGetSortDefaults(int * piDirection, int * plParamSort) { *plParamSort = (int)ICOLC_URL_ACCESSED; if (piDirection) *piDirection = 1; return S_OK; }
HRESULT CALLBACK CCacheFolder::_sViewCallback(IShellView *psv, IShellFolder *psf, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CCacheFolder *pfolder = NULL;
HRESULT hr = S_OK;
switch (uMsg) { case DVM_GETHELPTEXT: { TCHAR szText[MAX_PATH];
UINT id = LOWORD(wParam); UINT cchBuf = HIWORD(wParam); LPTSTR pszBuf = (LPTSTR)lParam;
MLLoadString(id + IDS_MH_FIRST, szText, ARRAYSIZE(szText));
// we know for a fact that this parameter is really a TCHAR
if ( IsOS( OS_NT )) { SHTCharToUnicode( szText, (LPWSTR) pszBuf, cchBuf ); } else { SHTCharToAnsi( szText, (LPSTR) pszBuf, cchBuf ); } break; }
case SFVM_GETNOTIFY: hr = psf->QueryInterface(CLSID_CacheFolder, (void **)&pfolder); if (SUCCEEDED(hr)) { *(LPCITEMIDLIST*)wParam = pfolder->_pidl; // evil alias
pfolder->Release(); } else wParam = 0; *(LONG*)lParam = SHCNE_DELETE | SHCNE_UPDATEDIR; break;
case DVM_DIDDRAGDROP: hr = CacheFolderView_DidDragDrop((IDataObject *)lParam, (DWORD)wParam); break;
case DVM_INITMENUPOPUP: hr = S_OK; break;
case DVM_INVOKECOMMAND: _ArrangeFolder(hwnd, (UINT)wParam); break;
case DVM_COLUMNCLICK: ShellFolderView_ReArrange(hwnd, (UINT)wParam); hr = S_OK; break;
case DVM_MERGEMENU: hr = CacheFolderView_MergeMenu(MENU_CACHE, (LPQCMINFO)lParam); break;
case DVM_DEFVIEWMODE: *(FOLDERVIEWMODE *)lParam = FVM_DETAILS; break;
case SFVM_ADDPROPERTYPAGES: hr = CacheFolderView_OnAddPropertyPages((DWORD)wParam, (SFVM_PROPPAGE_DATA *)lParam); break;
case SFVM_GETSORTDEFAULTS: hr = CacheFolderView_OnGetSortDefaults((int *)wParam, (int *)lParam); break;
case SFVM_UPDATESTATUSBAR: ResizeStatusBar(hwnd, FALSE); // We did not set any text; let defview do it
hr = E_NOTIMPL; break;
case SFVM_SIZE: ResizeStatusBar(hwnd, FALSE); break;
case SFVM_GETPANE: if (wParam == PANE_ZONE) *(DWORD*)lParam = 1; else *(DWORD*)lParam = PANE_NONE;
break; case SFVM_WINDOWCREATED: ResizeStatusBar(hwnd, TRUE); break;
case SFVM_GETZONE: *(DWORD*)lParam = URLZONE_INTERNET; // Internet by default
break;
default: hr = E_FAIL; }
return hr; }
HRESULT CacheFolderView_CreateInstance(CCacheFolder *pHCFolder, void **ppv) { CSFV csfv;
csfv.cbSize = sizeof(csfv); csfv.pshf = (IShellFolder *)pHCFolder; csfv.psvOuter = NULL; csfv.pidl = pHCFolder->_pidl; csfv.lEvents = SHCNE_DELETE; // SHCNE_DISKEVENTS | SHCNE_ASSOCCHANGED | SHCNE_GLOBALEVENTS;
csfv.pfnCallback = CCacheFolder::_sViewCallback; csfv.fvm = (FOLDERVIEWMODE)0; // Have defview restore the folder view mode
return SHCreateShellFolderViewEx(&csfv, (IShellView**)ppv); }
CCacheFolderEnum::CCacheFolderEnum(DWORD grfFlags, CCacheFolder *pHCFolder) : _cRef(1) { DllAddRef();
_grfFlags = grfFlags, _pCFolder = pHCFolder; pHCFolder->AddRef(); ASSERT(_hEnum == NULL); }
CCacheFolderEnum::~CCacheFolderEnum() { ASSERT(_cRef == 0); // we should always have a zero ref count here
TraceMsg(DM_HSFOLDER, "hcfe - ~CCacheFolderEnum() called."); _pCFolder->Release(); if (_pceiWorking) { LocalFree(_pceiWorking); _pceiWorking = NULL; }
if (_hEnum) { FindCloseUrlCache(_hEnum); _hEnum = NULL; } DllRelease(); }
HRESULT CCacheFolderEnum_CreateInstance(DWORD grfFlags, CCacheFolder *pHCFolder, IEnumIDList **ppeidl) { TraceMsg(DM_HSFOLDER, "hcfe - CreateInstance() called.");
*ppeidl = NULL; // null the out param
CCacheFolderEnum *pHCFE = new CCacheFolderEnum(grfFlags, pHCFolder); if (!pHCFE) return E_OUTOFMEMORY;
*ppeidl = pHCFE;
return S_OK; }
HRESULT CCacheFolderEnum::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CCacheFolderEnum, IEnumIDList), { 0 }, }; return QISearch(this, qit, riid, ppv); }
ULONG CCacheFolderEnum::AddRef(void) { return InterlockedIncrement(&_cRef); }
ULONG CCacheFolderEnum::Release(void) { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
//
// IEnumIDList Methods
//
HRESULT CCacheFolderEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) { HRESULT hr = S_FALSE; DWORD dwBuffSize; DWORD dwError; LPTSTR pszSearchPattern = NULL;
TraceMsg(DM_HSFOLDER, "hcfe - Next() called.");
if (0 == (SHCONTF_NONFOLDERS & _grfFlags)) { dwError = 0xFFFFFFFF; goto exitPoint; }
if (_pceiWorking == NULL) { _pceiWorking = (LPINTERNET_CACHE_ENTRY_INFO)LocalAlloc(LPTR, MAX_URLCACHE_ENTRY); if (_pceiWorking == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; goto exitPoint; } }
// Set up things to enumerate history items, if appropriate, otherwise,
// we'll just pass in NULL and enumerate all items as before.
TryAgain:
dwBuffSize = MAX_URLCACHE_ENTRY; dwError = S_OK;
if (!_hEnum) // _hEnum maintains our state as we iterate over all the cache entries
{ _hEnum = FindFirstUrlCacheEntry(pszSearchPattern, _pceiWorking, &dwBuffSize); if (!_hEnum) dwError = GetLastError(); }
else if (!FindNextUrlCacheEntry(_hEnum, _pceiWorking, &dwBuffSize)) { dwError = GetLastError(); }
if (S_OK == dwError) { LPCEIPIDL pcei = NULL;
if ((_pceiWorking->CacheEntryType & URLHISTORY_CACHE_ENTRY) == URLHISTORY_CACHE_ENTRY) goto TryAgain; pcei = _CreateBuffCacheFolderPidl(dwBuffSize, _pceiWorking); if (pcei) { _GetFileTypeInternal(pcei, pcei->szTypeName, ARRAYSIZE(pcei->szTypeName)); rgelt[0] = (LPITEMIDLIST)pcei; if (pceltFetched) *pceltFetched = 1; } else { dwError = ERROR_NOT_ENOUGH_MEMORY; } }
exitPoint:
if (dwError != S_OK) { if (_hEnum) { FindCloseUrlCache(_hEnum); _hEnum = NULL; } if (pceltFetched) *pceltFetched = 0; rgelt[0] = NULL; hr = S_FALSE; } else { hr = S_OK; } return hr; }
HRESULT CCacheFolderEnum::Skip(ULONG celt) { TraceMsg(DM_HSFOLDER, "hcfe - Skip() called."); return E_NOTIMPL; }
HRESULT CCacheFolderEnum::Reset() { TraceMsg(DM_HSFOLDER, "hcfe - Reset() called."); return E_NOTIMPL; }
HRESULT CCacheFolderEnum::Clone(IEnumIDList **ppenum) { TraceMsg(DM_HSFOLDER, "hcfe - Clone() called."); return E_NOTIMPL; }
//////////////////////////////////////////////////////////////////////////////
//
// CCacheFolder Object
//
//////////////////////////////////////////////////////////////////////////////
CCacheFolder::CCacheFolder() : _cRef(1) { ASSERT(_pidl == NULL); DllAddRef(); }
CCacheFolder::~CCacheFolder() { ASSERT(_cRef == 0); // should always have zero
TraceMsg(DM_HSFOLDER, "hcf - ~CCacheFolder() called."); if (_pidl) ILFree(_pidl); if (_pshfSys) _pshfSys->Release(); DllRelease(); }
HRESULT CCacheFolder::QueryInterface(REFIID iid, void **ppv) { static const QITAB qitCache[] = { QITABENT(CCacheFolder, IShellFolder2), QITABENTMULTI(CCacheFolder, IShellFolder, IShellFolder2), QITABENT(CCacheFolder, IShellIcon), QITABENT(CCacheFolder, IPersistFolder2), QITABENTMULTI(CCacheFolder, IPersistFolder, IPersistFolder2), QITABENTMULTI(CCacheFolder, IPersist, IPersistFolder2), { 0 }, };
if (iid == CLSID_CacheFolder) { *ppv = (void *)(CCacheFolder *)this; // unrefed
AddRef(); return S_OK; }
HRESULT hr = QISearch(this, qitCache, iid, ppv);
if (FAILED(hr) && !IsOS(OS_WHISTLERORGREATER)) { if (iid == IID_IShellView) { // this is a total hack... return our view object from this folder
//
// the desktop.ini file for "Temporary Internet Files" has UICLSID={guid of this object}
// this lets us implment only ths IShellView for this folder, leaving the IShellFolder
// to the default file system. this enables operations on the pidls that are stored in
// this folder that would otherwise faile since our IShellFolder is not as complete
// as the default (this is the same thing the font folder does).
//
// to support this with defview we would either have to do a complete wrapper object
// for the view implemenation, or add this hack that hands out the view object, this
// assumes we know the order of calls that the shell makes to create this object
// and get the IShellView implementation
//
hr = CacheFolderView_CreateInstance(this, ppv); } }
return hr; }
STDMETHODIMP CCacheFolder::_GetDetail(LPCITEMIDLIST pidl, UINT iColumn, LPTSTR pszStr, UINT cchStr) { switch (iColumn) { case ICOLC_URL_SHORTNAME: _GetCacheItemTitle((LPCEIPIDL)pidl, pszStr, cchStr); break;
case ICOLC_URL_NAME: StrCpyN(pszStr, CPidlToSourceUrl((LPCEIPIDL)pidl), cchStr); break;
case ICOLC_URL_TYPE: ualstrcpyn(pszStr, ((LPCEIPIDL)pidl)->szTypeName, cchStr); break;
case ICOLC_URL_SIZE: StrFormatKBSize(((LPCEIPIDL)pidl)->cei.dwSizeLow, pszStr, cchStr); break;
case ICOLC_URL_EXPIRES: FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.ExpireTime, pszStr, cchStr, FALSE); break;
case ICOLC_URL_ACCESSED: FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.LastAccessTime, pszStr, cchStr, FALSE); break;
case ICOLC_URL_MODIFIED: FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.LastModifiedTime, pszStr, cchStr, FALSE); break;
case ICOLC_URL_LASTSYNCED: FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.LastSyncTime, pszStr, cchStr, FALSE); break; } return S_OK; }
HRESULT CCacheFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pdi) { HRESULT hr = E_FAIL;
if (pidl == NULL) { if (iColumn < ICOLC_URL_MAX) { TCHAR szTemp[128];
MLLoadString(s_CacheFolder_cols[iColumn].ids, szTemp, ARRAYSIZE(szTemp)); pdi->fmt = s_CacheFolder_cols[iColumn].iFmt; pdi->cxChar = s_CacheFolder_cols[iColumn].cchCol; hr = StringToStrRet(szTemp, &pdi->str); } else { // enum done
hr = E_FAIL; } } else if (!IS_VALID_CEIPIDL(pidl)) { if (_pshfSys) { // delegate to the filesystem
hr = _pshfSys->GetDetailsOf(pidl, iColumn, pdi); } } else { TCHAR szTemp[MAX_URL_STRING];
hr = _GetDetail(pidl, iColumn, szTemp, ARRAYSIZE(szTemp)); if (SUCCEEDED(hr)) { hr = StringToStrRet(szTemp, &pdi->str); } } return hr; }
HRESULT CCacheFolder::_GetFileSysFolder(IShellFolder2 **ppsf) { *ppsf = NULL; IPersistFolder *ppf; HRESULT hr = CoCreateInstance(CLSID_ShellFSFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPersistFolder, &ppf)); if (SUCCEEDED(hr)) { hr = ppf->Initialize(this->_pidl); if (SUCCEEDED(hr)) { hr = ppf->QueryInterface(IID_PPV_ARG(IShellFolder2, ppsf)); } ppf->Release(); } return hr; }
// IShellFolder
HRESULT CCacheFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv) { HRESULT hr = E_FAIL;
if (!IS_VALID_CEIPIDL(pidl)) { if (_pshfSys) { hr = _pshfSys->BindToObject(pidl, pbc, riid, ppv); } } else { hr = E_NOTIMPL; *ppv = NULL; } return hr; }
HRESULT CCacheFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes) { HRESULT hr = E_FAIL; if (_pshfSys) { hr = _pshfSys->ParseDisplayName(hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes); } else *ppidl = NULL; return hr; }
// IPersist
HRESULT CCacheFolder::GetClassID(CLSID *pclsid) { *pclsid = CLSID_CacheFolder; return S_OK; }
STDAPI CacheFolder_CreateInstance(IUnknown* punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { *ppunk = NULL; // null the out param
if (punkOuter) return CLASS_E_NOAGGREGATION;
CCacheFolder *pcache = new CCacheFolder(); if (pcache) { *ppunk = SAFECAST(pcache, IShellFolder2*); return S_OK; } return E_OUTOFMEMORY; }
ULONG CCacheFolder::AddRef() { return InterlockedIncrement(&_cRef); }
ULONG CCacheFolder::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
// IShellFolder
HRESULT CCacheFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList) { return CCacheFolderEnum_CreateInstance(grfFlags, this, ppenumIDList); }
HRESULT CCacheFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv) { return BindToObject(pidl, pbc, riid, ppv); }
// unalligned verison
#if defined(UNIX) || !defined(_X86_)
// defined in hsfolder.cpp
extern UINT ULCompareFileTime(UNALIGNED const FILETIME *pft1, UNALIGNED const FILETIME *pft2);
#else
#define ULCompareFileTime(pft1, pft2) CompareFileTime(pft1, pft2)
#endif
HRESULT CCacheFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { BOOL fRealigned1; HRESULT hr = AlignPidl(&pidl1, &fRealigned1); if (SUCCEEDED(hr)) { BOOL fRealigned2; hr = AlignPidl(&pidl2, &fRealigned2);
if (SUCCEEDED(hr)) { hr = _CompareAlignedIDs(lParam, (LPCEIPIDL)pidl1, (LPCEIPIDL)pidl2);
if (fRealigned2) FreeRealignedPidl(pidl2); }
if (fRealigned1) FreeRealignedPidl(pidl1); }
return hr; }
int _CompareSize(LPCEIPIDL pcei1, LPCEIPIDL pcei2) { // check only the low for now
if (pcei1->cei.dwSizeLow == pcei2->cei.dwSizeLow) { return 0; } else if (pcei1->cei.dwSizeLow > pcei2->cei.dwSizeLow) { return 1; } return -1; }
HRESULT CCacheFolder::_CompareAlignedIDs(LPARAM lParam, LPCEIPIDL pidl1, LPCEIPIDL pidl2) { int iRet = 0;
if (NULL == pidl1 || NULL == pidl2) return E_INVALIDARG;
// At this point, both pidls have resolved to leaf (history or cache)
if (!IS_VALID_CEIPIDL(pidl1) || !IS_VALID_CEIPIDL(pidl2)) return E_FAIL;
switch (lParam & SHCIDS_COLUMNMASK) { case ICOLC_URL_SHORTNAME: iRet = StrCmpI(_FindURLFileName(CPidlToSourceUrl(pidl1)), _FindURLFileName(CPidlToSourceUrl(pidl2))); break;
case ICOLC_URL_NAME: iRet = _CompareCFolderPidl(pidl1, pidl2); break;
case ICOLC_URL_TYPE: iRet = ualstrcmp(pidl1->szTypeName, pidl2->szTypeName); break;
case ICOLC_URL_SIZE: iRet = _CompareSize(pidl1, pidl2); break;
case ICOLC_URL_MODIFIED: iRet = ULCompareFileTime(&pidl1->cei.LastModifiedTime, &pidl2->cei.LastModifiedTime); break;
case ICOLC_URL_ACCESSED: iRet = ULCompareFileTime(&pidl1->cei.LastAccessTime, &pidl2->cei.LastAccessTime); break;
case ICOLC_URL_EXPIRES: iRet = ULCompareFileTime(&pidl1->cei.ExpireTime, &pidl2->cei.ExpireTime); break;
case ICOLC_URL_LASTSYNCED: iRet = ULCompareFileTime(&pidl1->cei.LastSyncTime, &pidl2->cei.LastSyncTime); break;
default: iRet = -1; } return ResultFromShort((SHORT)iRet); }
HRESULT CCacheFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv) { HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
if (riid == IID_IShellView) { hr = CacheFolderView_CreateInstance(this, ppv); } else if (riid == IID_IContextMenu) { // this creates the "Arrange Icons" cascased menu in the background of folder view
CFolderArrangeMenu *p = new CFolderArrangeMenu(MENU_CACHE); if (p) { hr = p->QueryInterface(riid, ppv); p->Release(); } else hr = E_OUTOFMEMORY; } else if (riid == IID_IShellDetails) { CDetailsOfFolder *p = new CDetailsOfFolder(hwnd, this); if (p) { hr = p->QueryInterface(riid, ppv); p->Release(); } else hr = E_OUTOFMEMORY; }
return hr; }
// Right now, we will allow TIF Drag in Browser Only, even though
// it will not be Zone Checked at the Drop.
//#define BROWSERONLY_NOTIFDRAG
HRESULT CCacheFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG * prgfInOut) { ULONG rgfInOut; HRESULT hr = E_UNEXPECTED;
// Make sure each pidl in the array is dword aligned.
if (apidl && IS_VALID_CEIPIDL(apidl[0])) { BOOL fRealigned; hr = AlignPidlArray(apidl, cidl, &apidl, &fRealigned);
if (SUCCEEDED(hr)) { rgfInOut = SFGAO_FILESYSTEM | SFGAO_CANDELETE | SFGAO_HASPROPSHEET;
#ifdef BROWSERONLY_NOTIFDRAG
if (PLATFORM_INTEGRATED == WhichPlatform()) #endif // BROWSERONLY_NOTIFDRAG
{ SetFlag(rgfInOut, SFGAO_CANCOPY); }
// all items can be deleted
if (SUCCEEDED(hr)) rgfInOut |= SFGAO_CANDELETE; *prgfInOut = rgfInOut;
if (fRealigned) FreeRealignedPidlArray(apidl, cidl); } } else if (_pshfSys) { hr = _pshfSys->GetAttributesOf(cidl, apidl, prgfInOut); }
if (FAILED(hr)) *prgfInOut = 0;
return hr; }
HRESULT CCacheFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, void **ppv) { HRESULT hr = E_NOINTERFACE; *ppv = NULL; // null the out param
// Make sure all pidls in the array are dword aligned.
if (apidl && IS_VALID_CEIPIDL(apidl[0])) { BOOL fRealigned; hr = AlignPidlArray(apidl, cidl, &apidl, &fRealigned);
if (SUCCEEDED(hr)) { if ((riid == IID_IShellLinkA) || (riid == IID_IShellLinkW) || (riid == IID_IExtractIconA) || (riid == IID_IExtractIconW) || (riid == IID_IQueryInfo)) { LPCTSTR pszURL = CPidlToSourceUrl((LPCEIPIDL)apidl[0]);
hr = _GetShortcut(pszURL, riid, ppv); } else if ((riid == IID_IContextMenu) || (riid == IID_IDataObject) || (riid == IID_IExtractIconA) || (riid == IID_IExtractIconW)) { hr = CCacheItem_CreateInstance(this, hwnd, cidl, apidl, riid, ppv); } else { hr = E_FAIL; }
if (fRealigned) FreeRealignedPidlArray(apidl, cidl); } } else if (_pshfSys) { // delegate to the filesystem
hr = _pshfSys->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv); }
return hr; }
HRESULT CCacheFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) { if (pSort) { *pSort = 0; }
if (pDisplay) { *pDisplay = 0; } return S_OK; }
HRESULT CCacheFolder::_GetInfoTip(LPCITEMIDLIST pidl, DWORD dwFlags, WCHAR **ppwszTip) { *ppwszTip = NULL; return E_FAIL; }
HRESULT CCacheFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pstr) { BOOL fRealigned; HRESULT hr = E_FAIL;
if (!IS_VALID_CEIPIDL(pidl)) { if (_pshfSys) { // delegate to the filesystem
hr = _pshfSys->GetDisplayNameOf(pidl, uFlags, pstr); } } else if (SUCCEEDED(AlignPidl(&pidl, &fRealigned))) { hr = GetDisplayNameOfCEI(pidl, uFlags, pstr); if (fRealigned) FreeRealignedPidl(pidl); } return hr; }
HRESULT CCacheFolder::GetDisplayNameOfCEI(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pstr) { TCHAR szTemp[MAX_URL_STRING]; szTemp[0] = 0;
LPCTSTR pszTitle = _FindURLFileName(CEI_SOURCEURLNAME((LPCEIPIDL)pidl));
// _GetURLTitle could return the real title or just an URL.
// We use _URLTitleIsURL to make sure we don't unescape any titles.
if (pszTitle && *pszTitle) { StrCpyN(szTemp, pszTitle, ARRAYSIZE(szTemp)); } else { LPCTSTR pszUrl = _StripHistoryUrlToUrl(CPidlToSourceUrl((LPCEIPIDL)pidl)); if (pszUrl) StrCpyN(szTemp, pszUrl, ARRAYSIZE(szTemp)); } if (!(uFlags & SHGDN_FORPARSING)) { DWORD cchBuf = ARRAYSIZE(szTemp); PrepareURLForDisplayUTF8(szTemp, szTemp, &cchBuf, TRUE); SHELLSTATE ss; SHGetSetSettings(&ss, SSF_SHOWEXTENSIONS, FALSE); if (!ss.fShowExtensions) PathRemoveExtension(szTemp); }
return StringToStrRet(szTemp, pstr); }
HRESULT CCacheFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST *ppidlOut) { if (ppidlOut) *ppidlOut = NULL; // null the out param
return E_FAIL; }
//
// IShellIcon Methods...
//
HRESULT CCacheFolder::GetIconOf(LPCITEMIDLIST pidl, UINT flags, LPINT lpIconIndex) { BOOL fRealigned; HRESULT hr = E_FAIL;
if (!IS_VALID_CEIPIDL(pidl)) { if (_pshfSys) { IShellIcon* pshi; hr = _pshfSys->QueryInterface(IID_PPV_ARG(IShellIcon, &pshi)); if (SUCCEEDED(hr)) { hr = pshi->GetIconOf(pidl, flags, lpIconIndex); pshi->Release(); } } } else if (SUCCEEDED(AlignPidl(&pidl, &fRealigned))) { SHFILEINFO shfi; LPCTSTR pszIconFile = CEI_LOCALFILENAME((LPCEIPIDL)pidl);
if (SHGetFileInfo(pszIconFile, 0, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON)) { *lpIconIndex = shfi.iIcon; hr = S_OK; }
if (fRealigned) FreeRealignedPidl(pidl); } return hr; }
// IPersist
HRESULT CCacheFolder::Initialize(LPCITEMIDLIST pidlInit) { ILFree(_pidl); if (_pshfSys) { _pshfSys->Release(); _pshfSys = NULL; }
HRESULT hr; if (IsCSIDLFolder(CSIDL_INTERNET_CACHE, pidlInit)) { hr = SHILClone(pidlInit, &_pidl); if (SUCCEEDED(hr)) { hr = _GetFileSysFolder(&_pshfSys);
// On a pre-Win2k shell, CLSID_ShellFSFolder will not be registered. However, it does not
// impact the operation of the cache folder. So rather than propogate a failure return value to
// the shell, we treat that case as success.
if (FAILED(hr)) { // This is a pre-Win2k shell. Return S_OK.
hr = S_OK; } } } else { hr = E_FAIL; } return hr; }
//
// IPersistFolder2 Methods...
//
HRESULT CCacheFolder::GetCurFolder(LPITEMIDLIST *ppidl) { if (_pidl) return SHILClone(_pidl, ppidl);
*ppidl = NULL; return S_FALSE; // success but empty
}
void _GetFileTypeInternal(LPCEIPIDL pidl, LPUTSTR pszuStr, UINT cchStr) { SHFILEINFO shInfo; LPTSTR pszStr = NULL;
if (TSTR_ALIGNED(pszuStr) == FALSE) { //
// If pszuStr is in fact unaligned, allocate some scratch
// space on the heap for the output copy of this string.
//
pszStr = (LPTSTR)LocalAlloc(LPTR, cchStr * sizeof(TCHAR)); } else { pszStr = (LPTSTR)pszuStr; }
if (pszStr) { if (SHGetFileInfo(CEI_LOCALFILENAME((LPCEIPIDL)pidl), FILE_ATTRIBUTE_NORMAL, &shInfo, sizeof(shInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME) && shInfo.szTypeName[0]) { StrCpyN(pszStr, shInfo.szTypeName, cchStr); } else { LPTSTR psz = PathFindExtension(CEI_LOCALFILENAME((LPCEIPIDL)pidl)); DWORD dw; ASSERT((pszStr && (cchStr>0))); *pszStr = 0; if (psz && *psz) { psz++; StrCpyN(pszStr, psz, cchStr); CharUpper(pszStr); StrCatBuff(pszStr, TEXT(" "), cchStr); } dw = lstrlen(pszStr); MLLoadString(IDS_FILE_TYPE, pszStr+dw, cchStr-dw); }
if (TSTR_ALIGNED(pszuStr) == FALSE) { // If pszuStr was unaligned then copy the output string from
// the scratch space on the heap to the supplied output buffer
ualstrcpyn(pszuStr, pszStr, cchStr); LocalFree(pszStr); } } }
|