Source code of Windows XP (NT5)
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.

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