1163 lines
29 KiB
C++
1163 lines
29 KiB
C++
#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 dwSize, LPINTERNET_CACHE_ENTRY_INFO pcei)
|
|
{
|
|
|
|
DWORD dwTotalSize = 0;
|
|
dwTotalSize = sizeof(CEIPIDL) + dwSize - sizeof(INTERNET_CACHE_ENTRY_INFO);
|
|
|
|
#if defined(UNIX)
|
|
dwTotalSize = ALIGN4(dwTotalSize);
|
|
#endif
|
|
|
|
LPCEIPIDL pceip = (LPCEIPIDL)OleAlloc(dwTotalSize);
|
|
if (pceip)
|
|
{
|
|
memset(pceip, 0, dwTotalSize);
|
|
pceip->cb = (USHORT)(dwTotalSize - sizeof(USHORT));
|
|
pceip->usSign = CEIPIDL_SIGN;
|
|
_CopyCEI(&pceip->cei, pcei, dwSize);
|
|
}
|
|
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)
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// 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()
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// 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;
|
|
|
|
if (TSTR_ALIGNED(pszuStr) == FALSE)
|
|
{
|
|
//
|
|
// If pszuStr is in fact unaligned, allocate some scratch
|
|
// space on the stack for the output copy of this string.
|
|
//
|
|
|
|
pszStr = (LPTSTR)_alloca(cchStr * sizeof(TCHAR));
|
|
}
|
|
else
|
|
{
|
|
pszStr = (LPTSTR)pszuStr;
|
|
}
|
|
|
|
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 stack to the supplied output buffer
|
|
|
|
ualstrcpyn(pszuStr, pszStr, cchStr);
|
|
}
|
|
}
|