1184 lines
29 KiB
C++
1184 lines
29 KiB
C++
#include "private.h"
|
|
#include "offl_cpp.h"
|
|
#include <htmlhelp.h>
|
|
#include <shdocvw.h>
|
|
|
|
#include <mluisupp.h>
|
|
|
|
// {F5175861-2688-11d0-9C5E-00AA00A45957}
|
|
const GUID CLSID_OfflineFolder =
|
|
{ 0xf5175861, 0x2688, 0x11d0, { 0x9c, 0x5e, 0x0, 0xaa, 0x0, 0xa4, 0x59, 0x57 } };
|
|
|
|
// {F5175860-2688-11d0-9C5E-00AA00A45957}
|
|
const GUID IID_IOfflineObject =
|
|
{ 0xf5175860, 0x2688, 0x11d0, { 0x9c, 0x5e, 0x0, 0xaa, 0x0, 0xa4, 0x59, 0x57 } };
|
|
|
|
// Column definition for the Cache Folder DefView
|
|
|
|
ColInfoType s_AllItems_cols[] = {
|
|
{ICOLC_SHORTNAME, IDS_NAME_COL, 20, LVCFMT_LEFT},
|
|
{ICOLC_LAST, IDS_LAST_COL, 14, LVCFMT_LEFT},
|
|
{ICOLC_STATUS, IDS_STATUS_COL, 14, LVCFMT_LEFT},
|
|
{ICOLC_URL, IDS_URL_COL, 20, LVCFMT_LEFT},
|
|
{ICOLC_ACTUALSIZE, IDS_SIZE_COL, 10, LVCFMT_LEFT}};
|
|
|
|
ColInfoType * colInfo = s_AllItems_cols;
|
|
|
|
LPMYPIDL _CreateFolderPidl(IMalloc *pmalloc, DWORD dwSize);
|
|
|
|
HRESULT OfflineFolderView_InitMenuPopup(HWND hwnd, UINT idCmdFirst, int nIndex, HMENU hMenu)
|
|
{
|
|
UINT platform = WhichPlatform();
|
|
|
|
if (platform != PLATFORM_INTEGRATED) {
|
|
MENUITEMINFO mInfo = {0};
|
|
mInfo.cbSize = sizeof(MENUITEMINFO);
|
|
mInfo.fMask = MIIM_STATE;
|
|
if (IsGlobalOffline()) {
|
|
mInfo.fState = MFS_CHECKED;
|
|
} else {
|
|
mInfo.fState = MFS_UNCHECKED;
|
|
}
|
|
SetMenuItemInfo(hMenu, RSVIDM_WORKOFFLINE + idCmdFirst, FALSE, &mInfo);
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT OfflineFolderView_MergeMenu(LPQCMINFO pqcm)
|
|
{
|
|
HMENU hmenu = NULL;
|
|
UINT platform = WhichPlatform();
|
|
|
|
if (platform == PLATFORM_INTEGRATED) {
|
|
hmenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MENU_OFFLINE_TOP));
|
|
} else {
|
|
hmenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(MENU_OFFLINE_BRONLY));
|
|
}
|
|
|
|
if (hmenu)
|
|
{
|
|
MergeMenuHierarchy(pqcm->hmenu, hmenu, pqcm->idCmdFirst, pqcm->idCmdLast, TRUE);
|
|
DestroyMenu(hmenu);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
extern HRESULT CancelAllDownloads();
|
|
|
|
HRESULT OfflineFolderView_Command(HWND hwnd, UINT uID)
|
|
{
|
|
switch (uID) {
|
|
case RSVIDM_SORTBYNAME:
|
|
ShellFolderView_ReArrange(hwnd, ICOLC_SHORTNAME);
|
|
break;
|
|
case RSVIDM_UPDATEALL:
|
|
SendUpdateRequests(hwnd, NULL, 0);
|
|
break;
|
|
case RSVIDM_WORKOFFLINE:
|
|
SetGlobalOffline(!IsGlobalOffline());
|
|
break;
|
|
case RSVIDM_HELP:
|
|
SHHtmlHelpOnDemandWrap(hwnd, TEXT("iexplore.chm > iedefault"), 0, (DWORD_PTR) TEXT("subs_upd.htm"), ML_CROSSCODEPAGE);
|
|
break;
|
|
|
|
case RSVIDM_UPDATE:
|
|
{
|
|
LPMYPIDL * pidlsSel = NULL;
|
|
UINT count = 0;
|
|
|
|
count = (UINT) ShellFolderView_GetSelectedObjects
|
|
(hwnd, (LPITEMIDLIST*) &pidlsSel);
|
|
|
|
if ((!pidlsSel) || !count)
|
|
break;
|
|
|
|
CLSID * cookies = (CLSID *)MemAlloc(LPTR, count * sizeof(CLSID));
|
|
UINT validCount = 0;
|
|
|
|
if (cookies)
|
|
{
|
|
for (UINT i = 0; i < count; i ++) {
|
|
if (IS_VALID_MYPIDL(pidlsSel[i]))
|
|
cookies[validCount++] = pidlsSel[i]->ooe.m_Cookie;
|
|
}
|
|
|
|
if (validCount)
|
|
SendUpdateRequests(hwnd, cookies, validCount);
|
|
|
|
MemFree(cookies);
|
|
cookies = NULL;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
// We should make this a generic function for all types of items, even
|
|
// for the third party items they should support these properties.
|
|
|
|
HRESULT Generic_GetDetails(PDETAILSINFO pdi, UINT iColumn)
|
|
{
|
|
LPMYPIDL pooi = (LPMYPIDL)pdi->pidl;
|
|
POOEntry pooe = NULL;
|
|
TCHAR timeSTR[128];
|
|
|
|
pdi->str.uType = STRRET_CSTR;
|
|
pdi->str.cStr[0] = '\0';
|
|
|
|
pooe = &(pooi->ooe);
|
|
switch (iColumn)
|
|
{
|
|
case ICOLC_SHORTNAME:
|
|
SHTCharToAnsi(NAME(pooe), pdi->str.cStr, sizeof(pdi->str.cStr));
|
|
break;
|
|
case ICOLC_URL:
|
|
SHTCharToAnsi(URL(pooe), pdi->str.cStr, sizeof(pdi->str.cStr));
|
|
break;
|
|
case ICOLC_LAST:
|
|
DATE2DateTimeString(pooe->m_LastUpdated, timeSTR);
|
|
SHTCharToAnsi(timeSTR, pdi->str.cStr, sizeof(pdi->str.cStr));
|
|
break;
|
|
case ICOLC_STATUS:
|
|
SHTCharToAnsi(STATUS(pooe), pdi->str.cStr, sizeof(pdi->str.cStr));
|
|
break;
|
|
case ICOLC_ACTUALSIZE:
|
|
StrFormatByteSizeA(pooe->m_ActualSize * 1024, pdi->str.cStr, sizeof(pdi->str.cStr));
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT OfflineFolderView_OnGetDetailsOf(HWND hwnd, UINT iColumn, PDETAILSINFO pdi)
|
|
{
|
|
LPMYPIDL pooi = (LPMYPIDL)pdi->pidl;
|
|
|
|
if (iColumn > ICOLC_ACTUALSIZE)
|
|
return E_NOTIMPL;
|
|
|
|
if (!pooi)
|
|
{
|
|
pdi->str.uType = STRRET_CSTR;
|
|
pdi->str.cStr[0] = '\0';
|
|
MLLoadStringA(colInfo[iColumn].ids, pdi->str.cStr, sizeof(pdi->str.cStr));
|
|
pdi->fmt = colInfo[iColumn].iFmt;
|
|
pdi->cxChar = colInfo[iColumn].cchCol;
|
|
return S_OK;
|
|
}
|
|
|
|
UINT colId = colInfo[iColumn].iCol;
|
|
return Generic_GetDetails(pdi, colId);
|
|
}
|
|
|
|
HRESULT OfflineFolderView_OnColumnClick(HWND hwnd, UINT iColumn)
|
|
{
|
|
ShellFolderView_ReArrange(hwnd, colInfo[iColumn].iCol);
|
|
return NOERROR;
|
|
}
|
|
|
|
const TBBUTTON c_tbOffline[] = {
|
|
{ 0, RSVIDM_UPDATE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
|
|
{ 1, RSVIDM_UPDATEALL, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0L, -1 },
|
|
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP , {0,0}, 0L, -1 },
|
|
};
|
|
|
|
HRESULT OfflineFolderView_OnGetButtons(HWND hwnd, UINT idCmdFirst, LPTBBUTTON ptButton)
|
|
{
|
|
UINT i;
|
|
LONG_PTR iBtnOffset;
|
|
IShellBrowser * psb = FileCabinet_GetIShellBrowser(hwnd);
|
|
TBADDBITMAP ab;
|
|
|
|
// add the toolbar button bitmap, get it's offset
|
|
ab.hInst =g_hInst;
|
|
ab.nID = IDB_TB_SMALL; // std bitmaps
|
|
psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 2, (LPARAM)&ab, &iBtnOffset);
|
|
|
|
for (i = 0; i < ARRAYSIZE(c_tbOffline); i++)
|
|
{
|
|
ptButton[i] = c_tbOffline[i];
|
|
|
|
if (!(c_tbOffline[i].fsStyle & TBSTYLE_SEP))
|
|
{
|
|
ptButton[i].idCommand += idCmdFirst;
|
|
ptButton[i].iBitmap += (int)iBtnOffset;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT OfflineFolderView_OnGetButtonInfo(TBINFO * ptbInfo)
|
|
{
|
|
ptbInfo->uFlags = TBIF_PREPEND;
|
|
ptbInfo->cbuttons = ARRAYSIZE(c_tbOffline);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT OfflineFolderView_DidDragDrop(HWND hwnd,IDataObject *pdo,DWORD dwEffect)
|
|
{
|
|
if ((dwEffect & (DROPEFFECT_MOVE |DROPEFFECT_COPY)) == DROPEFFECT_MOVE)
|
|
{
|
|
COfflineObjectItem *pOOItem;
|
|
|
|
if (SUCCEEDED(pdo->QueryInterface(IID_IOfflineObject, (void **)&pOOItem)))
|
|
{
|
|
BOOL fDel = ConfirmDelete(hwnd, pOOItem->_cItems, pOOItem->_ppooi);
|
|
if (!fDel) {
|
|
pOOItem->Release();
|
|
return S_FALSE;
|
|
}
|
|
|
|
for (UINT i = 0; i < pOOItem->_cItems; i++)
|
|
{
|
|
if (SUCCEEDED(DoDeleteSubscription(&(pOOItem->_ppooi[i]->ooe)))) {
|
|
_GenerateEvent(SHCNE_DELETE,
|
|
(LPITEMIDLIST)pOOItem->_ppooi[i],
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
pOOItem->Release();
|
|
return S_OK;
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CALLBACK OfflineFolderView_ViewCallback(
|
|
IShellView *psvOuter,
|
|
IShellFolder *psf,
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
HRESULT hres = NOERROR;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case DVM_GETHELPTEXT:
|
|
case DVM_GETTOOLTIPTEXT:
|
|
{
|
|
UINT id = LOWORD(wParam);
|
|
UINT cchBuf = HIWORD(wParam);
|
|
if (g_fIsWinNT)
|
|
{
|
|
WCHAR * pszBuf = (WCHAR *)lParam;
|
|
MLLoadStringW(id + IDS_SB_FIRST, pszBuf, cchBuf);
|
|
}
|
|
else
|
|
{
|
|
CHAR * pszBuf = (CHAR *)lParam;
|
|
MLLoadStringA(id + IDS_SB_FIRST, pszBuf, cchBuf);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DVM_DIDDRAGDROP:
|
|
hres = OfflineFolderView_DidDragDrop(hwnd,(IDataObject *)lParam,(DWORD)wParam);
|
|
break;
|
|
|
|
case DVM_INITMENUPOPUP:
|
|
hres = OfflineFolderView_InitMenuPopup(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
|
|
break;
|
|
|
|
case DVM_INVOKECOMMAND:
|
|
OfflineFolderView_Command(hwnd, (UINT)wParam);
|
|
break;
|
|
|
|
case DVM_COLUMNCLICK:
|
|
hres = OfflineFolderView_OnColumnClick(hwnd, (UINT)wParam);
|
|
break;
|
|
|
|
case DVM_GETDETAILSOF:
|
|
hres = OfflineFolderView_OnGetDetailsOf(hwnd, (UINT)wParam, (PDETAILSINFO)lParam);
|
|
break;
|
|
|
|
case DVM_MERGEMENU:
|
|
hres = OfflineFolderView_MergeMenu((LPQCMINFO)lParam);
|
|
break;
|
|
|
|
case DVM_DEFVIEWMODE:
|
|
*(FOLDERVIEWMODE *)lParam = FVM_DETAILS;
|
|
break;
|
|
|
|
case DVM_GETBUTTONINFO:
|
|
hres = OfflineFolderView_OnGetButtonInfo((TBINFO *)lParam);
|
|
break;
|
|
|
|
case DVM_GETBUTTONS:
|
|
hres = OfflineFolderView_OnGetButtons(hwnd, LOWORD(wParam), (TBBUTTON *)lParam);
|
|
break;
|
|
|
|
default:
|
|
hres = E_FAIL;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT OfflineFolderView_CreateInstance(COfflineFolder *pOOFolder, LPCITEMIDLIST pidl, void **ppvOut)
|
|
{
|
|
CSFV csfv;
|
|
|
|
csfv.cbSize = sizeof(csfv);
|
|
csfv.pshf = (IShellFolder *)pOOFolder;
|
|
csfv.psvOuter = NULL;
|
|
csfv.pidl = pidl;
|
|
csfv.lEvents = SHCNE_DELETE | SHCNE_CREATE | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM | SHCNE_UPDATEDIR;
|
|
csfv.pfnCallback = OfflineFolderView_ViewCallback;
|
|
csfv.fvm = (FOLDERVIEWMODE)0; // Have defview restore the folder view mode
|
|
|
|
return SHCreateShellFolderViewEx(&csfv, (IShellView**)ppvOut); // &this->psv);
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// COfflineFolderEnum Object
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
COfflineFolderEnum::COfflineFolderEnum(DWORD grfFlags)
|
|
{
|
|
TraceMsg(TF_SUBSFOLDER, "hcfe - COfflineFolderEnum() called");
|
|
|
|
m_cRef = 1;
|
|
DllAddRef();
|
|
|
|
m_grfFlags = grfFlags;
|
|
}
|
|
|
|
IMalloc *COfflineFolderEnum::s_pMalloc = NULL;
|
|
|
|
void COfflineFolderEnum::EnsureMalloc()
|
|
{
|
|
if (NULL == s_pMalloc)
|
|
{
|
|
SHGetMalloc(&s_pMalloc);
|
|
}
|
|
|
|
ASSERT(NULL != s_pMalloc);
|
|
}
|
|
|
|
|
|
COfflineFolderEnum::~COfflineFolderEnum()
|
|
{
|
|
ASSERT(m_cRef == 0); // we should always have a zero ref count here
|
|
|
|
SAFERELEASE(m_pFolder);
|
|
SAFEDELETE(m_pCookies);
|
|
|
|
TraceMsg(TF_SUBSFOLDER, "hcfe - ~COfflineFolderEnum() called.");
|
|
DllRelease();
|
|
}
|
|
|
|
HRESULT COfflineFolderEnum::Initialize(COfflineFolder *pFolder)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(pFolder);
|
|
|
|
if (NULL != pFolder)
|
|
{
|
|
m_pFolder = pFolder;
|
|
m_pFolder->AddRef();
|
|
|
|
hr = CoInitialize(NULL);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ISubscriptionMgr2 *pSubsMgr2;
|
|
hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_ISubscriptionMgr2, (void **)&pSubsMgr2);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IEnumSubscription *pes;
|
|
|
|
hr = pSubsMgr2->EnumSubscriptions(0, &pes);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pes->GetCount(&m_nCount);
|
|
|
|
if (m_nCount > 0)
|
|
{
|
|
m_pCookies = new SUBSCRIPTIONCOOKIE[m_nCount];
|
|
|
|
if (NULL != m_pCookies)
|
|
{
|
|
hr = pes->Next(m_nCount, m_pCookies, &m_nCount);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
pes->Release();
|
|
}
|
|
pSubsMgr2->Release();
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COfflineFolderEnum_CreateInstance(DWORD grfFlags, COfflineFolder *pFolder,
|
|
LPENUMIDLIST *ppeidl)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppeidl = NULL;
|
|
|
|
COfflineFolderEnum *pOOFE = new COfflineFolderEnum(grfFlags);
|
|
|
|
if (NULL != pOOFE)
|
|
{
|
|
hr = pOOFE->Initialize(pFolder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppeidl = pOOFE;
|
|
}
|
|
else
|
|
{
|
|
pOOFE->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IUnknown Methods...
|
|
//
|
|
|
|
HRESULT COfflineFolderEnum::QueryInterface(REFIID iid,void **ppv)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "COfflineFolderEnum - QI called.");
|
|
|
|
if ((iid == IID_IEnumIDList) || (iid == IID_IUnknown))
|
|
{
|
|
*ppv = (IEnumIDList *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG COfflineFolderEnum::AddRef(void)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
ULONG COfflineFolderEnum::Release(void)
|
|
{
|
|
if (0L != --m_cRef)
|
|
return m_cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
LPMYPIDL COfflineFolderEnum::NewPidl(DWORD dwSize)
|
|
{
|
|
LPMYPIDL pidl;
|
|
|
|
// TraceMsg(TF_MEMORY, "NewPidl called");
|
|
|
|
EnsureMalloc();
|
|
|
|
pidl = _CreateFolderPidl(s_pMalloc, dwSize);
|
|
|
|
// TraceMsg(TF_MEMORY, "\tNewPidl returned with 0x%x", pidl);
|
|
|
|
return pidl;
|
|
}
|
|
|
|
void COfflineFolderEnum::FreePidl(LPMYPIDL pidl)
|
|
{
|
|
ASSERT(NULL != pidl);
|
|
|
|
// TraceMsg(TF_MEMORY, "FreePidl on (0x%x) called", pidl);
|
|
|
|
EnsureMalloc();
|
|
|
|
s_pMalloc->Free(pidl);
|
|
}
|
|
|
|
// IEnumIDList Methods
|
|
|
|
HRESULT COfflineFolderEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG nCopied;
|
|
DWORD dwBuffSize;
|
|
OOEBuf ooeBuf;
|
|
|
|
if ((0 == celt) ||
|
|
((celt > 1) && (NULL == pceltFetched)) ||
|
|
(NULL == rgelt))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
memset(&ooeBuf, 0, sizeof(ooeBuf));
|
|
|
|
for (nCopied = 0; (S_OK == hr) && (m_nCurrent < m_nCount) && (nCopied < celt);
|
|
m_nCurrent++, nCopied++)
|
|
{
|
|
rgelt[nCopied] = NULL;
|
|
hr = LoadOOEntryInfo(&ooeBuf, &m_pCookies[m_nCurrent], &dwBuffSize);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (IsNativeAgent(ooeBuf.clsidDest))
|
|
{
|
|
CLSID cookie;
|
|
HRESULT hrTmp = ReadCookieFromInetDB(ooeBuf.m_URL, &cookie);
|
|
if (S_OK != hrTmp)
|
|
{
|
|
hrTmp = WriteCookieToInetDB(ooeBuf.m_URL,&(ooeBuf.m_Cookie), FALSE);
|
|
ASSERT(SUCCEEDED(hrTmp));
|
|
}
|
|
}
|
|
|
|
LPMYPIDL pooi = NewPidl(dwBuffSize);
|
|
if (pooi)
|
|
{
|
|
CopyToMyPooe(&ooeBuf, &(pooi->ooe)); // Always succeeds!
|
|
rgelt[nCopied] = (LPITEMIDLIST)pooi;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = (celt == nCopied) ? S_OK : S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
for (ULONG i = 0; i < nCopied; i++)
|
|
{
|
|
FreePidl((LPMYPIDL)rgelt[i]);
|
|
}
|
|
}
|
|
|
|
if (NULL != pceltFetched)
|
|
{
|
|
*pceltFetched = SUCCEEDED(hr) ? nCopied : 0;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COfflineFolderEnum::Skip(ULONG celt)
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_nCurrent += celt;
|
|
|
|
if (m_nCurrent > (m_nCount - 1))
|
|
{
|
|
m_nCurrent = m_nCount; // Passed the last one
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT COfflineFolderEnum::Reset()
|
|
{
|
|
m_nCurrent = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT COfflineFolderEnum::Clone(IEnumIDList **ppenum)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// COfflineFolder Object
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
COfflineFolder::COfflineFolder(void)
|
|
{
|
|
TraceMsg(TF_SUBSFOLDER, "Folder - COfflineFolder() called.");
|
|
_cRef = 1;
|
|
viewMode = 0;
|
|
colInfo = s_AllItems_cols;
|
|
DllAddRef();
|
|
}
|
|
|
|
COfflineFolder::~COfflineFolder()
|
|
{
|
|
Assert(_cRef == 0); // should always have zero
|
|
TraceMsg(TF_SUBSFOLDER, "Folder - ~COfflineFolder() called.");
|
|
|
|
if (_pidl)
|
|
ILFree(_pidl);
|
|
|
|
DllRelease();
|
|
}
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IUnknown Methods...
|
|
//
|
|
HRESULT COfflineFolder::QueryInterface(REFIID iid, void **ppvObj)
|
|
{
|
|
*ppvObj = NULL; // null the out param
|
|
|
|
if (iid == IID_IUnknown) {
|
|
*ppvObj = (void *)this;
|
|
}
|
|
else if (iid == IID_IShellFolder) {
|
|
*ppvObj = (void *)(IShellFolder *)this;
|
|
}
|
|
else if ((iid == IID_IPersistFolder) || (iid == IID_IPersist) || (iid == IID_IPersistFolder2)) {
|
|
*ppvObj = (void *)(IPersistFolder *)this;
|
|
}
|
|
else if (iid == IID_IContextMenu)
|
|
{
|
|
*ppvObj = (void *)(IContextMenu *)this;
|
|
}
|
|
else if (iid == IID_IShellView)
|
|
{
|
|
return OfflineFolderView_CreateInstance(this, _pidl, ppvObj);
|
|
}
|
|
else if (iid == IID_IOfflineObject)
|
|
{
|
|
*ppvObj = (void *)this;
|
|
}
|
|
else if (iid == IID_IDropTarget)
|
|
{
|
|
// APPCOMPAT: Implementation of IDropTarget didn't follow the COM rules.
|
|
// We create following object by aggregattion but QI on it for IUnknown
|
|
// won't get us ptr THIS.
|
|
COfflineDropTarget * podt = new COfflineDropTarget(GetDesktopWindow());
|
|
if (podt)
|
|
{
|
|
HRESULT hr = podt->QueryInterface(iid, ppvObj);
|
|
podt->Release();
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (*ppvObj)
|
|
{
|
|
((IUnknown *)*ppvObj)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG COfflineFolder::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
ULONG COfflineFolder::Release()
|
|
{
|
|
if (0L != --_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IShellFolder methods...
|
|
//
|
|
HRESULT COfflineFolder::ParseDisplayName(HWND hwndOwner, LPBC pbcReserved,
|
|
LPOLESTR lpszDisplayName, ULONG *pchEaten,
|
|
LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - ParseDisplayName.");
|
|
*ppidl = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT COfflineFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags,
|
|
LPENUMIDLIST *ppenumIDList)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - EnumObjects.");
|
|
return COfflineFolderEnum_CreateInstance(grfFlags, this, ppenumIDList);
|
|
}
|
|
|
|
|
|
HRESULT COfflineFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
|
|
REFIID riid, void **ppvOut)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - BindToObject.");
|
|
*ppvOut = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT COfflineFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
|
|
REFIID riid, void **ppvObj)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - BindToStorage.");
|
|
*ppvObj = NULL;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT COfflineFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
|
{
|
|
int iRet;
|
|
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - CompareIDs(%d).", lParam);
|
|
|
|
if (!IS_VALID_MYPIDL(pidl1) || !IS_VALID_MYPIDL(pidl2))
|
|
return E_FAIL;
|
|
|
|
switch (lParam) {
|
|
case ICOLC_SHORTNAME:
|
|
iRet = _CompareShortName((LPMYPIDL)pidl1, (LPMYPIDL)pidl2);
|
|
break;
|
|
case ICOLC_URL:
|
|
iRet = _CompareURL((LPMYPIDL)pidl1, (LPMYPIDL)pidl2);
|
|
break;
|
|
case ICOLC_STATUS:
|
|
iRet = _CompareStatus((LPMYPIDL)pidl1, (LPMYPIDL)pidl2);
|
|
break;
|
|
case ICOLC_LAST:
|
|
iRet = _CompareLastUpdate((LPMYPIDL)pidl1, (LPMYPIDL)pidl2);
|
|
break;
|
|
case ICOLC_ACTUALSIZE:
|
|
iRet = (((LPMYPIDL)pidl1)->ooe.m_ActualSize - ((LPMYPIDL)pidl2)->ooe.m_ActualSize);
|
|
break;
|
|
default:
|
|
iRet = -1;
|
|
break;
|
|
}
|
|
return ResultFromShort((SHORT)iRet);
|
|
}
|
|
|
|
|
|
HRESULT COfflineFolder::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - CreateViewObject() called.");
|
|
|
|
if (riid == IID_IShellView)
|
|
{
|
|
hres = OfflineFolderView_CreateInstance(this, _pidl, ppvOut);
|
|
}
|
|
else if (riid == IID_IContextMenu)
|
|
{
|
|
COfflineFolder * pof = new COfflineFolder();
|
|
|
|
if (pof)
|
|
{
|
|
hres = pof->Initialize(this->_pidl);
|
|
if (SUCCEEDED(hres))
|
|
hres = pof->QueryInterface(riid, ppvOut);
|
|
pof->Release();
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else if (riid == IID_IDropTarget)
|
|
{
|
|
COfflineDropTarget * podt = new COfflineDropTarget(hwndOwner);
|
|
|
|
if (podt)
|
|
{
|
|
hres = podt->QueryInterface(riid, ppvOut);
|
|
podt->Release();
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else if (riid == IID_IShellDetails)
|
|
{
|
|
COfflineDetails *pod = new COfflineDetails(hwndOwner);
|
|
if (NULL != pod)
|
|
{
|
|
hres = pod->QueryInterface(IID_IShellDetails, ppvOut);
|
|
pod->Release();
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGIID("COfflineFolder::CreateViewObject() failed", riid);
|
|
*ppvOut = NULL; // null the out param
|
|
hres = E_NOINTERFACE;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT COfflineFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
|
|
ULONG * prgfInOut)
|
|
{
|
|
// Should we initialize this for each item in here? In other words,
|
|
// if cidl > 1, then we should initialize each entry in the prgInOut array
|
|
Assert( cidl == 1 );
|
|
|
|
UINT attr = SFGAO_CANCOPY | SFGAO_CANDELETE | SFGAO_CANRENAME |
|
|
SFGAO_HASPROPSHEET;
|
|
*prgfInOut = attr;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT COfflineFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
|
REFIID riid, UINT * prgfInOut, void **ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:ISF - GetUIObjectOf.");
|
|
if ((riid == IID_IContextMenu) || (riid == IID_IDataObject) ||
|
|
(riid == IID_IExtractIcon) || (riid == IID_IQueryInfo))
|
|
{
|
|
hres = COfflineObjectItem_CreateInstance(this, cidl, apidl, riid, ppvOut);
|
|
}
|
|
else if (riid == IID_IDropTarget)
|
|
{
|
|
hres = CreateViewObject(hwndOwner, IID_IDropTarget, ppvOut);
|
|
}
|
|
else
|
|
{
|
|
*ppvOut = NULL;
|
|
hres = E_FAIL;
|
|
DBGIID("Unsupported interface in COfflineFolder::GetUIObjectOf()", riid);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT COfflineFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "Folde:ISF - GetDisplayNameOf.");
|
|
|
|
if (!IS_VALID_MYPIDL(pidl))
|
|
{
|
|
lpName->uType = 0;
|
|
return E_FAIL;
|
|
}
|
|
|
|
lpName->uType = STRRET_CSTR;
|
|
lpName->cStr[0] = '\0';
|
|
|
|
PCTSTR pszNameLocal;
|
|
LPTSTR szNameUnaligned = NAME(&(((LPMYPIDL)pidl)->ooe));
|
|
|
|
TSTR_ALIGNED_STACK_COPY( &pszNameLocal, szNameUnaligned );
|
|
|
|
SHTCharToAnsi( pszNameLocal, lpName->cStr, ARRAYSIZE(lpName->cStr) );
|
|
|
|
TraceMsg(TF_ALWAYS, "COfflineFolder::GetDisplayNameOf() - pszNameLocal='%s'", pszNameLocal );
|
|
|
|
TraceMsg(TF_ALWAYS, "COfflineFolder::GetDisplayNameOf() - lpName->cStr='%S'", lpName->cStr );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT COfflineFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
|
|
LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST * ppidlOut)
|
|
{
|
|
OOEBuf ooeBuf;
|
|
POOEntry pooe = NULL;
|
|
// TraceMsg(TF_SUBSFOLDER, "Folde:ISF - SetNameOf.");
|
|
|
|
if (ppidlOut) {
|
|
*ppidlOut = NULL; // null the out param
|
|
}
|
|
|
|
if (!IS_VALID_MYPIDL(pidl))
|
|
return E_FAIL;
|
|
|
|
HRESULT hr;
|
|
WCHAR szTempName[MAX_PATH];
|
|
|
|
ASSERT(lpszName);
|
|
|
|
StrCpyNW(szTempName, lpszName, ARRAYSIZE(szTempName));
|
|
|
|
PathRemoveBlanks(szTempName);
|
|
|
|
if (szTempName[0])
|
|
{
|
|
memset(&ooeBuf, 0, sizeof(ooeBuf));
|
|
|
|
pooe = &(((LPMYPIDL)pidl)->ooe);
|
|
CopyToOOEBuf(pooe, &ooeBuf);
|
|
MyOleStrToStrN(ooeBuf.m_Name, MAX_NAME, szTempName);
|
|
|
|
ooeBuf.dwFlags = PROP_WEBCRAWL_NAME;
|
|
hr = SaveBufferChange(&ooeBuf, FALSE);
|
|
|
|
if (ppidlOut) {
|
|
DWORD dwSize = BufferSize(&ooeBuf);
|
|
*ppidlOut = (LPITEMIDLIST)COfflineFolderEnum::NewPidl(dwSize);
|
|
if (*ppidlOut) {
|
|
pooe = &(((LPMYPIDL)(*ppidlOut))->ooe);
|
|
CopyToMyPooe(&ooeBuf, pooe);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WCMessageBox(hwndOwner, IDS_NONULLNAME, IDS_RENAME, MB_OK | MB_ICONSTOP);
|
|
hr = E_FAIL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IPersistFolder Methods...
|
|
//
|
|
HRESULT COfflineFolder::GetClassID(LPCLSID lpClassID)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "hcf - pf - GetClassID.");
|
|
|
|
*lpClassID = CLSID_OfflineFolder;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT COfflineFolder::Initialize(LPCITEMIDLIST pidlInit)
|
|
{
|
|
if (_pidl)
|
|
ILFree(_pidl);
|
|
|
|
_pidl = ILClone(pidlInit);
|
|
|
|
if (!_pidl)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT COfflineFolder::GetCurFolder(LPITEMIDLIST *ppidl)
|
|
{
|
|
if (_pidl)
|
|
{
|
|
*ppidl = ILClone(_pidl);
|
|
return *ppidl ? NOERROR : E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppidl = NULL;
|
|
return S_FALSE; // success but empty
|
|
}
|
|
|
|
//////////////////////////////////
|
|
//
|
|
// IContextMenu Methods...
|
|
//
|
|
HRESULT COfflineFolder::QueryContextMenu
|
|
(
|
|
HMENU hmenu,
|
|
UINT indexMenu,
|
|
UINT idCmdFirst,
|
|
UINT idCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
USHORT cItems = 0;
|
|
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:IContextMenu- QueryContextMenu.");
|
|
if (uFlags == CMF_NORMAL)
|
|
{
|
|
HMENU hmenuHist = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(CONTEXT_MENU_OFFLINE));
|
|
if (hmenuHist)
|
|
{
|
|
cItems = (USHORT) MergeMenuHierarchy(hmenu, hmenuHist, idCmdFirst, idCmdLast, TRUE);
|
|
|
|
DestroyMenu(hmenuHist);
|
|
}
|
|
}
|
|
|
|
return ResultFromShort(cItems); // number of menu items
|
|
}
|
|
|
|
STDMETHODIMP COfflineFolder::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
|
{
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:IContextMenu - InvokeCommand.");
|
|
|
|
int idCmd = _GetCmdID(pici->lpVerb);
|
|
|
|
if (idCmd != RSVIDM_PASTE)
|
|
return OfflineFolderView_Command(pici->hwnd, idCmd);
|
|
|
|
IDataObject * dataSrc = NULL;
|
|
IDropTarget * pDropTrgt = NULL;
|
|
HRESULT hr;
|
|
|
|
hr = OleGetClipboard(&(dataSrc));
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = this->QueryInterface(IID_IDropTarget, (void **) &pDropTrgt);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
DWORD dwPrefEffect = DROPEFFECT_COPY;
|
|
POINTL pt = {0, 0};
|
|
|
|
hr = pDropTrgt->DragEnter(dataSrc, 0/*keystate*/, pt, &dwPrefEffect);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pDropTrgt->Drop(dataSrc, 0, pt, &dwPrefEffect);
|
|
}
|
|
}
|
|
|
|
if (dataSrc)
|
|
SAFERELEASE(dataSrc);
|
|
if (pDropTrgt)
|
|
SAFERELEASE(pDropTrgt);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COfflineFolder::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved,
|
|
LPSTR pszName, UINT cchMax)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
// TraceMsg(TF_SUBSFOLDER, "Folder:IContextMenu - GetCommandString.");
|
|
if (uFlags == GCS_HELPTEXTA)
|
|
{
|
|
MLLoadStringA((UINT)idCmd + IDS_SB_FIRST, pszName, cchMax);
|
|
hres = NOERROR;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
COfflineDetails::COfflineDetails(HWND hwndOwner)
|
|
{
|
|
ASSERT(NULL != hwndOwner);
|
|
m_hwndOwner = hwndOwner;
|
|
m_cRef = 1;
|
|
}
|
|
|
|
STDMETHODIMP COfflineDetails::QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if ((IID_IUnknown == riid) || (IID_IShellDetails == riid))
|
|
{
|
|
*ppv = (IShellDetails *)this;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COfflineDetails::AddRef()
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) COfflineDetails::Release()
|
|
{
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP COfflineDetails::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (iColumn > ICOLC_ACTUALSIZE)
|
|
return E_NOTIMPL;
|
|
|
|
if (NULL == pDetails)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (NULL != pidl)
|
|
{
|
|
DETAILSINFO di = { pidl };
|
|
hr = Generic_GetDetails(&di, colInfo[iColumn].iCol);
|
|
pDetails->fmt = di.fmt;
|
|
pDetails->cxChar = di.cxChar;
|
|
memcpy(&pDetails->str, &di.str, sizeof(di.str));
|
|
}
|
|
else
|
|
{
|
|
pDetails->str.uType = STRRET_CSTR;
|
|
pDetails->str.cStr[0] = '\0';
|
|
MLLoadStringA(colInfo[iColumn].ids, pDetails->str.cStr, sizeof(pDetails->str.cStr));
|
|
pDetails->fmt = colInfo[iColumn].iFmt;
|
|
pDetails->cxChar = colInfo[iColumn].cchCol;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP COfflineDetails::ColumnClick(UINT iColumn)
|
|
{
|
|
ShellFolderView_ReArrange(m_hwndOwner, colInfo[iColumn].iCol);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
LPMYPIDL _CreateFolderPidl(IMalloc *pmalloc, DWORD dwSize)
|
|
{
|
|
LPMYPIDL pooi = (LPMYPIDL)pmalloc->Alloc(sizeof(MYPIDL) + dwSize + sizeof(USHORT));
|
|
if (pooi)
|
|
{
|
|
memset(pooi, 0, sizeof(MYPIDL) + dwSize + sizeof(USHORT));
|
|
pooi->cb = (USHORT)(dwSize + sizeof(MYPIDL));
|
|
pooi->usSign = (USHORT)MYPIDL_MAGIC;
|
|
// TraceMsg(TF_MEMORY, "CreatePidl %d", sizeof(MYPIDL) + dwSize);
|
|
}
|
|
return pooi;
|
|
}
|