Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2808 lines
76 KiB

  1. #include "priv.h"
  2. #include "dspsprt.h"
  3. #include <hlink.h>
  4. #include "iface.h"
  5. #include "resource.h"
  6. #include <mluisupp.h>
  7. #include "shdocfl.h"
  8. class CTravelLog;
  9. class CEnumEntry : public IEnumTravelLogEntry
  10. {
  11. public:
  12. // *** IUnknown
  13. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  14. STDMETHODIMP_(ULONG) AddRef();
  15. STDMETHODIMP_(ULONG) Release();
  16. // *** IEnumTravelLogEntry specific methods
  17. STDMETHODIMP Next(ULONG cElt, ITravelLogEntry **rgElt, ULONG *pcEltFetched);
  18. STDMETHODIMP Skip(ULONG cElt);
  19. STDMETHODIMP Reset();
  20. STDMETHODIMP Clone(IEnumTravelLogEntry **ppEnum);
  21. CEnumEntry();
  22. void Init(CTravelLog *ptl, IUnknown *punk, DWORD dwOffset, DWORD dwFlags);
  23. void SetBase();
  24. protected:
  25. ~CEnumEntry();
  26. LONG _cRef;
  27. DWORD _dwFlags;
  28. DWORD _dwOffset;
  29. LONG _lStart;
  30. CTravelLog *_ptl;
  31. IUnknown *_punk;
  32. };
  33. class CTravelEntry : public ITravelEntry,
  34. public ITravelLogEntry,
  35. public IPropertyBag
  36. {
  37. public:
  38. CTravelEntry(BOOL fIsLocalAnchor);
  39. // *** IUnknown
  40. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  41. STDMETHODIMP_(ULONG) AddRef();
  42. STDMETHODIMP_(ULONG) Release();
  43. // *** ITravelEntry specific methods
  44. STDMETHODIMP Update(IUnknown *punk, BOOL fIsLocalAnchor);
  45. STDMETHODIMP Invoke(IUnknown *punk);
  46. STDMETHODIMP GetPidl(LPITEMIDLIST *ppidl);
  47. // *** ITravelLogEntry specific methods
  48. STDMETHODIMP GetTitle(LPOLESTR *ppszTitle);
  49. STDMETHODIMP GetURL(LPOLESTR *ppszURL);
  50. // *** IPropertyBag specific methods
  51. STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  52. STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar);
  53. static HRESULT CreateTravelEntry(IBrowserService *pbs, BOOL fIsLocalAnchor, CTravelEntry **ppte);
  54. void SetPrev(CTravelEntry *ptePrev);
  55. void SetNext(CTravelEntry *pteNext);
  56. CTravelEntry *GetPrev() {return _ptePrev;}
  57. CTravelEntry *GetNext() {return _pteNext;}
  58. void RemoveSelf();
  59. BOOL CanInvoke(IUnknown *punk, BOOL fAllowLocalAnchor);
  60. HRESULT GetIndexBrowser(IUnknown *punkIn, IUnknown ** ppsbOut) const;
  61. DWORD Size();
  62. DWORD ListSize();
  63. HRESULT Clone(CTravelEntry **ppte);
  64. HRESULT UpdateExternal(IUnknown *punk, IUnknown *punkHLBrowseContext);
  65. HRESULT UpdateSelf(IUnknown *punk)
  66. {return Update(punk, (_type == TET_LOCALANCHOR));}
  67. BOOL IsExternal(void)
  68. { return (_type==TET_EXTERNALNAV); }
  69. HRESULT GetDisplayName(LPTSTR psz, DWORD cch, DWORD dwFlags);
  70. BOOL IsEqual(LPCITEMIDLIST pidl)
  71. {return ILIsEqual(pidl, _pidl);}
  72. BOOL IsLocalAnchor(void)
  73. { return (_type==TET_LOCALANCHOR);}
  74. protected:
  75. CTravelEntry(void);
  76. HRESULT _InvokeExternal(IUnknown *punk);
  77. HRESULT _UpdateTravelLog(IUnknown *punk, BOOL fIsLocalAnchor);
  78. HRESULT _UpdateFromTLClient(IUnknown * punk, IStream ** ppStream);
  79. LONG _cRef;
  80. ~CTravelEntry();
  81. void _Reset(void);
  82. enum {
  83. TET_EMPTY = 0,
  84. TET_DEFAULT = 1,
  85. TET_LOCALANCHOR,
  86. TET_EXTERNALNAV
  87. };
  88. DWORD _type; // flags for our own sake...
  89. LPITEMIDLIST _pidl; // pidl of the entry
  90. HGLOBAL _hGlobalData; // the stream data saved by the entry
  91. DWORD _bid; // the BrowserIndex for frame specific navigation
  92. DWORD _dwCookie; // if _hGlobalData is NULL the cookie should be set
  93. WCHAR * _pwzTitle;
  94. WCHAR * _pwzUrlLocation;
  95. IHlink *_phl;
  96. IHlinkBrowseContext *_phlbc;
  97. IPropertyBag *_ppb;
  98. CTravelEntry *_ptePrev;
  99. CTravelEntry *_pteNext;
  100. };
  101. CTravelEntry::CTravelEntry(BOOL fIsLocalAnchor) : _cRef(1)
  102. {
  103. //these should always be allocated
  104. // thus they will always start 0
  105. if (fIsLocalAnchor)
  106. _type = TET_LOCALANCHOR;
  107. else
  108. ASSERT(!_type);
  109. ASSERT(!_pwzTitle);
  110. ASSERT(!_pwzUrlLocation);
  111. ASSERT(!_pidl);
  112. ASSERT(!_hGlobalData);
  113. ASSERT(!_bid);
  114. ASSERT(!_dwCookie);
  115. ASSERT(!_ptePrev);
  116. ASSERT(!_pteNext);
  117. ASSERT(!_phl);
  118. ASSERT(!_ppb);
  119. ASSERT(!_phlbc);
  120. TraceMsg(TF_TRAVELLOG, "TE[%X] created _type = %x", this, _type);
  121. }
  122. CTravelEntry::CTravelEntry(void) : _cRef(1)
  123. {
  124. ASSERT(!_type);
  125. ASSERT(!_pwzTitle);
  126. ASSERT(!_pwzUrlLocation);
  127. ASSERT(!_pidl);
  128. ASSERT(!_hGlobalData);
  129. ASSERT(!_bid);
  130. ASSERT(!_dwCookie);
  131. ASSERT(!_ptePrev);
  132. ASSERT(!_pteNext);
  133. ASSERT(!_phl);
  134. ASSERT(!_ppb);
  135. ASSERT(!_phlbc);
  136. TraceMsg(TF_TRAVELLOG, "TE[%X] created", this, _type);
  137. }
  138. HGLOBAL CloneHGlobal(HGLOBAL hGlobalIn)
  139. {
  140. DWORD dwSize = (DWORD)GlobalSize(hGlobalIn);
  141. HGLOBAL hGlobalOut = GlobalAlloc(GlobalFlags(hGlobalIn), dwSize);
  142. HGLOBAL hGlobalResult = NULL;
  143. if (NULL != hGlobalOut)
  144. {
  145. LPVOID pIn= GlobalLock(hGlobalIn);
  146. if (NULL != pIn)
  147. {
  148. LPVOID pOut= GlobalLock(hGlobalOut);
  149. if (NULL != pOut)
  150. {
  151. memcpy(pOut, pIn, dwSize);
  152. GlobalUnlock(hGlobalOut);
  153. hGlobalResult = hGlobalOut;
  154. }
  155. GlobalUnlock(hGlobalIn);
  156. }
  157. if (!hGlobalResult)
  158. {
  159. GlobalFree(hGlobalOut);
  160. hGlobalOut = NULL;
  161. }
  162. }
  163. return hGlobalResult;
  164. }
  165. HRESULT
  166. CTravelEntry::Clone(CTravelEntry **ppte)
  167. {
  168. // dont ever clone an external entry
  169. if (_type == TET_EXTERNALNAV)
  170. return E_FAIL;
  171. HRESULT hr = S_OK;
  172. CTravelEntry *pte = new CTravelEntry();
  173. if (pte)
  174. {
  175. pte->_type = _type;
  176. pte->_bid = _bid;
  177. pte->_dwCookie = _dwCookie;
  178. if (_pwzTitle)
  179. {
  180. pte->_pwzTitle = StrDup(_pwzTitle);
  181. if (!pte->_pwzTitle)
  182. {
  183. hr = E_OUTOFMEMORY;
  184. }
  185. }
  186. if (_pwzUrlLocation)
  187. {
  188. pte->_pwzUrlLocation = StrDup(_pwzUrlLocation);
  189. if (!pte->_pwzUrlLocation)
  190. {
  191. hr = E_OUTOFMEMORY;
  192. }
  193. }
  194. if (_pidl)
  195. {
  196. pte->_pidl = ILClone(_pidl);
  197. if (!pte->_pidl)
  198. hr = E_OUTOFMEMORY;
  199. }
  200. else
  201. pte->_pidl = NULL;
  202. if (_hGlobalData)
  203. {
  204. pte->_hGlobalData = CloneHGlobal(_hGlobalData);
  205. if (NULL == pte->_hGlobalData)
  206. {
  207. hr = E_OUTOFMEMORY;
  208. }
  209. }
  210. else
  211. {
  212. ASSERT(NULL == pte->_hGlobalData);
  213. }
  214. }
  215. else
  216. hr = E_OUTOFMEMORY;
  217. if (FAILED(hr) && pte)
  218. {
  219. pte->Release();
  220. *ppte = NULL;
  221. }
  222. else
  223. *ppte = pte;
  224. TraceMsg(TF_TRAVELLOG, "TE[%X] Clone hr = %x", this, hr);
  225. return hr;
  226. }
  227. CTravelEntry::~CTravelEntry()
  228. {
  229. ILFree(_pidl);
  230. if (_hGlobalData)
  231. {
  232. GlobalFree(_hGlobalData);
  233. _hGlobalData = NULL;
  234. }
  235. if (_pwzTitle)
  236. {
  237. LocalFree(_pwzTitle);
  238. _pwzTitle = NULL;
  239. }
  240. if (_pwzUrlLocation)
  241. {
  242. LocalFree(_pwzUrlLocation);
  243. _pwzUrlLocation = NULL;
  244. }
  245. if (_pteNext)
  246. {
  247. _pteNext->Release();
  248. }
  249. // Don't need to release _ptePrev because TravelEntry only addref's pteNext
  250. ATOMICRELEASE(_ppb);
  251. ATOMICRELEASE(_phl);
  252. ATOMICRELEASE(_phlbc);
  253. TraceMsg(TF_TRAVELLOG, "TE[%X] destroyed ", this);
  254. }
  255. HRESULT CTravelEntry::QueryInterface(REFIID riid, void **ppvObj)
  256. {
  257. static const QITAB qit[] = {
  258. QITABENT(CTravelEntry, ITravelEntry), // IID_ITravelEntry
  259. QITABENT(CTravelEntry, ITravelLogEntry),
  260. QITABENT(CTravelEntry, IPropertyBag),
  261. { 0 },
  262. };
  263. return QISearch(this, qit, riid, ppvObj);
  264. }
  265. ULONG CTravelEntry::AddRef()
  266. {
  267. return InterlockedIncrement(&_cRef);
  268. }
  269. ULONG CTravelEntry::Release()
  270. {
  271. ASSERT( 0 != _cRef );
  272. ULONG cRef = InterlockedDecrement(&_cRef);
  273. if (0 == cRef)
  274. {
  275. delete this;
  276. }
  277. return cRef;
  278. }
  279. //+-------------------------------------------------------------------------
  280. //
  281. // Method : CTravelEntry::GetIndexBrowser
  282. //
  283. // Synopsis : This method finds and returns the IUnknown of the browser
  284. // with the index in _bid. This method first checks to see
  285. // if the passed in punk supports ITravelLogClient. If it
  286. // doesn't, it checks for IBrowserService.
  287. //
  288. //--------------------------------------------------------------------------
  289. HRESULT
  290. CTravelEntry::GetIndexBrowser(IUnknown * punk, IUnknown ** ppunkBrowser) const
  291. {
  292. HRESULT hr = E_FAIL;
  293. ASSERT(ppunkBrowser);
  294. ITravelLogClient * ptlcTop;
  295. hr = punk->QueryInterface(IID_PPV_ARG(ITravelLogClient, &ptlcTop));
  296. if (SUCCEEDED(hr))
  297. {
  298. hr = ptlcTop->FindWindowByIndex(_bid, ppunkBrowser);
  299. ptlcTop->Release();
  300. }
  301. TraceMsg(TF_TRAVELLOG, "TE[%X]::GetIndexBrowser _bid = %X, hr = %X", this, _bid, hr);
  302. return hr;
  303. }
  304. //+-------------------------------------------------------------------------
  305. //
  306. // Method : CTravelEntry::CanInvoke
  307. //
  308. // Synopsis : This method determines if the current travel entry can
  309. // be invoked. There are two criteria that determine if
  310. // this entry can be invoked.
  311. // 1) If the entry is a local anchor, fAllowLocalAnchor must
  312. // be TRUE.
  313. // 2) A browser with the index in _bid must exist.
  314. //
  315. //--------------------------------------------------------------------------
  316. BOOL CTravelEntry::CanInvoke(IUnknown *punk, BOOL fAllowLocalAnchor)
  317. {
  318. IUnknown * punkBrowser = NULL;
  319. BOOL fRet = IsLocalAnchor() ? fAllowLocalAnchor : TRUE;
  320. fRet = fRet && SUCCEEDED(GetIndexBrowser(punk, &punkBrowser));
  321. SAFERELEASE(punkBrowser);
  322. return fRet;
  323. }
  324. DWORD CTravelEntry::Size()
  325. {
  326. DWORD cbSize = SIZEOF(*this);
  327. if (_pidl)
  328. cbSize += ILGetSize(_pidl);
  329. if (_hGlobalData)
  330. {
  331. cbSize += (DWORD)GlobalSize(_hGlobalData);
  332. }
  333. if (_pwzTitle)
  334. {
  335. cbSize += (DWORD)LocalSize(_pwzTitle);
  336. }
  337. if (_pwzUrlLocation)
  338. {
  339. cbSize += (DWORD)LocalSize(_pwzUrlLocation);
  340. }
  341. return cbSize;
  342. }
  343. DWORD CTravelEntry::ListSize()
  344. {
  345. CTravelEntry *pte = GetNext();
  346. DWORD cb = Size();
  347. while (pte)
  348. {
  349. cb += pte->Size();
  350. pte = pte->GetNext();
  351. }
  352. return cb;
  353. }
  354. void CTravelEntry::_Reset()
  355. {
  356. Pidl_Set(&_pidl, NULL);
  357. if (NULL != _hGlobalData)
  358. {
  359. GlobalFree(_hGlobalData);
  360. _hGlobalData = NULL;
  361. }
  362. ATOMICRELEASE(_phl);
  363. ATOMICRELEASE(_phlbc);
  364. _bid = 0;
  365. _type = TET_EMPTY;
  366. _dwCookie = 0;
  367. if (_pwzTitle)
  368. {
  369. LocalFree(_pwzTitle);
  370. _pwzTitle = NULL;
  371. }
  372. if (_pwzUrlLocation)
  373. {
  374. LocalFree(_pwzUrlLocation);
  375. _pwzUrlLocation = NULL;
  376. }
  377. TraceMsg(TF_TRAVELLOG, "TE[%X]::_Reset", this);
  378. }
  379. HRESULT CTravelEntry::_UpdateTravelLog(IUnknown *punk, BOOL fIsLocalAnchor)
  380. {
  381. IBrowserService *pbs;
  382. HRESULT hr = E_FAIL;
  383. // we need to update here
  384. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  385. {
  386. ITravelLog *ptl;
  387. if (SUCCEEDED(pbs->GetTravelLog(&ptl)))
  388. {
  389. hr = ptl->UpdateEntry(punk, fIsLocalAnchor);
  390. ptl->Release();
  391. }
  392. pbs->Release();
  393. }
  394. return hr;
  395. }
  396. HRESULT CTravelEntry::_InvokeExternal(IUnknown *punk)
  397. {
  398. HRESULT hr = E_FAIL;
  399. ASSERT(_phl);
  400. ASSERT(_phlbc);
  401. TraceMsg(TF_TRAVELLOG, "TE[%X]::InvokeExternal entered on _bid = %X, _phl = %X, _phlbc = %X", this, _bid, _phl, _phlbc);
  402. HWND hwnd = NULL;
  403. IOleWindow *pow;
  404. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IOleWindow, &pow))))
  405. {
  406. pow->GetWindow(&hwnd);
  407. pow->Release();
  408. }
  409. // set the size and position of the browser frame window, so that the
  410. // external target can sync up its frame window to those coordinates
  411. HLBWINFO hlbwi = {0};
  412. hlbwi.cbSize = sizeof(hlbwi);
  413. hlbwi.grfHLBWIF = 0;
  414. if (hwnd)
  415. {
  416. WINDOWPLACEMENT wp = {0};
  417. wp.length = sizeof(WINDOWPLACEMENT);
  418. GetWindowPlacement(hwnd, &wp);
  419. hlbwi.grfHLBWIF = HLBWIF_HASFRAMEWNDINFO;
  420. hlbwi.rcFramePos = wp.rcNormalPosition;
  421. if (wp.showCmd == SW_SHOWMAXIMIZED)
  422. hlbwi.grfHLBWIF |= HLBWIF_FRAMEWNDMAXIMIZED;
  423. }
  424. _phlbc->SetBrowseWindowInfo(&hlbwi);
  425. //
  426. // right now we always now we are going back, but later on
  427. // maybe we should ask the browser whether this is back or forward
  428. //
  429. hr = _phl->Navigate(HLNF_NAVIGATINGBACK, NULL, NULL, _phlbc);
  430. IWebBrowser2 *pwb;
  431. if (SUCCEEDED(IUnknown_QueryService(punk, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &pwb))))
  432. {
  433. ASSERT(pwb);
  434. pwb->put_Visible(FALSE);
  435. pwb->Release();
  436. }
  437. _UpdateTravelLog(punk, FALSE);
  438. TraceMsg(TF_TRAVELLOG, "TE[%X]::InvokeExternal exited hr = %X", this, hr);
  439. return hr;
  440. }
  441. HRESULT CTravelEntry::Invoke(IUnknown *punk)
  442. {
  443. IPersistHistory *pph = NULL;
  444. HRESULT hr = E_FAIL;
  445. IUnknown * punkBrowser = NULL;
  446. IHTMLWindow2 * pWindow = NULL;
  447. TraceMsg(TF_TRAVELLOG, "TE[%X]::Invoke entered on _bid = %X", this, _bid);
  448. TraceMsgW(TF_TRAVELLOG, "TE[%X]::Invoke title '%s'", this, _pwzTitle);
  449. if (_type == TET_EXTERNALNAV)
  450. {
  451. hr = _InvokeExternal(punk);
  452. goto Quit;
  453. }
  454. // Get the window/browser with the index. If that
  455. // fails, punk may be a IHTMLWindow2. If so,
  456. // get its IPersistHistory so the travel entry
  457. // can be loaded directly. (This is needed by Trident
  458. // in order to navigate in frames when traveling
  459. // backwards or forwards.
  460. //
  461. hr = GetIndexBrowser(punk, &punkBrowser);
  462. if (SUCCEEDED(hr))
  463. {
  464. hr = punkBrowser->QueryInterface(IID_PPV_ARG(IPersistHistory, &pph));
  465. }
  466. else
  467. {
  468. hr = punk->QueryInterface(IID_PPV_ARG(IHTMLWindow2, &pWindow));
  469. if (SUCCEEDED(hr))
  470. {
  471. hr = pWindow->QueryInterface(IID_PPV_ARG(IPersistHistory, &pph));
  472. }
  473. }
  474. if (SUCCEEDED(hr))
  475. {
  476. ASSERT(pph);
  477. if (_type == TET_LOCALANCHOR)
  478. {
  479. ITravelLogClient * pTLClient;
  480. hr = pph->QueryInterface(IID_PPV_ARG(ITravelLogClient, &pTLClient));
  481. if (SUCCEEDED(hr))
  482. {
  483. hr = pTLClient->LoadHistoryPosition(_pwzUrlLocation, _dwCookie);
  484. pTLClient->Release();
  485. }
  486. else
  487. {
  488. hr = pph->SetPositionCookie(_dwCookie);
  489. }
  490. }
  491. else
  492. {
  493. // we need to clone it
  494. ASSERT(_hGlobalData);
  495. HGLOBAL hGlobal = CloneHGlobal(_hGlobalData);
  496. if (NULL != hGlobal)
  497. {
  498. IStream *pstm;
  499. hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm);
  500. if (SUCCEEDED(hr))
  501. {
  502. hr = pph->LoadHistory(pstm, NULL);
  503. pstm->Release();
  504. }
  505. else
  506. {
  507. GlobalFree(hGlobal);
  508. }
  509. }
  510. else
  511. {
  512. hr = E_OUTOFMEMORY;
  513. }
  514. }
  515. pph->Release();
  516. }
  517. Quit:
  518. SAFERELEASE(punkBrowser);
  519. SAFERELEASE(pWindow);
  520. TraceMsg(TF_TRAVELLOG, "TE[%X]::Invoke exited on _bid = %X, hr = %X", this, _bid, hr);
  521. return hr;
  522. }
  523. HRESULT CTravelEntry::UpdateExternal(IUnknown *punk, IUnknown *punkHLBrowseContext)
  524. {
  525. TraceMsg(TF_TRAVELLOG, "TE[%X]::UpdateExternal entered on punk = %X, punkhlbc = %X", this, punk, punkHLBrowseContext);
  526. _Reset();
  527. ASSERT(punkHLBrowseContext);
  528. punkHLBrowseContext->QueryInterface(IID_PPV_ARG(IHlinkBrowseContext, &_phlbc));
  529. ASSERT(_phlbc);
  530. _type = TET_EXTERNALNAV;
  531. HRESULT hr = E_FAIL;
  532. //
  533. // right now we only support externals being previous. we never actually navigate
  534. // to another app. we handle everything in pane ourselves.
  535. // so theoretically we never need to worry about HLID_NEXT
  536. _phlbc->GetHlink((ULONG) HLID_PREVIOUS, &_phl);
  537. IBrowserService *pbs;
  538. punk->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs));
  539. if (pbs && _phl)
  540. {
  541. _bid = pbs->GetBrowserIndex();
  542. WCHAR *pwszTarget;
  543. hr = _phl->GetStringReference(HLINKGETREF_ABSOLUTE, &pwszTarget, NULL);
  544. if (SUCCEEDED(hr))
  545. {
  546. // create pidl
  547. hr = IECreateFromPath(pwszTarget, &_pidl);
  548. OleFree(pwszTarget);
  549. }
  550. }
  551. ATOMICRELEASE(pbs);
  552. TraceMsg(TF_TRAVELLOG, "TE[%X]::UpdateExternal exited _bid = %X, hr = %X", this, _bid, hr);
  553. return hr;
  554. }
  555. HRESULT CTravelEntry::Update(IUnknown *punk, BOOL fIsLocalAnchor)
  556. {
  557. ASSERT(punk);
  558. // this means that we went back to an external app,
  559. // and now we are going forward again. we dont persist
  560. // any state info about them that would be different.
  561. if (_type == TET_EXTERNALNAV)
  562. {
  563. TraceMsg(TF_TRAVELLOG, "TE[%X]::Update NOOP on external entry", this);
  564. return S_OK;
  565. }
  566. _Reset();
  567. // Try ITravelLogClient first. If that fails, revert to IBrowserService.
  568. //
  569. IStream *pstm = NULL;
  570. IPersistHistory *pph = NULL;
  571. HRESULT hr = _UpdateFromTLClient(punk, &pstm);
  572. if (S_OK != hr)
  573. goto Cleanup;
  574. hr = punk->QueryInterface(IID_PPV_ARG(IPersistHistory, &pph));
  575. ASSERT(SUCCEEDED(hr));
  576. if (S_OK != hr)
  577. goto Cleanup;
  578. if (fIsLocalAnchor)
  579. {
  580. // persist a cookie
  581. //
  582. _type = TET_LOCALANCHOR;
  583. hr = pph->GetPositionCookie(&_dwCookie);
  584. }
  585. else
  586. {
  587. _type = TET_DEFAULT;
  588. // persist a stream
  589. //
  590. ASSERT(!_hGlobalData);
  591. if (!pstm)
  592. {
  593. hr = CreateStreamOnHGlobal(NULL, FALSE, &pstm);
  594. if (hr != S_OK)
  595. goto Cleanup;
  596. pph->SaveHistory(pstm);
  597. }
  598. STATSTG stg;
  599. HRESULT hrStat = pstm->Stat(&stg, STATFLAG_NONAME);
  600. hr = GetHGlobalFromStream(pstm, &_hGlobalData);
  601. // This little exercise here is to shrink the memory block we get from
  602. // the OLE API which allocates blocks in chunks of 8KB. Typical stream
  603. // sizes are only a few hundred bytes.
  604. if (S_OK != hrStat)
  605. goto Cleanup;
  606. HGLOBAL hGlobalTemp = GlobalReAlloc(_hGlobalData, stg.cbSize.LowPart, GMEM_MOVEABLE);
  607. if (NULL != hGlobalTemp)
  608. {
  609. _hGlobalData = hGlobalTemp;
  610. }
  611. }
  612. Cleanup:
  613. if (FAILED(hr))
  614. _Reset();
  615. SAFERELEASE(pstm);
  616. SAFERELEASE(pph);
  617. TraceMsg(TF_TRAVELLOG, "TE[%X]::Update exited on _bid = %X, hr = %X", this, _bid, hr);
  618. return hr;
  619. }
  620. //+-----------------------------------------------------------------------------
  621. //
  622. // Method : CTravelEntry::_UpdateFromTLClient
  623. //
  624. // Synopsis : Updates the travel entry using the ITravelLogClient interface
  625. //
  626. //------------------------------------------------------------------------------
  627. HRESULT
  628. CTravelEntry::_UpdateFromTLClient(IUnknown * punk, IStream ** ppStream)
  629. {
  630. HRESULT hr;
  631. WINDOWDATA windata = {0};
  632. ITravelLogClient * ptlc = NULL;
  633. hr = punk->QueryInterface(IID_PPV_ARG(ITravelLogClient, &ptlc));
  634. if (S_OK != hr)
  635. goto Cleanup;
  636. hr = ptlc->GetWindowData(&windata);
  637. if (S_OK != hr)
  638. goto Cleanup;
  639. _bid = windata.dwWindowID;
  640. ILFree(_pidl);
  641. if (windata.pidl)
  642. {
  643. _pidl = ILClone(windata.pidl);
  644. }
  645. else
  646. {
  647. hr = IEParseDisplayNameWithBCW(windata.uiCP, windata.lpszUrl, NULL, &_pidl);
  648. if (S_OK != hr)
  649. goto Cleanup;
  650. }
  651. ASSERT(_pidl);
  652. // If there is an url location, append it to the end of the url
  653. //
  654. if (_pwzUrlLocation)
  655. {
  656. LocalFree(_pwzUrlLocation);
  657. _pwzUrlLocation = NULL;
  658. }
  659. if (windata.lpszUrlLocation && *windata.lpszUrlLocation)
  660. {
  661. _pwzUrlLocation = StrDup(windata.lpszUrlLocation);
  662. }
  663. // Pick up the title as a display name for menus and such.
  664. //
  665. if (_pwzTitle)
  666. {
  667. LocalFree(_pwzTitle);
  668. _pwzTitle = NULL;
  669. }
  670. if (windata.lpszTitle)
  671. _pwzTitle = StrDup(windata.lpszTitle);
  672. *ppStream = windata.pStream;
  673. TraceMsgW(TF_TRAVELLOG, "TE[%X]::_UpdateFromTLClient - ptlc:[0x%X] _bid:[%ld] Url:[%ws] Title:[%ws] UrlLocation:[%ws] ppStream:[0x%X]",
  674. this, ptlc, _bid, windata.lpszUrl, _pwzTitle, _pwzUrlLocation, *ppStream);
  675. Cleanup:
  676. ILFree(windata.pidl);
  677. CoTaskMemFree(windata.lpszUrl);
  678. CoTaskMemFree(windata.lpszUrlLocation);
  679. CoTaskMemFree(windata.lpszTitle);
  680. SAFERELEASE(ptlc);
  681. // Don't release windata.pStream. It will
  682. // be released when ppStream is released.
  683. return hr;
  684. }
  685. HRESULT CTravelEntry::GetPidl(LPITEMIDLIST * ppidl)
  686. {
  687. HRESULT hr = E_FAIL;
  688. if (EVAL(ppidl))
  689. {
  690. hr = SHILClone(_pidl, ppidl);
  691. }
  692. return hr;
  693. }
  694. void CTravelEntry::SetNext(CTravelEntry *pteNext)
  695. {
  696. if (_pteNext)
  697. _pteNext->Release();
  698. _pteNext = pteNext;
  699. if (_pteNext)
  700. {
  701. _pteNext->_ptePrev = this;
  702. }
  703. }
  704. void CTravelEntry::SetPrev(CTravelEntry *ptePrev)
  705. {
  706. _ptePrev = ptePrev;
  707. if (_ptePrev)
  708. _ptePrev->SetNext(this);
  709. }
  710. //
  711. // this is for removing from the middle of the list...
  712. //
  713. void CTravelEntry::RemoveSelf()
  714. {
  715. if (_pteNext)
  716. _pteNext->_ptePrev = _ptePrev;
  717. // remove yourself from the list
  718. if (_ptePrev)
  719. {
  720. // after this point, we may be destroyed so can't touch any more member vars
  721. _ptePrev->_pteNext = _pteNext;
  722. }
  723. _ptePrev = NULL;
  724. _pteNext = NULL;
  725. // we lose a reference now because we're gone from _ptePrev's _pteNext
  726. // (or if we were the top of the list, we're also nuked)
  727. Release();
  728. }
  729. HRESULT GetUnescapedUrlIfAppropriate(LPCITEMIDLIST pidl, LPTSTR pszUrl, DWORD cch)
  730. {
  731. TCHAR szUrl[MAX_URL_STRING];
  732. // The SHGDN_NORMAL display name will be the pretty name (Web Page title) unless
  733. // it's an FTP URL or the web page didn't set a title.
  734. if (SUCCEEDED(IEGetDisplayName(pidl, szUrl, SHGDN_NORMAL)) && UrlIs(szUrl, URLIS_URL))
  735. {
  736. // NT #279192, If an URL is escaped, it normally contains three types of
  737. // escaped chars.
  738. // 1) Seperating type chars ('#' for frag, '?' for params, etc.)
  739. // 2) DBCS chars,
  740. // 3) Data (a bitmap in the url by escaping the binary bytes)
  741. // Since #2 is very common, we want to try to unescape it so it has meaning
  742. // to the user. UnEscaping isn't safe if the user can copy or modify the data
  743. // because they could loose data when it's reparsed. One thing we need to
  744. // do for #2 to work is for it to be in ANSI when unescaped. This is needed
  745. // or the DBCS lead and trail bytes will be in unicode as [0x<LeadByte> 0x00]
  746. // [0x<TrailByte> 0x00]. Being in ANSI could cause a problem if the the string normally
  747. // crosses code pages, but that is uncommon or non-existent in the IsURLChild()
  748. // case.
  749. CHAR szUrlAnsi[MAX_URL_STRING];
  750. SHTCharToAnsi(szUrl, szUrlAnsi, ARRAYSIZE(szUrlAnsi));
  751. UrlUnescapeA(szUrlAnsi, NULL, NULL, URL_UNESCAPE_INPLACE|URL_UNESCAPE_HIGH_ANSI_ONLY);
  752. SHAnsiToTChar(szUrlAnsi, pszUrl, cch);
  753. }
  754. else
  755. {
  756. StrCpyN(pszUrl, szUrl, cch); // Truncate if needed
  757. }
  758. return S_OK;
  759. }
  760. #define TEGDN_FORSYSTEM 0x00000001
  761. HRESULT CTravelEntry::GetDisplayName(LPTSTR psz, DWORD cch, DWORD dwFlags)
  762. {
  763. if (!psz || !cch)
  764. return E_INVALIDARG;
  765. psz[0] = 0;
  766. if ((NULL != _pwzTitle) && (*_pwzTitle != 0))
  767. {
  768. StrCpyNW(psz, _pwzTitle, cch);
  769. }
  770. else if (_pidl)
  771. {
  772. GetUnescapedUrlIfAppropriate(_pidl, psz, cch);
  773. }
  774. if (dwFlags & TEGDN_FORSYSTEM)
  775. {
  776. if (!SHIsDisplayable(psz, g_fRunOnFE, g_bRunOnNT5))
  777. {
  778. // Display name isn't system-displayable. Just use the path/url instead.
  779. SHTitleFromPidl(_pidl, psz, cch, FALSE);
  780. }
  781. }
  782. SHCleanupUrlForDisplay(psz);
  783. return psz[0] ? S_OK : E_FAIL;
  784. }
  785. HRESULT CTravelEntry::GetTitle(LPOLESTR *ppszTitle)
  786. {
  787. HRESULT hres = S_OK;
  788. TCHAR szTitle[MAX_BROWSER_WINDOW_TITLE];
  789. ASSERT(IS_VALID_WRITE_PTR(ppszTitle, LPOLESTR));
  790. hres = GetDisplayName(szTitle, ARRAYSIZE(szTitle), TEGDN_FORSYSTEM);
  791. if (SUCCEEDED(hres))
  792. {
  793. ASSERT(*szTitle);
  794. hres = SHStrDup(szTitle, ppszTitle);
  795. }
  796. return hres;
  797. }
  798. HRESULT CTravelEntry::GetURL(LPOLESTR *ppszUrl)
  799. {
  800. HRESULT hres = E_FAIL;
  801. LPITEMIDLIST pidl = NULL;
  802. WCHAR wszURL[MAX_URL_STRING];
  803. if (_pidl)
  804. hres = ::IEGetDisplayName(_pidl, wszURL, SHGDN_FORPARSING);
  805. if (SUCCEEDED(hres))
  806. hres = SHStrDup(wszURL, ppszUrl);
  807. return hres;
  808. }
  809. HRESULT CTravelEntry::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  810. {
  811. if (!_ppb)
  812. {
  813. return E_INVALIDARG;
  814. }
  815. return _ppb->Read(pszPropName, pVar, pErrorLog);
  816. }
  817. HRESULT CTravelEntry::Write(LPCOLESTR pszPropName, VARIANT *pVar)
  818. {
  819. HRESULT hres = S_OK;
  820. if (!_ppb)
  821. {
  822. hres = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &_ppb));
  823. }
  824. if (SUCCEEDED(hres))
  825. {
  826. ASSERT(_ppb);
  827. hres = _ppb->Write(pszPropName, pVar);
  828. }
  829. return hres;
  830. }
  831. class CTravelLog : public ITravelLog,
  832. public ITravelLogEx
  833. {
  834. public:
  835. // *** IUnknown
  836. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  837. STDMETHODIMP_(ULONG) AddRef() ;
  838. STDMETHODIMP_(ULONG) Release();
  839. // *** ITravelLog specific methods
  840. STDMETHODIMP AddEntry(IUnknown *punk, BOOL fIsLocalAnchor);
  841. STDMETHODIMP UpdateEntry(IUnknown *punk, BOOL fIsLocalAnchor);
  842. STDMETHODIMP UpdateExternal(IUnknown *punk, IUnknown *punkHLBrowseContext);
  843. STDMETHODIMP Travel(IUnknown *punk, int iOffset);
  844. STDMETHODIMP GetTravelEntry(IUnknown *punk, int iOffset, ITravelEntry **ppte);
  845. STDMETHODIMP FindTravelEntry(IUnknown *punk, LPCITEMIDLIST pidl, ITravelEntry **ppte);
  846. STDMETHODIMP GetToolTipText(IUnknown *punk, int iOffset, int idsTemplate, LPWSTR pwzText, DWORD cchText);
  847. STDMETHODIMP InsertMenuEntries(IUnknown *punk, HMENU hmenu, int nPos, int idFirst, int idLast, DWORD dwFlags);
  848. STDMETHODIMP Clone(ITravelLog **pptl);
  849. STDMETHODIMP_(DWORD) CountEntries(IUnknown *punk);
  850. STDMETHODIMP Revert(void);
  851. // *** ITravelLogEx specific methods
  852. STDMETHODIMP FindTravelEntryWithUrl(IUnknown * punk, UINT uiCP, LPOLESTR lpszUrl, ITravelEntry ** ppte);
  853. STDMETHODIMP TravelToUrl(IUnknown * punk, UINT uiCP, LPOLESTR lpszUrl);
  854. STDMETHOD(DeleteIndexEntry)(IUnknown *punk, int index);
  855. STDMETHOD(DeleteUrlEntry)(IUnknown *punk, UINT uiCP, LPOLESTR pszUrl);
  856. STDMETHOD(CountEntryNodes)(IUnknown *punk, DWORD dwFlags, DWORD *pdwCount);
  857. STDMETHOD(CreateEnumEntry)(IUnknown *punk, IEnumTravelLogEntry **ppEnum, DWORD dwFlags);
  858. STDMETHOD(DeleteEntry)(IUnknown *punk, ITravelLogEntry *pte);
  859. STDMETHOD(InsertEntry)(IUnknown *punkBrowser, ITravelLogEntry *pteRelativeTo, BOOL fPrepend,
  860. IUnknown* punkTLClient, ITravelLogEntry **ppEntry);
  861. STDMETHOD(TravelToEntry)(IUnknown *punkBrowser, ITravelLogEntry *pteDestination);
  862. CTravelLog();
  863. protected:
  864. ~CTravelLog();
  865. HRESULT _FindEntryByOffset(IUnknown *punk, int iOffset, CTravelEntry **ppte);
  866. HRESULT _FindEntryByPidl(IUnknown * punk, LPCITEMIDLIST pidl, CTravelEntry ** ppte);
  867. HRESULT _FindEntryByPunk(IUnknown * punk, ITravelLogEntry *pteSearch, CTravelEntry ** ppte);
  868. void _DeleteFrameSetEntry(IUnknown *punk, CTravelEntry *pte);
  869. void _Prune(void);
  870. LONG _cRef;
  871. DWORD _cbMaxSize;
  872. DWORD _cbTotalSize;
  873. CTravelEntry *_pteCurrent; //pteCurrent
  874. CTravelEntry *_pteUpdate;
  875. CTravelEntry *_pteRoot;
  876. };
  877. CTravelLog::CTravelLog() : _cRef(1)
  878. {
  879. ASSERT(!_pteCurrent);
  880. ASSERT(!_pteUpdate);
  881. ASSERT(!_pteRoot);
  882. DWORD dwType, dwSize = SIZEOF(_cbMaxSize), dwDefault = 1024 * 1024;
  883. SHRegGetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TravelLog"), TEXT("MaxSize"), &dwType, (LPVOID)&_cbMaxSize, &dwSize, FALSE, (void *)&dwDefault, SIZEOF(dwDefault));
  884. TraceMsg(TF_TRAVELLOG, "TL[%X] created", this);
  885. }
  886. CTravelLog::~CTravelLog()
  887. {
  888. //DestroyList by releasing the root
  889. SAFERELEASE(_pteRoot);
  890. TraceMsg(TF_TRAVELLOG, "TL[%X] destroyed ", this);
  891. }
  892. HRESULT CTravelLog::QueryInterface(REFIID riid, void **ppvObj)
  893. {
  894. static const QITAB qit[] = {
  895. QITABENT(CTravelLog, ITravelLog), // IID_ITravelLog
  896. QITABENT(CTravelLog, ITravelLogEx), // IID_ITravelLogEx
  897. { 0 },
  898. };
  899. return QISearch(this, qit, riid, ppvObj);
  900. }
  901. ULONG CTravelLog::AddRef()
  902. {
  903. return InterlockedIncrement(&_cRef);
  904. }
  905. ULONG CTravelLog::Release()
  906. {
  907. ASSERT( 0 != _cRef );
  908. ULONG cRef = InterlockedDecrement(&_cRef);
  909. if (0 == cRef)
  910. {
  911. delete this;
  912. }
  913. return cRef;
  914. }
  915. HRESULT CTravelLog::AddEntry(IUnknown *punk, BOOL fIsLocalAnchor)
  916. {
  917. ASSERT(punk);
  918. if (SHRestricted2W(REST_NoNavButtons, NULL, 0))
  919. {
  920. return S_FALSE;
  921. }
  922. TraceMsg(TF_TRAVELLOG, "TL[%X]::AddEntry punk = %X, IsLocal = %s", this, punk, fIsLocalAnchor ? "TRUE" : "FALSE");
  923. CTravelEntry *pte = new CTravelEntry(fIsLocalAnchor);
  924. if (pte)
  925. {
  926. //replace the current with the new
  927. if (_pteCurrent)
  928. {
  929. CTravelEntry *pteNext = _pteCurrent->GetNext();
  930. if (pteNext)
  931. {
  932. _cbTotalSize -= pteNext->ListSize();
  933. }
  934. // the list keeps its own ref count, and only needs
  935. // to be modified when passed outside of the list
  936. // setnext will release the current next if necessary
  937. // this will also set pte->prev = pteCurrent
  938. _pteCurrent->SetNext(pte);
  939. }
  940. else
  941. _pteRoot = pte;
  942. _cbTotalSize += pte->Size();
  943. _pteCurrent = pte;
  944. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  945. }
  946. TraceMsg(TF_TRAVELLOG, "TL[%X]::AddEntry punk = %X, IsLocal = %d, pte = %X", this, punk, fIsLocalAnchor, pte);
  947. return pte ? S_OK : E_OUTOFMEMORY;
  948. }
  949. void CTravelLog::_Prune(void)
  950. {
  951. // FEATURE: need an increment or something
  952. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  953. while (_cbTotalSize > _cbMaxSize && _pteRoot != _pteCurrent)
  954. {
  955. CTravelEntry *pte = _pteRoot;
  956. _pteRoot = _pteRoot->GetNext();
  957. _cbTotalSize -= pte->Size();
  958. pte->RemoveSelf();
  959. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  960. }
  961. }
  962. HRESULT CTravelLog::UpdateEntry(IUnknown *punk, BOOL fIsLocalAnchor)
  963. {
  964. CTravelEntry *pte = _pteUpdate ? _pteUpdate : _pteCurrent;
  965. // this can happen under weird stress conditions, evidently
  966. if (!pte)
  967. return E_FAIL;
  968. _cbTotalSize -= pte->Size();
  969. HRESULT hr = pte->Update(punk, fIsLocalAnchor);
  970. _cbTotalSize += pte->Size();
  971. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  972. // Debug prints need to be before _Prune() since pte can get freed by _Prune() resulting
  973. // in a crash if pte->Size() is called
  974. TraceMsg(TF_TRAVELLOG, "TL[%X]::UpdateEntry pte->Size() = %d", this, pte->Size());
  975. TraceMsg(TF_TRAVELLOG, "TL[%X]::UpdateEntry punk = %X, IsLocal = %d, hr = %X", this, punk, fIsLocalAnchor, hr);
  976. _Prune();
  977. _pteUpdate = NULL;
  978. return hr;
  979. }
  980. HRESULT CTravelLog::UpdateExternal(IUnknown *punk, IUnknown *punkHLBrowseContext)
  981. {
  982. CTravelEntry *pte = _pteUpdate ? _pteUpdate : _pteCurrent;
  983. ASSERT(punk);
  984. ASSERT(pte);
  985. ASSERT(punkHLBrowseContext);
  986. if (pte)
  987. return pte->UpdateExternal(punk, punkHLBrowseContext);
  988. return E_FAIL;
  989. }
  990. HRESULT CTravelLog::Travel(IUnknown *punk, int iOffset)
  991. {
  992. ASSERT(punk);
  993. HRESULT hr = E_FAIL;
  994. CTravelEntry *pte;
  995. TraceMsg(TF_TRAVELLOG, "TL[%X]::Travel entered with punk = %X, iOffset = %d", this, punk, iOffset);
  996. if (SUCCEEDED(_FindEntryByOffset(punk, iOffset, &pte)))
  997. {
  998. #ifdef DEBUG
  999. TCHAR szPath[MAX_PATH];
  1000. LPITEMIDLIST pidl;
  1001. pte->GetPidl(&pidl);
  1002. SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL);
  1003. ILFree(pidl);
  1004. TraceMsgW(TF_TRAVELLOG, "TL[%X]::URL %s", this, szPath);
  1005. #endif
  1006. // we will update where we are before we move away...
  1007. // but external navigates dont go through the normal activation
  1008. // so we dont want to setup the external to be updated
  1009. // _pteUpdate is also what allows us to Revert().
  1010. if (!_pteCurrent->IsExternal() && !_pteUpdate)
  1011. _pteUpdate = _pteCurrent;
  1012. _pteCurrent = pte;
  1013. hr = _pteCurrent->Invoke(punk);
  1014. //
  1015. // if the entry bails with an error, then we need to reset ourself
  1016. // to what we were. right now, the only place this should happen
  1017. // is if an Abort was returned from SetPositionCookie
  1018. // because somebody aborted during before navigate.
  1019. // but i think that any error means that we can legitimately Revert().
  1020. //
  1021. if (FAILED(hr))
  1022. {
  1023. Revert();
  1024. }
  1025. }
  1026. TraceMsg(TF_TRAVELLOG, "TL[%X]::Travel exited with hr = %X", this, hr);
  1027. return hr;
  1028. }
  1029. //+---------------------------------------------------------------------------
  1030. //
  1031. // Method : CTravelLog::TravelToUrl
  1032. //
  1033. // Interface : ITravelLogEx
  1034. //
  1035. // Synopsis : Travels to the specified URL in the travel log.
  1036. //
  1037. //----------------------------------------------------------------------------
  1038. HRESULT
  1039. CTravelLog::TravelToUrl(IUnknown * punk, UINT uiCP, LPOLESTR lpszUrl)
  1040. {
  1041. ASSERT(punk);
  1042. ASSERT(lpszUrl);
  1043. HRESULT hr;
  1044. LPITEMIDLIST pidl;
  1045. CTravelEntry * pte = NULL;
  1046. TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
  1047. DWORD cchOut = ARRAYSIZE(szUrl);
  1048. hr = UrlCanonicalize(lpszUrl, szUrl, &cchOut, URL_ESCAPE_SPACES_ONLY);
  1049. if (SUCCEEDED(hr))
  1050. {
  1051. hr = IEParseDisplayName(uiCP, szUrl, &pidl);
  1052. if (SUCCEEDED(hr))
  1053. {
  1054. hr = _FindEntryByPidl(punk, pidl, &pte);
  1055. ILFree(pidl);
  1056. if (SUCCEEDED(hr))
  1057. {
  1058. // We will update where we are before we move away...
  1059. // but external navigates don't go through the normal activation
  1060. // so we dont want to setup the external to be updated
  1061. // _pteUpdate is also what allows us to Revert().
  1062. //
  1063. if (!_pteCurrent->IsExternal() && !_pteUpdate)
  1064. {
  1065. _pteUpdate = _pteCurrent;
  1066. }
  1067. _pteCurrent = pte;
  1068. hr = _pteCurrent->Invoke(punk);
  1069. // If the entry bails with an error, then we need to reset ourself
  1070. // to what we were. Right now, the only place this should happen
  1071. // is if an Abort was returned from SetPositionCookie
  1072. // because somebody aborted during before navigate.
  1073. // But i think that any error means that we can legitimately Revert().
  1074. //
  1075. if (FAILED(hr))
  1076. {
  1077. Revert();
  1078. }
  1079. }
  1080. }
  1081. }
  1082. TraceMsg(TF_TRAVELLOG, "TL[%X]::TravelToUrl exited with hr = %X", this, hr);
  1083. return hr;
  1084. }
  1085. HRESULT CTravelLog::_FindEntryByOffset(IUnknown *punk, int iOffset, CTravelEntry **ppte)
  1086. {
  1087. CTravelEntry *pte = _pteCurrent;
  1088. BOOL fAllowLocalAnchor = TRUE;
  1089. if (iOffset < 0)
  1090. {
  1091. while (iOffset && pte)
  1092. {
  1093. pte = pte->GetPrev();
  1094. if (pte && pte->CanInvoke(punk, fAllowLocalAnchor))
  1095. {
  1096. iOffset++;
  1097. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1098. }
  1099. }
  1100. }
  1101. else if (iOffset > 0)
  1102. {
  1103. while (iOffset && pte)
  1104. {
  1105. pte = pte->GetNext();
  1106. if (pte && pte->CanInvoke(punk, fAllowLocalAnchor))
  1107. {
  1108. iOffset--;
  1109. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1110. }
  1111. }
  1112. }
  1113. if (pte)
  1114. {
  1115. *ppte = pte;
  1116. return S_OK;
  1117. }
  1118. return E_FAIL;
  1119. }
  1120. HRESULT CTravelLog::GetTravelEntry(IUnknown *punk, int iOffset, ITravelEntry **ppte)
  1121. {
  1122. HRESULT hr;
  1123. BOOL fCheckExternal = FALSE;
  1124. if (iOffset == TLOG_BACKEXTERNAL)
  1125. {
  1126. iOffset = TLOG_BACK;
  1127. fCheckExternal = TRUE;
  1128. }
  1129. if (iOffset == 0)
  1130. {
  1131. // APPCOMPAT - going back and fore between external apps is dangerous - zekel 24-JUN-97
  1132. // we always fail if the current is external
  1133. // this is because word will attempt to navigate us to
  1134. // the same url instead of FORE when the user selects
  1135. // it from the drop down.
  1136. if (_pteCurrent && _pteCurrent->IsExternal())
  1137. {
  1138. hr = E_FAIL;
  1139. ASSERT(!_pteCurrent->GetPrev());
  1140. TraceMsg(TF_TRAVELLOG, "TL[%X]::GetTravelEntry current is External", this);
  1141. goto Quit;
  1142. }
  1143. }
  1144. CTravelEntry *pte;
  1145. hr = _FindEntryByOffset(punk, iOffset, &pte);
  1146. //
  1147. // If TLOG_BACKEXTERNAL is specified, we return S_OK only if the previous
  1148. // entry is external.
  1149. //
  1150. if (fCheckExternal && SUCCEEDED(hr))
  1151. {
  1152. if (!pte->IsExternal())
  1153. {
  1154. hr = E_FAIL;
  1155. }
  1156. TraceMsg(TF_TRAVELLOG, "TL[%X]::GetTravelEntry(BACKEX)", this);
  1157. }
  1158. if (ppte && SUCCEEDED(hr))
  1159. {
  1160. hr = pte->QueryInterface(IID_PPV_ARG(ITravelEntry, ppte));
  1161. }
  1162. Quit:
  1163. TraceMsg(TF_TRAVELLOG, "TL[%X]::GetTravelEntry iOffset = %d, hr = %X", this, iOffset, hr);
  1164. return hr;
  1165. }
  1166. //+---------------------------------------------------------------------------
  1167. //
  1168. // Method : CTravelLog::FindTravelEntry
  1169. //
  1170. // Synopsis : Finds the travel entry with the specified PIDL and returns
  1171. // the ITravelEntry interface of the entry.
  1172. //
  1173. //----------------------------------------------------------------------------
  1174. HRESULT CTravelLog::FindTravelEntry(IUnknown *punk, LPCITEMIDLIST pidl, ITravelEntry **ppte)
  1175. {
  1176. CTravelEntry * pte = _pteRoot;
  1177. _FindEntryByPidl(punk, pidl, &pte);
  1178. if (pte)
  1179. {
  1180. return pte->QueryInterface(IID_PPV_ARG(ITravelEntry, ppte));
  1181. }
  1182. *ppte = NULL;
  1183. return E_FAIL;
  1184. }
  1185. //+---------------------------------------------------------------------------
  1186. //
  1187. // Method : CTravelLog::_FindEntryByPidl
  1188. //
  1189. // Synopsis : Finds and returns the travel entry with the specified PIDL.
  1190. // This private method returns a CTravelEntry instead of
  1191. // an ITravelEntry.
  1192. //
  1193. //----------------------------------------------------------------------------
  1194. HRESULT
  1195. CTravelLog::_FindEntryByPidl(IUnknown * punk, LPCITEMIDLIST pidl, CTravelEntry ** ppte)
  1196. {
  1197. CTravelEntry * pte = _pteRoot;
  1198. BOOL fAllowLocalAnchor = TRUE;
  1199. ASSERT(punk);
  1200. ASSERT(pidl);
  1201. ASSERT(ppte);
  1202. while (pte)
  1203. {
  1204. if (pte->CanInvoke(punk, fAllowLocalAnchor) && pte->IsEqual(pidl))
  1205. {
  1206. *ppte = pte;
  1207. return S_OK;
  1208. }
  1209. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1210. pte = pte->GetNext();
  1211. }
  1212. *ppte = NULL;
  1213. return E_FAIL;
  1214. }
  1215. //+---------------------------------------------------------------------------
  1216. //
  1217. // Method : CTravelLog::FindEntryByPunk
  1218. //
  1219. // Interface : ITravelLogEx
  1220. //
  1221. // Synopsis : Find the entry object given its punk.
  1222. //
  1223. //----------------------------------------------------------------------------
  1224. HRESULT
  1225. CTravelLog::_FindEntryByPunk(IUnknown * punk, ITravelLogEntry *pteSearch, CTravelEntry ** ppte)
  1226. {
  1227. CTravelEntry *pte = _pteRoot;
  1228. ITravelEntry *pteCur;
  1229. BOOL fAllowLocalAnchor = TRUE;
  1230. ASSERT(ppte);
  1231. // check for the current entry.
  1232. // often the current entry will fail CanInvoke because it's incomplete at this time.
  1233. if (IsSameObject(pteSearch, SAFECAST(_pteCurrent, ITravelEntry*)))
  1234. {
  1235. *ppte = _pteCurrent;
  1236. return S_OK;
  1237. }
  1238. while (pte)
  1239. {
  1240. pteCur = SAFECAST(pte, ITravelEntry*);
  1241. if ((pte->CanInvoke(punk, fAllowLocalAnchor)) && IsSameObject(pteCur, pteSearch))
  1242. {
  1243. *ppte = pte;
  1244. return S_OK;
  1245. }
  1246. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1247. pte = pte->GetNext();
  1248. }
  1249. *ppte = NULL;
  1250. return E_FAIL;
  1251. }
  1252. //+---------------------------------------------------------------------------
  1253. //
  1254. // Method : CTravelLog::FindTravelEntryWithUrl
  1255. //
  1256. // Interface : ITravelLogEx
  1257. //
  1258. // Synopsis : Finds and returns the travel entry with the specified URL.
  1259. //
  1260. //----------------------------------------------------------------------------
  1261. HRESULT
  1262. CTravelLog::FindTravelEntryWithUrl(IUnknown * punk, UINT uiCP, LPOLESTR lpszUrl, ITravelEntry ** ppte)
  1263. {
  1264. LPITEMIDLIST pidl;
  1265. HRESULT hr = E_FAIL;
  1266. ASSERT(punk);
  1267. ASSERT(lpszUrl);
  1268. ASSERT(ppte);
  1269. if (SUCCEEDED(IEParseDisplayNameWithBCW(uiCP, lpszUrl, NULL, &pidl)))
  1270. {
  1271. hr = FindTravelEntry(punk, pidl, ppte);
  1272. ILFree(pidl);
  1273. }
  1274. return hr;
  1275. }
  1276. HRESULT CTravelLog::Clone(ITravelLog **pptl)
  1277. {
  1278. CTravelLog *ptl = new CTravelLog();
  1279. HRESULT hr = S_OK;
  1280. if (ptl && _pteCurrent)
  1281. {
  1282. // first set the current pointer
  1283. hr = _pteCurrent->Clone(&ptl->_pteCurrent);
  1284. if (SUCCEEDED(hr))
  1285. {
  1286. ptl->_cbTotalSize = _cbTotalSize;
  1287. CTravelEntry *pteSrc;
  1288. CTravelEntry *pteClone, *pteDst = ptl->_pteCurrent;
  1289. // then we need to loop forward and set each
  1290. for (pteSrc = _pteCurrent->GetNext(), pteDst = ptl->_pteCurrent;
  1291. pteSrc; pteSrc = pteSrc->GetNext())
  1292. {
  1293. ASSERT(pteDst);
  1294. if (FAILED(pteSrc->Clone(&pteClone)))
  1295. break;
  1296. ASSERT(pteClone);
  1297. pteDst->SetNext(pteClone);
  1298. pteDst = pteClone;
  1299. }
  1300. //then loop back and set them all
  1301. for (pteSrc = _pteCurrent->GetPrev(), pteDst = ptl->_pteCurrent;
  1302. pteSrc; pteSrc = pteSrc->GetPrev())
  1303. {
  1304. ASSERT(pteDst);
  1305. if (FAILED(pteSrc->Clone(&pteClone)))
  1306. break;
  1307. ASSERT(pteClone);
  1308. pteDst->SetPrev(pteClone);
  1309. pteDst = pteClone;
  1310. }
  1311. // the root is the furthest back we could go
  1312. ptl->_pteRoot = pteDst;
  1313. }
  1314. }
  1315. else
  1316. hr = E_OUTOFMEMORY;
  1317. if (SUCCEEDED(hr))
  1318. {
  1319. ptl->QueryInterface(IID_PPV_ARG(ITravelLog, pptl));
  1320. }
  1321. else
  1322. {
  1323. *pptl = NULL;
  1324. }
  1325. if (ptl)
  1326. ptl->Release();
  1327. TraceMsg(TF_TRAVELLOG, "TL[%X]::Clone hr = %x, ptlClone = %X", this, hr, ptl);
  1328. return hr;
  1329. }
  1330. // HACKHACK: 3rd parameter used to be idsTemplate, which we would use to grab the
  1331. // string template. However, since there's no way the caller can specify the hinst
  1332. // of the module in which to look for this resource, this broke in the shdocvw /
  1333. // browseui split (callers would pass offsets into browseui.dll; we'd look for them in
  1334. // shdocvw.dll). My solution is is to ignore this parameter entirely and assume that:
  1335. //
  1336. // if iOffset is negative, the caller wants the "back to" text
  1337. // else, the caller wants the "forward to" text
  1338. //
  1339. // tjgreen 14-july-98.
  1340. //
  1341. HRESULT CTravelLog::GetToolTipText(IUnknown *punk, int iOffset, int, LPWSTR pwzText, DWORD cchText)
  1342. {
  1343. TraceMsg(TF_TRAVELLOG, "TL[%X]::ToolTip entering iOffset = %d, ptlClone = %X", this, iOffset);
  1344. ASSERT(pwzText);
  1345. ASSERT(cchText);
  1346. *pwzText = 0;
  1347. CTravelEntry *pte;
  1348. HRESULT hr = _FindEntryByOffset(punk, iOffset, &pte);
  1349. if (SUCCEEDED(hr))
  1350. {
  1351. ASSERT(pte);
  1352. TCHAR szName[MAX_URL_STRING];
  1353. pte->GetDisplayName(szName, ARRAYSIZE(szName), 0);
  1354. int idsTemplate = (iOffset < 0) ? IDS_NAVIGATEBACKTO : IDS_NAVIGATEFORWARDTO;
  1355. TCHAR szTemplate[80];
  1356. if (MLLoadString(idsTemplate, szTemplate, ARRAYSIZE(szTemplate)))
  1357. {
  1358. DWORD cchTemplateLen = lstrlen(szTemplate);
  1359. DWORD cchLen = cchTemplateLen + lstrlen(szName);
  1360. if (cchLen > cchText)
  1361. {
  1362. // so that we don't overflow the pwzText buffer
  1363. // review: do we even need this now that we are using StringCchPrintf below?
  1364. szName[cchText - cchTemplateLen - 1] = 0;
  1365. }
  1366. StringCchPrintf(pwzText, cchText, szTemplate, szName);
  1367. }
  1368. else
  1369. hr = E_UNEXPECTED;
  1370. }
  1371. TraceMsg(TF_TRAVELLOG, "TL[%X]::ToolTip exiting hr = %X, pwzText = %ls", this, hr, pwzText);
  1372. return hr;
  1373. }
  1374. HRESULT CTravelLog::InsertMenuEntries(IUnknown *punk, HMENU hmenu, int iIns, int idFirst, int idLast, DWORD dwFlags)
  1375. {
  1376. ASSERT(idLast >= idFirst);
  1377. ASSERT(hmenu);
  1378. ASSERT(punk);
  1379. int cItemsBack = idLast - idFirst + 1;
  1380. int cItemsFore = 0;
  1381. CTravelEntry *pte;
  1382. LONG cAdded = 0;
  1383. TraceMsg(TF_TRAVELLOG, "TL[%X]::InsertMenuEntries entered on punk = %X, hmenu = %X, iIns = %d, idRange = %d-%d, flags = %X", this, punk, hmenu, iIns, idFirst, idLast, dwFlags);
  1384. ASSERT(cItemsFore >= 0);
  1385. ASSERT(cItemsBack >= 0);
  1386. if (IsFlagSet(dwFlags, TLMENUF_INCLUDECURRENT))
  1387. cItemsBack--;
  1388. if (IsFlagSet(dwFlags, TLMENUF_BACKANDFORTH))
  1389. {
  1390. cItemsFore = cItemsBack / 2;
  1391. cItemsBack = cItemsBack - cItemsFore;
  1392. }
  1393. else if (IsFlagSet(dwFlags, TLMENUF_FORE))
  1394. {
  1395. cItemsFore = cItemsBack;
  1396. cItemsBack = 0;
  1397. }
  1398. TCHAR szName[40];
  1399. UINT uFlags = MF_STRING | MF_ENABLED | MF_BYPOSITION;
  1400. while (cItemsFore)
  1401. {
  1402. if (SUCCEEDED(_FindEntryByOffset(punk, cItemsFore, &pte)))
  1403. {
  1404. pte->GetDisplayName(szName, ARRAYSIZE(szName), TEGDN_FORSYSTEM);
  1405. ASSERT(*szName);
  1406. FixAmpersands(szName, ARRAYSIZE(szName));
  1407. InsertMenu(hmenu, iIns, uFlags, idLast, szName);
  1408. cAdded++;
  1409. TraceMsg(TF_TRAVELLOG, "TL[%X]::IME Fore id = %d, szName = %s", this, idLast, szName);
  1410. }
  1411. cItemsFore--;
  1412. idLast--;
  1413. }
  1414. if (IsFlagSet(dwFlags, TLMENUF_INCLUDECURRENT))
  1415. {
  1416. // clear the name
  1417. *szName = 0;
  1418. //have to get the title from the actual pbs
  1419. LPITEMIDLIST pidl = NULL;
  1420. IBrowserService *pbs;
  1421. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  1422. {
  1423. pbs->GetPidl(&pidl);
  1424. WCHAR wzTitle[MAX_PATH];
  1425. if (SUCCEEDED(pbs->GetTitle(NULL, wzTitle, ARRAYSIZE(wzTitle))))
  1426. {
  1427. StrCpyN(szName, wzTitle, ARRAYSIZE(szName));
  1428. }
  1429. else if (pidl)
  1430. {
  1431. GetUnescapedUrlIfAppropriate(pidl, szName, ARRAYSIZE(szName));
  1432. }
  1433. pbs->Release();
  1434. }
  1435. if (!SHIsDisplayable(szName, g_fRunOnFE, g_bRunOnNT5) && pidl)
  1436. {
  1437. // Display name isn't system-displayable. Just use the path/url instead.
  1438. SHTitleFromPidl(pidl, szName, ARRAYSIZE(szName), FALSE);
  1439. }
  1440. if (!(*szName))
  1441. TraceMsg(TF_ERROR, "CTravelLog::InsertMenuEntries -- failed to find title for current entry");
  1442. ILFree(pidl);
  1443. FixAmpersands(szName, ARRAYSIZE(szName));
  1444. InsertMenu(hmenu, iIns, uFlags | (IsFlagSet(dwFlags, TLMENUF_CHECKCURRENT) ? MF_CHECKED : 0), idLast, szName);
  1445. cAdded++;
  1446. TraceMsg(TF_TRAVELLOG, "TL[%X]::IME Current id = %d, szName = %s", this, idLast, szName);
  1447. idLast--;
  1448. }
  1449. if (IsFlagSet(dwFlags, TLMENUF_BACKANDFORTH))
  1450. {
  1451. // we need to reverse the order of insertion for back
  1452. // when both directions are displayed
  1453. int i;
  1454. for (i = 1; i <= cItemsBack; i++, idLast--)
  1455. {
  1456. if (SUCCEEDED(_FindEntryByOffset(punk, -i, &pte)))
  1457. {
  1458. pte->GetDisplayName(szName, ARRAYSIZE(szName), TEGDN_FORSYSTEM);
  1459. ASSERT(*szName);
  1460. FixAmpersands(szName, ARRAYSIZE(szName));
  1461. InsertMenu(hmenu, iIns, uFlags, idLast, szName);
  1462. cAdded++;
  1463. TraceMsg(TF_TRAVELLOG, "TL[%X]::IME Back id = %d, szName = %s", this, idLast, szName);
  1464. }
  1465. }
  1466. }
  1467. else while (cItemsBack)
  1468. {
  1469. if (SUCCEEDED(_FindEntryByOffset(punk, -cItemsBack, &pte)))
  1470. {
  1471. pte->GetDisplayName(szName, ARRAYSIZE(szName), TEGDN_FORSYSTEM);
  1472. ASSERT(*szName);
  1473. FixAmpersands(szName, ARRAYSIZE(szName));
  1474. InsertMenu(hmenu, iIns, uFlags, idLast, szName);
  1475. cAdded++;
  1476. TraceMsg(TF_TRAVELLOG, "TL[%X]::IME Back id = %d, szName = %s", this, idLast, szName);
  1477. }
  1478. cItemsBack--;
  1479. idLast--;
  1480. }
  1481. TraceMsg(TF_TRAVELLOG, "TL[%X]::InsertMenuEntries exiting added = %d", this, cAdded);
  1482. return cAdded ? S_OK : S_FALSE;
  1483. }
  1484. DWORD CTravelLog::CountEntries(IUnknown *punk)
  1485. {
  1486. CTravelEntry *pte = _pteRoot;
  1487. DWORD dw = 0;
  1488. BOOL fAllowLocalAnchor = TRUE;
  1489. while (pte)
  1490. {
  1491. if (pte->CanInvoke(punk, fAllowLocalAnchor))
  1492. dw++;
  1493. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1494. pte = pte->GetNext();
  1495. }
  1496. TraceMsg(TF_TRAVELLOG, "TL[%X]::CountEntries count = %d", this, dw);
  1497. return dw;
  1498. }
  1499. HRESULT CTravelLog::Revert(void)
  1500. {
  1501. // this function should only be called when
  1502. // we have travelled, and we stop the travel before finishing
  1503. if (_pteUpdate)
  1504. {
  1505. // trade them back
  1506. _pteCurrent = _pteUpdate;
  1507. _pteUpdate = NULL;
  1508. return S_OK;
  1509. }
  1510. return E_FAIL;
  1511. }
  1512. //
  1513. // delete nodes belonging to the frameset pte
  1514. //
  1515. void CTravelLog::_DeleteFrameSetEntry(IUnknown *punk, CTravelEntry *pte)
  1516. {
  1517. ASSERT(pte);
  1518. CTravelEntry *ptetmp = pte;
  1519. BOOL fAllowLocalAnchor = TRUE;
  1520. while (ptetmp && ptetmp != _pteCurrent)
  1521. ptetmp = ptetmp->GetNext();
  1522. if (ptetmp)
  1523. {
  1524. // entry on left of _pteCurrent , delete on left
  1525. do
  1526. {
  1527. if (pte == _pteRoot)
  1528. _pteRoot = pte->GetNext();
  1529. ptetmp = pte;
  1530. pte = pte->GetPrev();
  1531. fAllowLocalAnchor = fAllowLocalAnchor && ptetmp->IsLocalAnchor();
  1532. _cbTotalSize -= ptetmp->Size();
  1533. ptetmp->RemoveSelf();
  1534. } while (pte && !(pte->CanInvoke(punk, fAllowLocalAnchor)));
  1535. }
  1536. else if (pte)
  1537. {
  1538. do
  1539. {
  1540. ptetmp = pte;
  1541. pte = pte->GetNext();
  1542. fAllowLocalAnchor = fAllowLocalAnchor && ptetmp->IsLocalAnchor();
  1543. _cbTotalSize -= ptetmp->Size();
  1544. ptetmp->RemoveSelf();
  1545. } while (pte && !(pte->CanInvoke(punk, fAllowLocalAnchor)));
  1546. }
  1547. }
  1548. //+---------------------------------------------------------------------------
  1549. //
  1550. // Method : CTravelLog::DeleteIndexEntry
  1551. //
  1552. // Interface : ITravelLogEx
  1553. //
  1554. // Synopsis : Delete the entry given by index.
  1555. //
  1556. //----------------------------------------------------------------------------
  1557. HRESULT CTravelLog::DeleteIndexEntry(IUnknown *punk, int index)
  1558. {
  1559. HRESULT hres = E_FAIL;
  1560. CTravelEntry *pte;
  1561. IBrowserService *pbs;
  1562. BOOL fAllowLocalAnchor = TRUE;
  1563. ASSERT(punk);
  1564. if (index == 0) // don't delete current entry
  1565. return hres;
  1566. hres = _FindEntryByOffset(punk, index, &pte);
  1567. if (SUCCEEDED(hres))
  1568. {
  1569. _DeleteFrameSetEntry(punk, pte);
  1570. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  1571. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  1572. {
  1573. pbs->UpdateBackForwardState();
  1574. pbs->Release();
  1575. }
  1576. }
  1577. return hres;
  1578. }
  1579. //+---------------------------------------------------------------------------
  1580. //
  1581. // Method : CTravelLog::DeleteUrlEntry
  1582. //
  1583. // Interface : ITravelLogEx
  1584. //
  1585. // Synopsis : Delete all the entries given by URL. Fails for current entry.
  1586. //
  1587. //----------------------------------------------------------------------------
  1588. HRESULT CTravelLog::DeleteUrlEntry(IUnknown *punk, UINT uiCP, LPOLESTR lpszUrl)
  1589. {
  1590. HRESULT hres = E_FAIL;
  1591. CTravelEntry *pte;
  1592. IBrowserService *pbs;
  1593. LPITEMIDLIST pidl;
  1594. BOOL fAllowLocalAnchor = TRUE;
  1595. int count = 0;
  1596. ASSERT(punk);
  1597. if (SUCCEEDED(IEParseDisplayNameWithBCW(uiCP, lpszUrl, NULL, &pidl)))
  1598. {
  1599. // delete only if different from current
  1600. if (!_pteCurrent->IsEqual(pidl))
  1601. {
  1602. hres = S_OK;
  1603. while(SUCCEEDED(_FindEntryByPidl(punk, pidl, &pte)))
  1604. {
  1605. _DeleteFrameSetEntry(punk, pte);
  1606. count++;
  1607. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  1608. }
  1609. }
  1610. ILFree(pidl);
  1611. if (count && SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  1612. {
  1613. pbs->UpdateBackForwardState();
  1614. pbs->Release();
  1615. }
  1616. }
  1617. return hres;
  1618. }
  1619. //+---------------------------------------------------------------------------
  1620. //
  1621. // Method : CTravelLog::DeleteEntry
  1622. //
  1623. // Interface : ITravelLogEx
  1624. //
  1625. // Synopsis : Delete the entries given by punk. Fails for current entry.
  1626. //
  1627. //----------------------------------------------------------------------------
  1628. HRESULT CTravelLog::DeleteEntry(IUnknown *punk, ITravelLogEntry *ptleDelete)
  1629. {
  1630. HRESULT hres;
  1631. CTravelEntry *pte;
  1632. BOOL fAllowLocalAnchor = TRUE;
  1633. IBrowserService *pbs;
  1634. ASSERT(punk);
  1635. hres = _FindEntryByPunk(punk, ptleDelete, &pte);
  1636. if (SUCCEEDED(hres) && pte != _pteCurrent) // don't remove current
  1637. {
  1638. _DeleteFrameSetEntry(punk, pte);
  1639. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  1640. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  1641. {
  1642. pbs->UpdateBackForwardState();
  1643. pbs->Release();
  1644. }
  1645. }
  1646. else
  1647. {
  1648. hres = E_FAIL;
  1649. }
  1650. return hres;
  1651. }
  1652. //+---------------------------------------------------------------------------
  1653. //
  1654. // Method : CTravelLog::CountEntryNodes
  1655. //
  1656. // Synopsis : Counts Back/Forward entries including the current one
  1657. // as given by dwFlags
  1658. //
  1659. //----------------------------------------------------------------------------
  1660. HRESULT CTravelLog::CountEntryNodes(IUnknown *punk, DWORD dwFlags, DWORD *pdwCount)
  1661. {
  1662. CTravelEntry *pte;
  1663. BOOL fAllowLocalAnchor = TRUE;
  1664. ASSERT(punk);
  1665. DWORD dwCount = 0;
  1666. if (!_pteCurrent)
  1667. {
  1668. *pdwCount = 0;
  1669. return S_OK;
  1670. }
  1671. if (IsFlagSet(dwFlags, TLMENUF_BACK))
  1672. {
  1673. pte = _pteRoot;
  1674. while (pte != _pteCurrent)
  1675. {
  1676. if (pte->CanInvoke(punk, fAllowLocalAnchor))
  1677. {
  1678. dwCount++;
  1679. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1680. }
  1681. pte = pte->GetNext();
  1682. }
  1683. }
  1684. if (IsFlagSet(dwFlags, TLMENUF_INCLUDECURRENT))
  1685. {
  1686. if (_pteCurrent->CanInvoke(punk, fAllowLocalAnchor))
  1687. {
  1688. dwCount++;
  1689. fAllowLocalAnchor = fAllowLocalAnchor && _pteCurrent->IsLocalAnchor();
  1690. }
  1691. }
  1692. if (IsFlagSet(dwFlags, TLMENUF_FORE))
  1693. {
  1694. pte = _pteCurrent->GetNext();
  1695. while (pte)
  1696. {
  1697. if (pte->CanInvoke(punk, fAllowLocalAnchor))
  1698. {
  1699. dwCount++;
  1700. fAllowLocalAnchor = fAllowLocalAnchor && pte->IsLocalAnchor();
  1701. }
  1702. pte = pte->GetNext();
  1703. }
  1704. }
  1705. *pdwCount = dwCount;
  1706. TraceMsg(TF_TRAVELLOG, "TL[%X]::CountEntryNodes count = %d", this, *pdwCount);
  1707. return S_OK;
  1708. }
  1709. //+---------------------------------------------------------------------------
  1710. //
  1711. // Method : CTravelLog::CreateEnumEntry
  1712. //
  1713. // Synopsis : Returns an enumerator object for the back/fore travel entries
  1714. // as selected by the dwFlags option
  1715. //
  1716. //----------------------------------------------------------------------------
  1717. HRESULT
  1718. CTravelLog::CreateEnumEntry(IUnknown *punk, IEnumTravelLogEntry **ppEnum, DWORD dwFlags)
  1719. {
  1720. ASSERT(punk);
  1721. ASSERT(ppEnum);
  1722. *ppEnum = 0;
  1723. HRESULT hr = E_OUTOFMEMORY;
  1724. CEnumEntry *penum = new CEnumEntry();
  1725. if (penum)
  1726. {
  1727. penum->Init(this, punk, 0, dwFlags);
  1728. *ppEnum = SAFECAST(penum, IEnumTravelLogEntry *);
  1729. hr = S_OK;
  1730. }
  1731. return hr;
  1732. }
  1733. //+---------------------------------------------------------------------------
  1734. //
  1735. // Method : CTravelLogEx::InsertEntry
  1736. //
  1737. // Synopsis : Inserts an entry into the specified position in the
  1738. // travellog and calls Update with the given IUnknown.
  1739. //
  1740. //----------------------------------------------------------------------------
  1741. HRESULT
  1742. CTravelLog::InsertEntry(IUnknown *punkBrowser, ITravelLogEntry *pteRelativeTo, BOOL fPrepend,
  1743. IUnknown* punkTLClient, ITravelLogEntry **ppEntry)
  1744. {
  1745. TraceMsg(TF_TRAVELLOG, "TL[%X]::InsertEntry", this);
  1746. ASSERT(punkBrowser);
  1747. CTravelEntry * pteRelative;
  1748. _FindEntryByPunk(punkBrowser, pteRelativeTo, &pteRelative);
  1749. if (!pteRelative)
  1750. pteRelative = _pteCurrent;
  1751. CTravelEntry *pte = new CTravelEntry(FALSE);
  1752. if (!pte)
  1753. return E_OUTOFMEMORY;
  1754. if (fPrepend)
  1755. {
  1756. // keep relative alive as it's reconnected
  1757. pteRelative->AddRef();
  1758. pte->SetPrev(pteRelative->GetPrev());
  1759. pteRelative->SetPrev(pte);
  1760. if (pteRelative == _pteRoot)
  1761. {
  1762. _pteRoot = pte;
  1763. }
  1764. }
  1765. else
  1766. {
  1767. CTravelEntry * pteNext = pteRelative->GetNext();
  1768. if (pteNext)
  1769. pteNext->AddRef();
  1770. pte->SetNext(pteNext);
  1771. pteRelative->SetNext(pte);
  1772. }
  1773. // update will fill in all the data from the passed in TL Client
  1774. HRESULT hres = pte->Update(punkTLClient, FALSE);
  1775. _cbTotalSize += pte->Size();
  1776. ASSERT(_cbTotalSize == _pteRoot->ListSize());
  1777. IBrowserService *pbs;
  1778. if (SUCCEEDED(punkBrowser->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  1779. {
  1780. pbs->UpdateBackForwardState();
  1781. pbs->Release();
  1782. hres = S_OK;
  1783. }
  1784. // return the ITLEntry for the new entry
  1785. if (SUCCEEDED(hres) && ppEntry)
  1786. {
  1787. hres = pte->QueryInterface(IID_PPV_ARG(ITravelLogEntry, ppEntry));
  1788. }
  1789. return hres;
  1790. }
  1791. //+---------------------------------------------------------------------------
  1792. //
  1793. // Method : CTravelLog::TravelToEntry
  1794. //
  1795. // Synopsis : Travels directly to the specified entry.
  1796. // Invoke cannot be called directly due to update strangeness.
  1797. //
  1798. //----------------------------------------------------------------------------
  1799. HRESULT CTravelLog::TravelToEntry(
  1800. IUnknown *punkBrowser,
  1801. ITravelLogEntry *pteDestination)
  1802. {
  1803. HRESULT hr = E_FAIL;
  1804. CTravelEntry *pte = NULL;
  1805. ASSERT(punkBrowser);
  1806. ASSERT(pteDestination);
  1807. _FindEntryByPunk(punkBrowser, pteDestination , &pte);
  1808. if (pte)
  1809. {
  1810. if (!_pteCurrent->IsExternal() && !_pteUpdate)
  1811. _pteUpdate = _pteCurrent;
  1812. _pteCurrent = pte;
  1813. hr = pte->Invoke(punkBrowser);
  1814. if (FAILED(hr))
  1815. {
  1816. Revert();
  1817. }
  1818. }
  1819. return hr;
  1820. }
  1821. HRESULT CreateTravelLog(ITravelLog **pptl)
  1822. {
  1823. HRESULT hres;
  1824. CTravelLog *ptl = new CTravelLog();
  1825. if (ptl)
  1826. {
  1827. hres = ptl->QueryInterface(IID_PPV_ARG(ITravelLog, pptl));
  1828. ptl->Release();
  1829. }
  1830. else
  1831. {
  1832. *pptl = NULL;
  1833. hres = E_OUTOFMEMORY;
  1834. }
  1835. return hres;
  1836. }
  1837. CEnumEntry::CEnumEntry() :_cRef(1)
  1838. {
  1839. ASSERT(!_ptl);
  1840. ASSERT(!_punk);
  1841. TraceMsg(TF_TRAVELLOG, "EET[%X] created ", this);
  1842. }
  1843. CEnumEntry::~CEnumEntry()
  1844. {
  1845. SAFERELEASE(_ptl);
  1846. SAFERELEASE(_punk);
  1847. TraceMsg(TF_TRAVELLOG, "EET[%X] destroyed ", this);
  1848. }
  1849. HRESULT CEnumEntry::QueryInterface(REFIID riid, void **ppvObj)
  1850. {
  1851. static const QITAB qit[] = {
  1852. QITABENT(CEnumEntry, IEnumTravelLogEntry),
  1853. { 0 },
  1854. };
  1855. return QISearch(this, qit, riid, ppvObj);
  1856. }
  1857. ULONG CEnumEntry::AddRef()
  1858. {
  1859. return InterlockedIncrement(&_cRef);
  1860. }
  1861. ULONG CEnumEntry::Release()
  1862. {
  1863. ASSERT(0 != _cRef);
  1864. ULONG cRef = InterlockedDecrement(&_cRef);
  1865. if (0 == cRef)
  1866. {
  1867. delete this;
  1868. }
  1869. return cRef;
  1870. }
  1871. void CEnumEntry::Init(CTravelLog *ptl, IUnknown *punk, DWORD dwOffset, DWORD dwFlags)
  1872. {
  1873. ASSERT(ptl);
  1874. ASSERT(punk);
  1875. _ptl = ptl;
  1876. _dwFlags = dwFlags;
  1877. _punk = punk;
  1878. _dwOffset = dwOffset;
  1879. _lStart = 0;
  1880. _ptl->AddRef();
  1881. _punk->AddRef();
  1882. SetBase();
  1883. }
  1884. void CEnumEntry::SetBase()
  1885. {
  1886. ITravelEntry *ptetmp;
  1887. // the start is always computed relative to the current entry
  1888. if (IsFlagSet(_dwFlags, TLEF_RELATIVE_FORE|TLEF_RELATIVE_BACK))
  1889. {
  1890. _lStart = -1;
  1891. while (SUCCEEDED(_ptl->GetTravelEntry(_punk, _lStart, &ptetmp)))
  1892. {
  1893. _lStart--;
  1894. ptetmp->Release();
  1895. }
  1896. _lStart++;
  1897. }
  1898. else if (!IsFlagSet(_dwFlags, TLEF_RELATIVE_INCLUDE_CURRENT))
  1899. _lStart = IsFlagSet(_dwFlags, TLEF_RELATIVE_BACK) ? -1: 1;
  1900. }
  1901. HRESULT CEnumEntry::Reset()
  1902. {
  1903. _dwOffset = 0;
  1904. // base changes when add/delete entries
  1905. SetBase();
  1906. return S_OK;
  1907. }
  1908. HRESULT CEnumEntry::Skip(ULONG cElt)
  1909. {
  1910. HRESULT hres;
  1911. ITravelEntry *pte;
  1912. ULONG uCount;
  1913. LONG lIndex;
  1914. BOOL fToRight = IsFlagSet(_dwFlags, TLEF_RELATIVE_FORE);
  1915. BOOL fIncludeCurrent = IsFlagSet(_dwFlags, TLEF_RELATIVE_INCLUDE_CURRENT);
  1916. for (uCount = 0; uCount < cElt; uCount++)
  1917. {
  1918. lIndex = fToRight ? _lStart + _dwOffset : _lStart - _dwOffset;
  1919. if (lIndex || fIncludeCurrent)
  1920. {
  1921. if (SUCCEEDED(hres = _ptl->GetTravelEntry(_punk, lIndex, &pte)))
  1922. {
  1923. _dwOffset++;
  1924. pte->Release();
  1925. }
  1926. else
  1927. break;
  1928. }
  1929. else
  1930. {
  1931. _dwOffset++;
  1932. uCount--;
  1933. }
  1934. }
  1935. if (uCount != cElt)
  1936. hres = S_FALSE;
  1937. return hres;
  1938. }
  1939. HRESULT CEnumEntry::Next(ULONG cElt, ITravelLogEntry **rgpte2, ULONG *pcEltFetched)
  1940. {
  1941. HRESULT hres = S_OK;
  1942. ULONG uCount = 0;
  1943. ITravelEntry *pte;
  1944. LONG lIndex;
  1945. BOOL fToRight;
  1946. BOOL fIncludeCurrent;
  1947. fToRight = IsFlagSet(_dwFlags, TLEF_RELATIVE_FORE);
  1948. fIncludeCurrent = IsFlagSet(_dwFlags, TLEF_RELATIVE_INCLUDE_CURRENT);
  1949. if (pcEltFetched)
  1950. *pcEltFetched = 0;
  1951. for (uCount = 0; uCount < cElt; uCount++)
  1952. {
  1953. lIndex = fToRight ? _lStart + _dwOffset : _lStart - _dwOffset;
  1954. if (lIndex || fIncludeCurrent)
  1955. {
  1956. hres = _ptl->GetTravelEntry(_punk, lIndex, &pte);
  1957. if (SUCCEEDED(hres))
  1958. {
  1959. _dwOffset++;
  1960. pte->QueryInterface(IID_PPV_ARG(ITravelLogEntry, &rgpte2[uCount]));
  1961. pte->Release();
  1962. }
  1963. else
  1964. break;
  1965. }
  1966. else
  1967. {
  1968. _dwOffset++;
  1969. uCount--;
  1970. }
  1971. }
  1972. if (pcEltFetched )
  1973. *pcEltFetched = uCount;
  1974. if (uCount != cElt)
  1975. {
  1976. hres = S_FALSE;
  1977. for(;uCount < cElt; uCount++)
  1978. rgpte2[uCount] = 0;
  1979. }
  1980. return hres;
  1981. }
  1982. STDMETHODIMP CEnumEntry::Clone(IEnumTravelLogEntry **ppEnum)
  1983. {
  1984. HRESULT hres = E_OUTOFMEMORY;
  1985. CEnumEntry *penum;
  1986. ASSERT(ppEnum);
  1987. *ppEnum = 0;
  1988. penum = new CEnumEntry();
  1989. if (penum)
  1990. {
  1991. penum->Init(_ptl, _punk, _dwOffset, _dwFlags);
  1992. *ppEnum = SAFECAST(penum, IEnumTravelLogEntry*);
  1993. hres = S_OK;
  1994. }
  1995. return hres;
  1996. }
  1997. // Helper object for creating new travel entries
  1998. class CPublicTravelLogCreateHelper : public ITravelLogClient, IPersistHistory
  1999. {
  2000. public:
  2001. // *** IUnknown
  2002. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  2003. STDMETHODIMP_(ULONG) AddRef() ;
  2004. STDMETHODIMP_(ULONG) Release();
  2005. // ITravelLogClient methods
  2006. STDMETHODIMP FindWindowByIndex(DWORD dwID, IUnknown **ppunk);
  2007. STDMETHODIMP GetWindowData(WINDOWDATA *pwindata);
  2008. STDMETHODIMP LoadHistoryPosition(LPOLESTR pszUrlLocation, DWORD dwCookie)
  2009. { return SetPositionCookie(dwCookie); }
  2010. // IPersist methods. (dummy)
  2011. STDMETHODIMP GetClassID(CLSID *pClassID)
  2012. { ASSERT(FALSE); return E_NOTIMPL; }
  2013. // IPersistHistory methods. (dummy)
  2014. // These should never be called, but Update QI's the client to see if it supports IPH.
  2015. STDMETHODIMP LoadHistory(IStream *pStream, IBindCtx *pbc)
  2016. { return E_NOTIMPL; }
  2017. STDMETHODIMP SaveHistory(IStream *pStream)
  2018. { ASSERT(FALSE); return S_OK; }
  2019. STDMETHODIMP SetPositionCookie(DWORD dwPositioncookie)
  2020. { return E_NOTIMPL; }
  2021. STDMETHODIMP GetPositionCookie(DWORD *pdwPositioncookie)
  2022. { return E_NOTIMPL; }
  2023. CPublicTravelLogCreateHelper(IBrowserService *pbs, LPCOLESTR pszUrl, LPCOLESTR pszTitle);
  2024. protected:
  2025. ~CPublicTravelLogCreateHelper();
  2026. LONG _cRef;
  2027. IBrowserService *_pbs;
  2028. LPOLESTR _pszUrl;
  2029. LPOLESTR _pszTitle;
  2030. };
  2031. CPublicTravelLogCreateHelper::CPublicTravelLogCreateHelper(IBrowserService *pbs, LPCOLESTR pszUrl, LPCOLESTR pszTitle) : _pbs(pbs), _cRef(1)
  2032. {
  2033. ASSERT(_pbs);
  2034. ASSERT(!_pszUrl);
  2035. ASSERT(!_pszTitle);
  2036. ASSERT(pszUrl);
  2037. ASSERT(pszTitle);
  2038. if (_pbs)
  2039. _pbs->AddRef();
  2040. if (pszUrl)
  2041. {
  2042. SHStrDup(pszUrl, &_pszUrl);
  2043. }
  2044. if (pszTitle)
  2045. {
  2046. SHStrDup(pszTitle, &_pszTitle);
  2047. }
  2048. TraceMsg(TF_TRAVELLOG, "TPLCH[%X] created", this);
  2049. }
  2050. CPublicTravelLogCreateHelper::~CPublicTravelLogCreateHelper()
  2051. {
  2052. SAFERELEASE(_pbs);
  2053. CoTaskMemFree(_pszUrl);
  2054. CoTaskMemFree(_pszTitle);
  2055. TraceMsg(TF_TRAVELLOG, "TPLCH[%X] destroyed ", this);
  2056. }
  2057. HRESULT CPublicTravelLogCreateHelper ::QueryInterface(REFIID riid, void **ppvObj)
  2058. {
  2059. static const QITAB qit[] = {
  2060. QITABENT(CPublicTravelLogCreateHelper , ITravelLogClient),
  2061. QITABENT(CPublicTravelLogCreateHelper , IPersistHistory),
  2062. QITABENT(CPublicTravelLogCreateHelper , IPersist),
  2063. { 0 },
  2064. };
  2065. return QISearch(this, qit, riid, ppvObj);
  2066. }
  2067. ULONG CPublicTravelLogCreateHelper ::AddRef()
  2068. {
  2069. return InterlockedIncrement(&_cRef);
  2070. }
  2071. ULONG CPublicTravelLogCreateHelper ::Release()
  2072. {
  2073. ASSERT(0 != _cRef);
  2074. ULONG cRef = InterlockedDecrement(&_cRef);
  2075. if (0 == cRef)
  2076. {
  2077. delete this;
  2078. }
  2079. return cRef;
  2080. }
  2081. // ITravelLogClient::FindWindowByIndex
  2082. HRESULT
  2083. CPublicTravelLogCreateHelper::FindWindowByIndex(DWORD dwID, IUnknown **ppunk)
  2084. {
  2085. *ppunk = NULL;
  2086. return E_NOTIMPL;
  2087. }
  2088. // ITravelLogClient::GetWindowData
  2089. // turns around and talks to the browser
  2090. HRESULT
  2091. CPublicTravelLogCreateHelper::GetWindowData(WINDOWDATA *pwindata)
  2092. {
  2093. ITravelLogClient2 *pcli;
  2094. HRESULT hres = _pbs->QueryInterface(IID_PPV_ARG(ITravelLogClient2, &pcli));
  2095. if (SUCCEEDED(hres))
  2096. hres = pcli->GetDummyWindowData(_pszUrl, _pszTitle, pwindata);
  2097. if (pcli)
  2098. pcli->Release();
  2099. return SUCCEEDED(hres) ? S_OK : E_FAIL;
  2100. }
  2101. // Implements the publicly exposed interface ITravelLogStg (can be QS'd for from top browser)
  2102. class CPublicTravelLog : public ITravelLogStg
  2103. {
  2104. public:
  2105. // *** IUnknown
  2106. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  2107. STDMETHODIMP_(ULONG) AddRef() ;
  2108. STDMETHODIMP_(ULONG) Release();
  2109. // *** ITravelLogStg specific methods
  2110. STDMETHODIMP CreateEntry(LPCOLESTR pszUrl, LPCOLESTR pszTitle, ITravelLogEntry *ptleRelativeTo,
  2111. BOOL fPrepend, ITravelLogEntry **pptle);
  2112. STDMETHODIMP TravelTo(ITravelLogEntry *ptle);
  2113. STDMETHODIMP EnumEntries(TLENUMF flags, IEnumTravelLogEntry **ppenum);
  2114. STDMETHODIMP FindEntries(TLENUMF flags, LPCOLESTR pszUrl, IEnumTravelLogEntry **ppenum);
  2115. STDMETHODIMP GetCount(TLENUMF flags, DWORD *pcEntries);
  2116. STDMETHODIMP RemoveEntry(ITravelLogEntry *ptle);
  2117. STDMETHODIMP GetRelativeEntry(int iOffset, ITravelLogEntry **ptle);
  2118. CPublicTravelLog(IBrowserService *pbs, ITravelLogEx *ptlx);
  2119. protected:
  2120. ~CPublicTravelLog();
  2121. LONG _cRef;
  2122. IBrowserService *_pbs;
  2123. ITravelLogEx *_ptlx;
  2124. };
  2125. CPublicTravelLog::CPublicTravelLog(IBrowserService *pbs, ITravelLogEx *ptlx) : _pbs(pbs), _ptlx(ptlx), _cRef(1)
  2126. {
  2127. ASSERT(pbs);
  2128. ASSERT(ptlx);
  2129. // We don't addref _pbs because we are always contained within the browser serivce,
  2130. // so avoid the circular ref.
  2131. if (_ptlx)
  2132. _ptlx->AddRef();
  2133. TraceMsg(TF_TRAVELLOG, "TLP[%X] created", this);
  2134. }
  2135. CPublicTravelLog::~CPublicTravelLog()
  2136. {
  2137. // We don't need to release _pbs because we are always contained within the browser serivce,
  2138. // so we didn't addref to avoid the circular ref so don't release
  2139. SAFERELEASE(_ptlx);
  2140. TraceMsg(TF_TRAVELLOG, "TLP[%X] destroyed ", this);
  2141. }
  2142. HRESULT CPublicTravelLog::QueryInterface(REFIID riid, void **ppvObj)
  2143. {
  2144. static const QITAB qit[] = {
  2145. QITABENT(CPublicTravelLog, ITravelLogStg), // IID_ITravelLogStg
  2146. { 0 },
  2147. };
  2148. return QISearch(this, qit, riid, ppvObj);
  2149. }
  2150. ULONG CPublicTravelLog::AddRef()
  2151. {
  2152. return InterlockedIncrement(&_cRef);
  2153. }
  2154. ULONG CPublicTravelLog::Release()
  2155. {
  2156. ASSERT(0 != _cRef);
  2157. ULONG cRef = InterlockedDecrement(&_cRef);
  2158. if (0 == cRef)
  2159. {
  2160. delete this;
  2161. }
  2162. return cRef;
  2163. }
  2164. //+---------------------------------------------------------------------------
  2165. //
  2166. // Method : CPublicTravelLog::CreateEntry
  2167. //
  2168. // Interface : ITravelLogStg
  2169. //
  2170. // Synopsis : Insert a new dummy entry.
  2171. // Creates an entry in the travel log and passes CPTHCEHelper
  2172. // as travel log client; that gets called back and fills in the
  2173. // data from the browser.
  2174. //
  2175. //----------------------------------------------------------------------------
  2176. HRESULT CPublicTravelLog::CreateEntry(LPCOLESTR pszUrl, LPCOLESTR pszTitle, ITravelLogEntry *ptleRelativeTo,
  2177. BOOL fPrepend, ITravelLogEntry **pptle)
  2178. {
  2179. HRESULT hres = E_FAIL;
  2180. CPublicTravelLogCreateHelper * ptlch;
  2181. ITravelLogClient *ptlc;
  2182. ptlch = new CPublicTravelLogCreateHelper(_pbs, pszUrl, pszTitle);
  2183. if (!ptlch)
  2184. return E_OUTOFMEMORY;
  2185. ptlc = SAFECAST(ptlch, ITravelLogClient *);
  2186. if (ptlc)
  2187. {
  2188. // Create TLogEntry and have it get its data from the helper.
  2189. hres = _ptlx->InsertEntry(_pbs, ptleRelativeTo, fPrepend, ptlc, pptle);
  2190. }
  2191. ptlc->Release();
  2192. return hres;
  2193. }
  2194. HRESULT CPublicTravelLog::TravelTo(ITravelLogEntry *ptle)
  2195. {
  2196. if (ptle)
  2197. return _ptlx->TravelToEntry(_pbs, ptle);
  2198. else
  2199. return E_POINTER;
  2200. }
  2201. //+---------------------------------------------------------------------------
  2202. //
  2203. // Method : CPublicTravelLog::EnumEntries
  2204. //
  2205. // Interface : ITravelLogStg
  2206. //
  2207. // Synopsis : Get an enumerators for specific entries given by flags.
  2208. // Flags should match with those used by ITravelLogEx!
  2209. //
  2210. //----------------------------------------------------------------------------
  2211. HRESULT CPublicTravelLog::EnumEntries(TLENUMF flags, IEnumTravelLogEntry **ppenum)
  2212. {
  2213. return _ptlx->CreateEnumEntry(_pbs, ppenum, flags);
  2214. }
  2215. //+---------------------------------------------------------------------------
  2216. //
  2217. // Method : CPublicTravelLog::FindEntries
  2218. //
  2219. // Interface : ITravelLogStg
  2220. //
  2221. // Synopsis : Allow to retrieve duplicate entries.
  2222. // Flags should match with those used by ITravelLogEx!
  2223. //
  2224. //----------------------------------------------------------------------------
  2225. HRESULT CPublicTravelLog::FindEntries(TLENUMF flags, LPCOLESTR pszUrl, IEnumTravelLogEntry **ppenum)
  2226. {
  2227. return E_NOTIMPL;
  2228. }
  2229. //+---------------------------------------------------------------------------
  2230. //
  2231. // Method : CPublicTravelLog::GetCount
  2232. //
  2233. // Interface : ITravelLogStg
  2234. //
  2235. // Synopsis : Public methods to get ITravelLogEx count.
  2236. // Flags should match with those used by ITravelLogEx!
  2237. //
  2238. //----------------------------------------------------------------------------
  2239. HRESULT CPublicTravelLog::GetCount(TLENUMF flags, DWORD *pcEntries)
  2240. {
  2241. return _ptlx->CountEntryNodes(_pbs, flags, pcEntries);
  2242. }
  2243. //+---------------------------------------------------------------------------
  2244. //
  2245. // Method : CPublicTravelLog::RemoveEntry
  2246. //
  2247. // Interface : ITravelLogStg
  2248. //
  2249. // Synopsis : Delete the entry ant its frameset.
  2250. //
  2251. //----------------------------------------------------------------------------
  2252. HRESULT CPublicTravelLog::RemoveEntry(ITravelLogEntry *ptle)
  2253. {
  2254. HRESULT hr = E_FAIL;
  2255. if (ptle)
  2256. hr = _ptlx->DeleteEntry(_pbs, ptle);
  2257. return hr;
  2258. }
  2259. HRESULT CPublicTravelLog::GetRelativeEntry(int iOffset, ITravelLogEntry **pptle)
  2260. {
  2261. HRESULT hr = E_FAIL;
  2262. ITravelEntry* pte;
  2263. ITravelLog* ptl;
  2264. if (SUCCEEDED(_ptlx->QueryInterface(IID_PPV_ARG(ITravelLog, &ptl))))
  2265. {
  2266. hr = ptl->GetTravelEntry(_pbs, iOffset, &pte);
  2267. if (SUCCEEDED(hr) && pte)
  2268. {
  2269. hr = pte->QueryInterface(IID_PPV_ARG(ITravelLogEntry, pptle));
  2270. pte->Release();
  2271. }
  2272. ptl->Release();
  2273. }
  2274. return hr;
  2275. }
  2276. // public method used by the browser to create us
  2277. HRESULT CreatePublicTravelLog(IBrowserService *pbs, ITravelLogEx* ptlx, ITravelLogStg **pptlstg)
  2278. {
  2279. HRESULT hres;
  2280. CPublicTravelLog *ptlp = new CPublicTravelLog(pbs, ptlx);
  2281. if (ptlp)
  2282. {
  2283. hres = ptlp->QueryInterface(IID_PPV_ARG(ITravelLogStg, pptlstg));
  2284. ptlp->Release();
  2285. }
  2286. else
  2287. {
  2288. *pptlstg = NULL;
  2289. hres = E_OUTOFMEMORY;
  2290. }
  2291. return hres;
  2292. }