//========================================================================================== // 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; }