4 * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 Implements a class that keeps track of a PIDL history and allows
23 navigation forward and backward. This really should be in shdocvw, but it
24 is not registered for external instantiation, and the entire IBrowserService
25 hierarchy that normally spans browseui and shdocvw are collapsed into one
26 hierarchy in browseui, so I am moving it to browseui for now. If someone
27 decides to refactor code later, it wouldn't be difficult to move it.
30 ****Does original travel log update the current item in the Travel method before or after calling ITravelEntry::Invoke?
31 ****Change to load maximum size from registry
32 ****Add code to track current size
33 ****Fix InsertMenuEntries to not exceed limit of menu item ids provided. Perhaps the method should try to be intelligent and if there are
34 too many items, center around the current item? Could cause dispatch problems...
35 ****Move tool tip text templates to resources
36 **Simplify code in InsertMenuEntries
37 Implement UpdateExternal
38 Implement FindTravelEntry
46 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
50 CTravelEntry
*fNextEntry
;
51 CTravelEntry
*fPreviousEntry
;
54 HGLOBAL fPersistState
;
58 HRESULT
GetToolTipText(IUnknown
*punk
, LPWSTR pwzText
) const;
61 // *** ITravelEntry methods ***
62 virtual HRESULT STDMETHODCALLTYPE
Invoke(IUnknown
*punk
);
63 virtual HRESULT STDMETHODCALLTYPE
Update(IUnknown
*punk
, BOOL fIsLocalAnchor
);
64 virtual HRESULT STDMETHODCALLTYPE
GetPidl(LPITEMIDLIST
*ppidl
);
66 BEGIN_COM_MAP(CTravelEntry
)
67 COM_INTERFACE_ENTRY_IID(IID_ITravelEntry
, ITravelEntry
)
72 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
76 CTravelEntry
*fListHead
;
77 CTravelEntry
*fListTail
;
78 CTravelEntry
*fCurrentEntry
;
81 unsigned long fEntryCount
;
86 HRESULT
FindRelativeEntry(int offset
, CTravelEntry
**foundEntry
);
87 void DeleteChain(CTravelEntry
*startHere
);
88 void AppendEntry(CTravelEntry
*afterEntry
, CTravelEntry
*newEntry
);
91 // *** ITravelLog methods ***
92 virtual HRESULT STDMETHODCALLTYPE
AddEntry(IUnknown
*punk
, BOOL fIsLocalAnchor
);
93 virtual HRESULT STDMETHODCALLTYPE
UpdateEntry(IUnknown
*punk
, BOOL fIsLocalAnchor
);
94 virtual HRESULT STDMETHODCALLTYPE
UpdateExternal(IUnknown
*punk
, IUnknown
*punkHLBrowseContext
);
95 virtual HRESULT STDMETHODCALLTYPE
Travel(IUnknown
*punk
, int iOffset
);
96 virtual HRESULT STDMETHODCALLTYPE
GetTravelEntry(IUnknown
*punk
, int iOffset
, ITravelEntry
**ppte
);
97 virtual HRESULT STDMETHODCALLTYPE
FindTravelEntry(IUnknown
*punk
, LPCITEMIDLIST pidl
, ITravelEntry
**ppte
);
98 virtual HRESULT STDMETHODCALLTYPE
GetToolTipText(IUnknown
*punk
, int iOffset
, int idsTemplate
, LPWSTR pwzText
, DWORD cchText
);
99 virtual HRESULT STDMETHODCALLTYPE
InsertMenuEntries(IUnknown
*punk
, HMENU hmenu
, int nPos
, int idFirst
, int idLast
, DWORD dwFlags
);
100 virtual HRESULT STDMETHODCALLTYPE
Clone(ITravelLog
**pptl
);
101 virtual DWORD STDMETHODCALLTYPE
CountEntries(IUnknown
*punk
);
102 virtual HRESULT STDMETHODCALLTYPE
Revert();
104 BEGIN_COM_MAP(CTravelLog
)
105 COM_INTERFACE_ENTRY_IID(IID_ITravelLog
, ITravelLog
)
109 CTravelEntry::CTravelEntry()
112 fPreviousEntry
= NULL
;
114 fPersistState
= NULL
;
117 CTravelEntry::~CTravelEntry()
120 GlobalFree(fPersistState
);
123 HRESULT
CTravelEntry::GetToolTipText(IUnknown
*punk
, LPWSTR pwzText
) const
127 hResult
= ILGetDisplayNameEx(NULL
, fPIDL
, pwzText
, ILGDN_NORMAL
);
133 long CTravelEntry::GetSize() const
138 HRESULT STDMETHODCALLTYPE
CTravelEntry::Invoke(IUnknown
*punk
)
140 CComPtr
<IPersistHistory
> persistHistory
;
141 CComPtr
<IStream
> globalStream
;
144 hResult
= punk
->QueryInterface(IID_IPersistHistory
, (void **)&persistHistory
);
147 hResult
= CreateStreamOnHGlobal(fPersistState
, FALSE
, &globalStream
);
150 hResult
= persistHistory
->LoadHistory(globalStream
, NULL
);
156 HRESULT STDMETHODCALLTYPE
CTravelEntry::Update(IUnknown
*punk
, BOOL fIsLocalAnchor
)
158 CComPtr
<ITravelLogClient
> travelLogClient
;
159 CComPtr
<IPersistHistory
> persistHistory
;
160 CComPtr
<IStream
> globalStream
;
161 WINDOWDATA windowData
;
162 HGLOBAL globalStorage
;
167 GlobalFree(fPersistState
);
168 fPersistState
= NULL
;
169 hResult
= punk
->QueryInterface(IID_ITravelLogClient
, (void **)&travelLogClient
);
172 hResult
= travelLogClient
->GetWindowData(&windowData
);
175 fPIDL
= windowData
.pidl
;
176 // TODO: Properly free the windowData
177 hResult
= punk
->QueryInterface(IID_IPersistHistory
, (void **)&persistHistory
);
180 globalStorage
= GlobalAlloc(GMEM_FIXED
, 0);
181 hResult
= CreateStreamOnHGlobal(globalStorage
, FALSE
, &globalStream
);
184 hResult
= persistHistory
->SaveHistory(globalStream
);
187 hResult
= GetHGlobalFromStream(globalStream
, &fPersistState
);
193 HRESULT STDMETHODCALLTYPE
CTravelEntry::GetPidl(LPITEMIDLIST
*ppidl
)
197 *ppidl
= ILClone(fPIDL
);
199 return E_OUTOFMEMORY
;
203 CTravelLog::CTravelLog()
207 fCurrentEntry
= NULL
;
213 CTravelLog::~CTravelLog()
215 CTravelEntry
*anEntry
;
219 while (anEntry
!= NULL
)
221 next
= anEntry
->fNextEntry
;
227 HRESULT
CTravelLog::Initialize()
229 fMaximumSize
= 1024 * 1024; // TODO: change to read this from registry
230 // Software\Microsoft\Windows\CurrentVersion\Explorer\TravelLog
235 HRESULT
CTravelLog::FindRelativeEntry(int offset
, CTravelEntry
**foundEntry
)
237 CTravelEntry
*curEntry
;
240 curEntry
= fCurrentEntry
;
243 while (offset
< 0 && curEntry
!= NULL
)
245 curEntry
= curEntry
->fPreviousEntry
;
251 while (offset
> 0 && curEntry
!= NULL
)
253 curEntry
= curEntry
->fNextEntry
;
257 if (curEntry
== NULL
)
259 *foundEntry
= curEntry
;
263 void CTravelLog::DeleteChain(CTravelEntry
*startHere
)
265 CTravelEntry
*saveNext
;
268 if (startHere
->fPreviousEntry
!= NULL
)
270 startHere
->fPreviousEntry
->fNextEntry
= NULL
;
271 fListTail
= startHere
->fPreviousEntry
;
278 while (startHere
!= NULL
)
280 saveNext
= startHere
->fNextEntry
;
281 itemSize
= startHere
->GetSize();
282 fCurrentSize
-= itemSize
;
283 startHere
->Release();
284 startHere
= saveNext
;
289 void CTravelLog::AppendEntry(CTravelEntry
*afterEntry
, CTravelEntry
*newEntry
)
291 if (afterEntry
== NULL
)
293 fListHead
= newEntry
;
294 fListTail
= newEntry
;
298 newEntry
->fNextEntry
= afterEntry
->fNextEntry
;
299 afterEntry
->fNextEntry
= newEntry
;
300 newEntry
->fPreviousEntry
= afterEntry
;
301 if (newEntry
->fNextEntry
== NULL
)
302 fListTail
= newEntry
;
304 newEntry
->fNextEntry
->fPreviousEntry
= newEntry
;
309 HRESULT STDMETHODCALLTYPE
CTravelLog::AddEntry(IUnknown
*punk
, BOOL fIsLocalAnchor
)
311 CComObject
<CTravelEntry
> *newEntry
;
316 ATLTRY (newEntry
= new CComObject
<CTravelEntry
>);
317 if (newEntry
== NULL
)
318 return E_OUTOFMEMORY
;
320 if (fCurrentEntry
!= NULL
&& fCurrentEntry
->fNextEntry
!= NULL
)
321 DeleteChain(fCurrentEntry
->fNextEntry
);
322 AppendEntry(fCurrentEntry
, newEntry
);
323 itemSize
= newEntry
->GetSize();
324 fCurrentSize
+= itemSize
;
325 fCurrentEntry
= newEntry
;
329 HRESULT STDMETHODCALLTYPE
CTravelLog::UpdateEntry(IUnknown
*punk
, BOOL fIsLocalAnchor
)
333 if (fCurrentEntry
== NULL
)
335 return fCurrentEntry
->Update(punk
, fIsLocalAnchor
);
338 HRESULT STDMETHODCALLTYPE
CTravelLog::UpdateExternal(IUnknown
*punk
, IUnknown
*punkHLBrowseContext
)
343 HRESULT STDMETHODCALLTYPE
CTravelLog::Travel(IUnknown
*punk
, int iOffset
)
345 CTravelEntry
*destinationEntry
;
348 hResult
= FindRelativeEntry(iOffset
, &destinationEntry
);
351 fCurrentEntry
= destinationEntry
;
352 hResult
= destinationEntry
->Invoke(punk
);
358 HRESULT STDMETHODCALLTYPE
CTravelLog::GetTravelEntry(IUnknown
*punk
, int iOffset
, ITravelEntry
**ppte
)
360 CTravelEntry
*destinationEntry
;
363 hResult
= FindRelativeEntry(iOffset
, &destinationEntry
);
366 return destinationEntry
->QueryInterface(IID_ITravelEntry
, (void **)ppte
);
369 HRESULT STDMETHODCALLTYPE
CTravelLog::FindTravelEntry(IUnknown
*punk
, LPCITEMIDLIST pidl
, ITravelEntry
**ppte
)
373 if (punk
== NULL
|| pidl
== NULL
)
378 HRESULT STDMETHODCALLTYPE
CTravelLog::GetToolTipText(IUnknown
*punk
, int iOffset
, int idsTemplate
, LPWSTR pwzText
, DWORD cchText
)
380 CTravelEntry
*destinationEntry
;
381 wchar_t tempString
[MAX_PATH
];
382 wchar_t templateString
[200];
387 if (punk
== NULL
|| cchText
== 0)
389 hResult
= FindRelativeEntry(iOffset
, &destinationEntry
);
392 hResult
= destinationEntry
->GetToolTipText(punk
, tempString
);
397 wcscpy(templateString
, L
"Back to %s");
401 wcscpy(templateString
, L
"Forward to %s");
403 _snwprintf(pwzText
, cchText
, templateString
, tempString
);
407 static void FixAmpersands(wchar_t *buffer
)
409 wchar_t tempBuffer
[MAX_PATH
* 2];
424 wcscpy(buffer
, tempBuffer
);
427 HRESULT STDMETHODCALLTYPE
CTravelLog::InsertMenuEntries(IUnknown
*punk
, HMENU hmenu
, int nPos
, int idFirst
, int idLast
, DWORD dwFlags
)
429 CTravelEntry
*currentItem
;
430 MENUITEMINFO menuItemInfo
;
431 wchar_t itemTextBuffer
[MAX_PATH
* 2];
434 // TLMENUF_BACK - include back entries
435 // TLMENUF_INCLUDECURRENT - include current entry, if TLMENUF_CHECKCURRENT then check the entry
436 // TLMENUF_FORE - include next entries
437 // if fore+back, list from oldest to newest
438 // if back, list from newest to oldest
439 // if fore, list from newest to oldest
441 // don't forget to patch ampersands before adding to menu
444 if (idLast
<= idFirst
)
446 menuItemInfo
.cbSize
= sizeof(menuItemInfo
);
447 menuItemInfo
.fMask
= MIIM_FTYPE
| MIIM_ID
| MIIM_STATE
| MIIM_STRING
;
448 menuItemInfo
.fType
= MFT_STRING
;
449 menuItemInfo
.wID
= idFirst
;
450 menuItemInfo
.fState
= MFS_ENABLED
;
451 menuItemInfo
.dwTypeData
= itemTextBuffer
;
452 if ((dwFlags
& TLMENUF_BACK
) != 0)
454 if ((dwFlags
& TLMENUF_FORE
) != 0)
456 currentItem
= fCurrentEntry
;
457 if (currentItem
!= NULL
)
459 while (currentItem
->fPreviousEntry
!= NULL
)
460 currentItem
= currentItem
->fPreviousEntry
;
462 while (currentItem
!= fCurrentEntry
)
464 hResult
= currentItem
->GetToolTipText(punk
, itemTextBuffer
);
465 if (SUCCEEDED(hResult
))
467 FixAmpersands(itemTextBuffer
);
468 if (InsertMenuItem(hmenu
, nPos
, TRUE
, &menuItemInfo
))
474 currentItem
= currentItem
->fNextEntry
;
479 currentItem
= fCurrentEntry
;
480 if (currentItem
!= NULL
)
481 currentItem
= currentItem
->fPreviousEntry
;
482 while (currentItem
!= NULL
)
484 hResult
= currentItem
->GetToolTipText(punk
, itemTextBuffer
);
485 if (SUCCEEDED(hResult
))
487 FixAmpersands(itemTextBuffer
);
488 if (InsertMenuItem(hmenu
, nPos
, TRUE
, &menuItemInfo
))
494 currentItem
= currentItem
->fPreviousEntry
;
498 if ((dwFlags
& TLMENUF_INCLUDECURRENT
) != 0)
500 if (fCurrentEntry
!= NULL
)
502 hResult
= fCurrentEntry
->GetToolTipText(punk
, itemTextBuffer
);
503 if (SUCCEEDED(hResult
))
505 FixAmpersands(itemTextBuffer
);
506 if ((dwFlags
& TLMENUF_CHECKCURRENT
) != 0)
507 menuItemInfo
.fState
|= MFS_CHECKED
;
508 if (InsertMenuItem(hmenu
, nPos
, TRUE
, &menuItemInfo
))
513 menuItemInfo
.fState
&= ~MFS_CHECKED
;
517 if ((dwFlags
& TLMENUF_FORE
) != 0)
519 currentItem
= fCurrentEntry
;
520 if (currentItem
!= NULL
)
521 currentItem
= currentItem
->fNextEntry
;
522 while (currentItem
!= NULL
)
524 hResult
= currentItem
->GetToolTipText(punk
, itemTextBuffer
);
525 if (SUCCEEDED(hResult
))
527 FixAmpersands(itemTextBuffer
);
528 if (InsertMenuItem(hmenu
, nPos
, TRUE
, &menuItemInfo
))
534 currentItem
= currentItem
->fNextEntry
;
540 HRESULT STDMETHODCALLTYPE
CTravelLog::Clone(ITravelLog
**pptl
)
549 DWORD STDMETHODCALLTYPE
CTravelLog::CountEntries(IUnknown
*punk
)
556 HRESULT STDMETHODCALLTYPE
CTravelLog::Revert()
558 // remove the current entry?
562 HRESULT
CreateTravelLog(REFIID riid
, void **ppv
)
564 CComObject
<CTravelLog
> *theTravelLog
;
570 ATLTRY (theTravelLog
= new CComObject
<CTravelLog
>);
571 if (theTravelLog
== NULL
)
572 return E_OUTOFMEMORY
;
573 hResult
= theTravelLog
->QueryInterface (riid
, (void **)ppv
);
574 if (FAILED (hResult
))
579 hResult
= theTravelLog
->Initialize();