windows-nt/Source/XPSP1/NT/shell/shdocvw/urlprop2.cpp
2020-09-26 16:20:57 +08:00

428 lines
13 KiB
C++

//==========================================================================================
// HISTDATA helper (should be a static member)
//==========================================================================================
#define CUrlHistoryProp IntsiteProp
//==========================================================================================
// IntsiteProp class implementation
//==========================================================================================
#ifdef DEBUG
/*----------------------------------------------------------
Purpose: Dump the properties in this object
*/
STDMETHODIMP_(void)
CUrlHistoryProp::Dump(void)
{
if (IsFlagSet(g_dwDumpFlags, DF_URLPROP))
{
TraceMsg(TF_ALWAYS, " Intsite Property obj: %s", m_szURL);
URLProp::Dump();
}
}
#endif
/*----------------------------------------------------------
Purpose: Constructor for URLProp
*/
CUrlHistoryProp::CUrlHistoryProp(void)
{
// Don't validate this until after construction.
// This object should only be allocated, not used on the stack,
// because we don't zero-initialize the member variables.
// Here's a sanity assertion.
ASSERT(NULL == m_pintshcut);
ASSERT(IS_VALID_STRUCT_PTR(this, CIntsiteProp));
return;
}
/*----------------------------------------------------------
Purpose: Destructor for CUrlHistoryProp
*/
CUrlHistoryProp::~CUrlHistoryProp(void)
{
if (m_pintshcut)
{
if (!m_fPrivate)
m_pintshcut->Release();
m_pintshcut = NULL;
}
return;
}
STDAPI CIntsiteProp_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvOut)
{
HRESULT hres;
*ppvOut = NULL;
ASSERT(punkOuter==NULL)
IUnknown * piunk = (IUnknown *)new IntsiteProp;
if ( !piunk )
{
hres = E_OUTOFMEMORY;
}
else
{
hres = piunk->QueryInterface(riid, ppvOut);
piunk->Release();
}
return hres; // S_OK or E_NOINTERFACE
}
HRESULT CUrlHistoryProp::Init(void)
{
return URLProp::Init();
}
STDMETHODIMP CUrlHistoryProp::InitFromDB(LPCTSTR pszURL, Intshcut *pintshcut, BOOL fPrivObj)
{
// TraceMsg(DM_HISTPROP, "CUHP::InitFromDB called for %s", pszURL);
// Initialize the in-memory property storage from the file
// and database
HRESULT hres = Init();
if (SUCCEEDED(hres))
{
if (NULL == m_pintshcut)
{
m_fPrivate = fPrivObj;
if (!m_fPrivate)
pintshcut->AddRef();
m_pintshcut = pintshcut;
}
else
{
// We can't switch from Private->Public or visaversa.
ASSERT(fPrivObj == m_fPrivate);
}
if (pszURL)
{
// Is this really a URL??
PARSEDURL pu;
pu.cbSize = SIZEOF(pu);
hres = ParseURL(pszURL, &pu);
if (S_OK == hres)
{
// Yes; go ahead and initialize
StrCpyN(m_szURL, pszURL, SIZECHARS(m_szURL));
hres = LoadFromDB(pszURL);
}
}
}
return hres;
}
HRESULT CUrlHistoryProp::LoadFromDB(
IN LPCTSTR pszURL)
{
TraceMsg(DM_HISTPROP, "CUHP::LoadFromDB called for %s", pszURL);
CEI_PREALLOC buf;
CUrlHistory::s_ConvertToPrefixedUrlW(pszURL, buf.szPrefixedUrl, ARRAYSIZE(buf.szPrefixedUrl), &buf.pszFragment);
CUrlHistory::s_RetrievePrefixedUrlInfo(buf.szPrefixedUrl, &buf);
//
// if there is already an entry for this Url, then we will reuse some of the
// settings. retrieve the relevant info if possible.
//
if (buf.pcei) {
CHistoryData* phdPrev = CHistoryData::s_GetHistoryData(buf.pcei);
if (phdPrev) {
//
// Initialize non-string properties first
//
const static PROPSPEC c_aprspec[] = {
{ PRSPEC_PROPID, PID_INTSITE_FLAGS },
{ PRSPEC_PROPID, PID_INTSITE_LASTVISIT },
{ PRSPEC_PROPID, PID_INTSITE_LASTMOD },
{ PRSPEC_PROPID, PID_INTSITE_WATCH },
};
PROPVARIANT apropvar[ARRAYSIZE(c_aprspec)] = { 0 };
apropvar[0].vt = VT_UI4;
apropvar[0].lVal = phdPrev->dwFlags;
apropvar[1].vt = VT_FILETIME;
apropvar[1].filetime = buf.pcei->LastAccessTime;
apropvar[2].vt = VT_FILETIME;
apropvar[2].filetime = buf.pcei->LastModifiedTime;
apropvar[3].vt = VT_UI4;
apropvar[3].lVal = phdPrev->dwWatch;
TraceMsg(DM_HISTPROP, "CUHP::InitFromDB calling WriteMultiple (wFlags=%x)", phdPrev->dwFlags);
WriteMultiple(ARRAYSIZE(c_aprspec), c_aprspec, apropvar, 0);
PropStg_DirtyMultiple(m_hstg, ARRAYSIZE(c_aprspec), c_aprspec, FALSE);
//
// Then, initialize others
//
PROPSPEC prspec;
prspec.ulKind = PRSPEC_PROPID;
for (const HISTEXTRA* phextPrev = phdPrev->_GetExtra();
phextPrev && !phextPrev->IsTerminator();
phextPrev = phextPrev->GetNextFast())
{
TraceMsg(DM_HISTPROP, "CUHP::InitFromDB found HISTEXTRA (id=%d, vt=%d)",
phextPrev->idExtra, phextPrev->cbExtra);
WCHAR wszBuf[MAX_URL_STRING]; // NOTES: scope must be right
apropvar[0].vt = phextPrev->vtExtra;
switch(phextPrev->vtExtra) {
case VT_LPWSTR:
apropvar[0].pwszVal = (LPWSTR)phextPrev->abExtra;
break;
case VT_LPSTR:
//
// Notice that we always convert it to LPWSTR
//
{
apropvar[0].pwszVal = wszBuf;
LPCSTR pszExtra = (LPCSTR)phextPrev->abExtra;
AnsiToUnicode(pszExtra, wszBuf, ARRAYSIZE(wszBuf));
apropvar[0].vt = VT_LPWSTR;
}
break;
case VT_UI4:
case VT_I4:
apropvar[0].lVal = *(DWORD*)phextPrev->abExtra;
break;
case VT_NULL:
ASSERT(phextPrev->idExtra == PID_INTSITE_FRAGMENT);
continue;
default:
ASSERT(0);
continue;
}
prspec.propid = phextPrev->idExtra;
WriteMultiple(1, &prspec, apropvar, 0);
PropStg_DirtyMultiple(m_hstg, 1, &prspec, FALSE);
}
} else {
TraceMsg(DM_HISTPROP, "CUHP::LoadFromDB can't get phdPrev");
}
} else {
TraceMsg(DM_HISTPROP, "CUHP::LoadFromDB can't get pcei");
}
return S_OK;
}
struct URLHIST_ENUMPARAM {
CUrlHistoryProp* that;
INTERNET_CACHE_ENTRY_INFO cei;
LPINTERNET_CACHE_ENTRY_INFO pceiPrev;
CHistoryData* phdPrev;
LPHISTEXTRA phextCur;
UINT cbHistExtra;
BOOL fDirty;
};
STDAPI s_CommitHistItem(
IN PROPID propid,
IN PROPVARIANT * ppropvar,
IN LPARAM lParam)
{
URLHIST_ENUMPARAM* peparam = (URLHIST_ENUMPARAM*)lParam;
CHistoryData* phdNew = (CHistoryData*)peparam->cei.lpHeaderInfo;
TraceMsg(DM_HISTEXTRA, "CUHP::s_CommitHistItem called for id=%d vt=%d (phextCur=%x)",
propid, ppropvar->vt, peparam->phextCur);
UINT cbExtra = 0;
UINT cbRequired;
switch(propid) {
case PID_INTSITE_FLAGS:
if (ppropvar->vt == VT_UI4 && phdNew) {
TraceMsg(DM_HISTPROP, "CUHP::s_CommitHistItem updating PID_INSITE_FLAGS (%x to %x)",
phdNew->dwFlags, ppropvar->lVal);
phdNew->dwFlags = ppropvar->lVal;
peparam->fDirty = TRUE;
}
break;
case PID_INTSITE_WATCH:
if (ppropvar->vt == VT_UI4 && phdNew) {
TraceMsg(DM_HISTPROP, "CUHP::s_CommitHistItem updating PID_INSITE_WATCH (%x to %x)",
phdNew->dwFlags, ppropvar->lVal);
phdNew->dwWatch = ppropvar->lVal;
peparam->fDirty = TRUE;
}
break;
case PID_INTSITE_LASTVISIT:
case PID_INTSITE_LASTMOD:
// They are read-only. We can change it if we want.
ASSERT(0);
break;
default:
switch(ppropvar->vt) {
case VT_UI4:
case VT_I4:
cbExtra = DW_ALIGNED(SIZEOF(HISTEXTRA)-SIZEOF(peparam->phextCur->abExtra)+SIZEOF(UINT));
if (peparam->phextCur) {
peparam->phextCur->cbExtra = cbExtra;
peparam->phextCur->idExtra = propid;
peparam->phextCur->vtExtra = ppropvar->vt;
*(DWORD*)peparam->phextCur->abExtra = ppropvar->lVal;
peparam->fDirty = TRUE;
}
break;
case VT_LPWSTR:
cbRequired = WideCharToMultiByte(CP_ACP, 0, ppropvar->pwszVal, -1,
NULL, 0, NULL, NULL);
cbExtra = DW_ALIGNED(SIZEOF(HISTEXTRA) + cbRequired);
if (peparam->phextCur)
{
peparam->phextCur->cbExtra = cbExtra;
peparam->phextCur->idExtra = propid;
peparam->phextCur->vtExtra = VT_LPSTR;
WideCharToMultiByte(CP_ACP, 0, ppropvar->pwszVal, -1,
(LPSTR)peparam->phextCur->abExtra, cbRequired, NULL, NULL);
peparam->fDirty = TRUE;
}
break;
case VT_EMPTY:
if (peparam->phextCur) {
peparam->fDirty = TRUE;
}
break;
default:
ASSERT(0);
break;
}
if (peparam->phextCur) {
// We are saving the data, move the write pointer.
TraceMsg(DM_HISTEXTRA, "s_CommitHistItem moving phextCur forward %d bytes",
peparam->phextCur->cbExtra);
peparam->phextCur = peparam->phextCur->GetNextFastForSave();
ASSERT(peparam->phextCur->cbExtra == 0);
} else {
// We are calcurating the required size, just add the size.
TraceMsg(DM_HISTEXTRA, "s_CommitHistItem adding %d", cbExtra);
peparam->cbHistExtra += cbExtra;
// Remove existing one.
if (peparam->phdPrev) {
// FEATURE: Bad const to non-const cast
HISTEXTRA* phextPrev =
(HISTEXTRA*)peparam->phdPrev->_FindExtra(propid);
if (phextPrev) {
TraceMsg(DM_HISTEXTRA, "s_CommitHistItem invalidate an old one id=%d %d bytes",
phextPrev->idExtra, phextPrev->cbExtra);
phextPrev->vtExtra = VT_EMPTY;
}
}
}
}
return S_OK;
};
HRESULT CUrlHistoryProp::Commit(IN DWORD dwFlags)
{
TraceMsg(DM_HISTPROP, "CUHP::Commit called for %s", m_szURL);
CEI_PREALLOC buf;
CUrlHistory::s_ConvertToPrefixedUrlW(m_szURL, buf.szPrefixedUrl, ARRAYSIZE(buf.szPrefixedUrl), &buf.pszFragment);
CUrlHistory::s_RetrievePrefixedUrlInfo(buf.szPrefixedUrl, &buf);
HRESULT hres;
URLHIST_ENUMPARAM eparam = { this };
ASSERT(eparam.fDirty == FALSE);
eparam.pceiPrev = buf.pcei;
if (eparam.pceiPrev) {
eparam.cei = *eparam.pceiPrev;
eparam.phdPrev = CHistoryData::s_GetHistoryData(eparam.pceiPrev);
}
// First, enemerate once to get the size for extra.
eparam.cei.lpHeaderInfo = NULL;
eparam.cbHistExtra = 0;
hres = PropStg_Enum(m_hstg, PSTGEF_DIRTY, s_CommitHistItem, (LPARAM)&eparam);
DWORD dwFlagsPrev = 0;
if (eparam.phdPrev) {
eparam.cbHistExtra += eparam.phdPrev->GetTotalExtraSize();
dwFlagsPrev = eparam.phdPrev->dwFlags;
}
TraceMsg(DM_HISTEXTRA, "CUHP::Commit total size is %d", eparam.cbHistExtra);
CHistoryData* phdNew = CHistoryData::s_AllocateHeaderInfo(
eparam.cbHistExtra, eparam.phdPrev,
&eparam.cei.dwHeaderInfoSize);
if (phdNew) {
eparam.cei.lpHeaderInfo = (LPTSTR)phdNew;
eparam.phextCur = phdNew->_GetExtra();
// Enumerate again to fill the extra data.
hres = PropStg_Enum(m_hstg, PSTGEF_DIRTY, s_CommitHistItem, (LPARAM)&eparam);
if (eparam.fDirty)
{
if (eparam.phdPrev) {
eparam.phdPrev->CopyExtra(eparam.phextCur);
}
TraceMsg(DM_HISTPROP, "CUHP::Commit It's dirty. save it (header = %d bytes)",
eparam.cei.dwHeaderInfoSize);
ASSERT(eparam.cbHistExtra == phdNew->GetTotalExtraSize());
CUrlHistory::s_CommitUrlCacheEntry(buf.szPrefixedUrl, &eparam.cei);
if ((dwFlagsPrev & PIDISF_RECENTLYCHANGED)
!= (phdNew->dwFlags & PIDISF_RECENTLYCHANGED))
{
// Yes; update the images
CUrlHistory::s_UpdateIcon(m_pintshcut, dwFlagsPrev);
}
}
LocalFree(phdNew);
phdNew = NULL;
}
return hres;
}