Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentravellog.cpp
Go to the documentation of this file.
00001 /* 00002 * ReactOS Explorer 00003 * 00004 * Copyright 2009 Andrew Hill <ash77 at domain reactos.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 */ 00020 00021 /* 00022 Implements a class that keeps track of a PIDL history and allows 00023 navigation forward and backward. This really should be in shdocvw, but it 00024 is not registered for external instantiation, and the entire IBrowserService 00025 hierarchy that normally spans browseui and shdocvw are collapsed into one 00026 hierarchy in browseui, so I am moving it to browseui for now. If someone 00027 decides to refactor code later, it wouldn't be difficult to move it. 00028 00029 TODO: 00030 ****Does original travel log update the current item in the Travel method before or after calling ITravelEntry::Invoke? 00031 ****Change to load maximum size from registry 00032 ****Add code to track current size 00033 ****Fix InsertMenuEntries to not exceed limit of menu item ids provided. Perhaps the method should try to be intelligent and if there are 00034 too many items, center around the current item? Could cause dispatch problems... 00035 ****Move tool tip text templates to resources 00036 **Simplify code in InsertMenuEntries 00037 Implement UpdateExternal 00038 Implement FindTravelEntry 00039 Implement Clone 00040 Implement Revert 00041 00042 */ 00043 #include "precomp.h" 00044 00045 class CTravelEntry : 00046 public CComObjectRootEx<CComMultiThreadModelNoCS>, 00047 public ITravelEntry 00048 { 00049 public: 00050 CTravelEntry *fNextEntry; 00051 CTravelEntry *fPreviousEntry; 00052 private: 00053 LPITEMIDLIST fPIDL; 00054 HGLOBAL fPersistState; 00055 public: 00056 CTravelEntry(); 00057 ~CTravelEntry(); 00058 HRESULT GetToolTipText(IUnknown *punk, LPWSTR pwzText) const; 00059 long GetSize() const; 00060 00061 // *** ITravelEntry methods *** 00062 virtual HRESULT STDMETHODCALLTYPE Invoke(IUnknown *punk); 00063 virtual HRESULT STDMETHODCALLTYPE Update(IUnknown *punk, BOOL fIsLocalAnchor); 00064 virtual HRESULT STDMETHODCALLTYPE GetPidl(LPITEMIDLIST *ppidl); 00065 00066 BEGIN_COM_MAP(CTravelEntry) 00067 COM_INTERFACE_ENTRY_IID(IID_ITravelEntry, ITravelEntry) 00068 END_COM_MAP() 00069 }; 00070 00071 class CTravelLog : 00072 public CComObjectRootEx<CComMultiThreadModelNoCS>, 00073 public ITravelLog 00074 { 00075 private: 00076 CTravelEntry *fListHead; 00077 CTravelEntry *fListTail; 00078 CTravelEntry *fCurrentEntry; 00079 long fMaximumSize; 00080 long fCurrentSize; 00081 unsigned long fEntryCount; 00082 public: 00083 CTravelLog(); 00084 ~CTravelLog(); 00085 HRESULT Initialize(); 00086 HRESULT FindRelativeEntry(int offset, CTravelEntry **foundEntry); 00087 void DeleteChain(CTravelEntry *startHere); 00088 void AppendEntry(CTravelEntry *afterEntry, CTravelEntry *newEntry); 00089 public: 00090 00091 // *** ITravelLog methods *** 00092 virtual HRESULT STDMETHODCALLTYPE AddEntry(IUnknown *punk, BOOL fIsLocalAnchor); 00093 virtual HRESULT STDMETHODCALLTYPE UpdateEntry(IUnknown *punk, BOOL fIsLocalAnchor); 00094 virtual HRESULT STDMETHODCALLTYPE UpdateExternal(IUnknown *punk, IUnknown *punkHLBrowseContext); 00095 virtual HRESULT STDMETHODCALLTYPE Travel(IUnknown *punk, int iOffset); 00096 virtual HRESULT STDMETHODCALLTYPE GetTravelEntry(IUnknown *punk, int iOffset, ITravelEntry **ppte); 00097 virtual HRESULT STDMETHODCALLTYPE FindTravelEntry(IUnknown *punk, LPCITEMIDLIST pidl, ITravelEntry **ppte); 00098 virtual HRESULT STDMETHODCALLTYPE GetToolTipText(IUnknown *punk, int iOffset, int idsTemplate, LPWSTR pwzText, DWORD cchText); 00099 virtual HRESULT STDMETHODCALLTYPE InsertMenuEntries(IUnknown *punk, HMENU hmenu, int nPos, int idFirst, int idLast, DWORD dwFlags); 00100 virtual HRESULT STDMETHODCALLTYPE Clone(ITravelLog **pptl); 00101 virtual DWORD STDMETHODCALLTYPE CountEntries(IUnknown *punk); 00102 virtual HRESULT STDMETHODCALLTYPE Revert(); 00103 00104 BEGIN_COM_MAP(CTravelLog) 00105 COM_INTERFACE_ENTRY_IID(IID_ITravelLog, ITravelLog) 00106 END_COM_MAP() 00107 }; 00108 00109 CTravelEntry::CTravelEntry() 00110 { 00111 fNextEntry = NULL; 00112 fPreviousEntry = NULL; 00113 fPIDL = NULL; 00114 fPersistState = NULL; 00115 } 00116 00117 CTravelEntry::~CTravelEntry() 00118 { 00119 ILFree(fPIDL); 00120 GlobalFree(fPersistState); 00121 } 00122 00123 HRESULT CTravelEntry::GetToolTipText(IUnknown *punk, LPWSTR pwzText) const 00124 { 00125 HRESULT hResult; 00126 00127 hResult = ILGetDisplayNameEx(NULL, fPIDL, pwzText, ILGDN_NORMAL); 00128 if (FAILED(hResult)) 00129 return hResult; 00130 return S_OK; 00131 } 00132 00133 long CTravelEntry::GetSize() const 00134 { 00135 return 0; 00136 } 00137 00138 HRESULT STDMETHODCALLTYPE CTravelEntry::Invoke(IUnknown *punk) 00139 { 00140 CComPtr<IPersistHistory> persistHistory; 00141 CComPtr<IStream> globalStream; 00142 HRESULT hResult; 00143 00144 hResult = punk->QueryInterface(IID_IPersistHistory, (void **)&persistHistory); 00145 if (FAILED(hResult)) 00146 return hResult; 00147 hResult = CreateStreamOnHGlobal(fPersistState, FALSE, &globalStream); 00148 if (FAILED(hResult)) 00149 return hResult; 00150 hResult = persistHistory->LoadHistory(globalStream, NULL); 00151 if (FAILED(hResult)) 00152 return hResult; 00153 return S_OK; 00154 } 00155 00156 HRESULT STDMETHODCALLTYPE CTravelEntry::Update(IUnknown *punk, BOOL fIsLocalAnchor) 00157 { 00158 CComPtr<ITravelLogClient> travelLogClient; 00159 CComPtr<IPersistHistory> persistHistory; 00160 CComPtr<IStream> globalStream; 00161 WINDOWDATA windowData; 00162 HGLOBAL globalStorage; 00163 HRESULT hResult; 00164 00165 ILFree(fPIDL); 00166 fPIDL = NULL; 00167 GlobalFree(fPersistState); 00168 fPersistState = NULL; 00169 hResult = punk->QueryInterface(IID_ITravelLogClient, (void **)&travelLogClient); 00170 if (FAILED(hResult)) 00171 return hResult; 00172 hResult = travelLogClient->GetWindowData(&windowData); 00173 if (FAILED(hResult)) 00174 return hResult; 00175 fPIDL = windowData.pidl; 00176 // TODO: Properly free the windowData 00177 hResult = punk->QueryInterface(IID_IPersistHistory, (void **)&persistHistory); 00178 if (FAILED(hResult)) 00179 return hResult; 00180 globalStorage = GlobalAlloc(GMEM_FIXED, 0); 00181 hResult = CreateStreamOnHGlobal(globalStorage, FALSE, &globalStream); 00182 if (FAILED(hResult)) 00183 return hResult; 00184 hResult = persistHistory->SaveHistory(globalStream); 00185 if (FAILED(hResult)) 00186 return hResult; 00187 hResult = GetHGlobalFromStream(globalStream, &fPersistState); 00188 if (FAILED(hResult)) 00189 return hResult; 00190 return S_OK; 00191 } 00192 00193 HRESULT STDMETHODCALLTYPE CTravelEntry::GetPidl(LPITEMIDLIST *ppidl) 00194 { 00195 if (ppidl == NULL) 00196 return E_POINTER; 00197 *ppidl = ILClone(fPIDL); 00198 if (*ppidl == NULL) 00199 return E_OUTOFMEMORY; 00200 return S_OK; 00201 } 00202 00203 CTravelLog::CTravelLog() 00204 { 00205 fListHead = NULL; 00206 fListTail = NULL; 00207 fCurrentEntry = NULL; 00208 fMaximumSize = 0; 00209 fCurrentSize = 0; 00210 fEntryCount = 0; 00211 } 00212 00213 CTravelLog::~CTravelLog() 00214 { 00215 CTravelEntry *anEntry; 00216 CTravelEntry *next; 00217 00218 anEntry = fListHead; 00219 while (anEntry != NULL) 00220 { 00221 next = anEntry->fNextEntry; 00222 anEntry->Release(); 00223 anEntry = next; 00224 } 00225 } 00226 00227 HRESULT CTravelLog::Initialize() 00228 { 00229 fMaximumSize = 1024 * 1024; // TODO: change to read this from registry 00230 // Software\Microsoft\Windows\CurrentVersion\Explorer\TravelLog 00231 // MaxSize 00232 return S_OK; 00233 } 00234 00235 HRESULT CTravelLog::FindRelativeEntry(int offset, CTravelEntry **foundEntry) 00236 { 00237 CTravelEntry *curEntry; 00238 00239 *foundEntry = NULL; 00240 curEntry = fCurrentEntry; 00241 if (offset < 0) 00242 { 00243 while (offset < 0 && curEntry != NULL) 00244 { 00245 curEntry = curEntry->fPreviousEntry; 00246 offset++; 00247 } 00248 } 00249 else 00250 { 00251 while (offset > 0 && curEntry != NULL) 00252 { 00253 curEntry = curEntry->fNextEntry; 00254 offset--; 00255 } 00256 } 00257 if (curEntry == NULL) 00258 return E_INVALIDARG; 00259 *foundEntry = curEntry; 00260 return S_OK; 00261 } 00262 00263 void CTravelLog::DeleteChain(CTravelEntry *startHere) 00264 { 00265 CTravelEntry *saveNext; 00266 long itemSize; 00267 00268 if (startHere->fPreviousEntry != NULL) 00269 { 00270 startHere->fPreviousEntry->fNextEntry = NULL; 00271 fListTail = startHere->fPreviousEntry; 00272 } 00273 else 00274 { 00275 fListHead = NULL; 00276 fListTail = NULL; 00277 } 00278 while (startHere != NULL) 00279 { 00280 saveNext = startHere->fNextEntry; 00281 itemSize = startHere->GetSize(); 00282 fCurrentSize -= itemSize; 00283 startHere->Release(); 00284 startHere = saveNext; 00285 fEntryCount--; 00286 } 00287 } 00288 00289 void CTravelLog::AppendEntry(CTravelEntry *afterEntry, CTravelEntry *newEntry) 00290 { 00291 if (afterEntry == NULL) 00292 { 00293 fListHead = newEntry; 00294 fListTail = newEntry; 00295 } 00296 else 00297 { 00298 newEntry->fNextEntry = afterEntry->fNextEntry; 00299 afterEntry->fNextEntry = newEntry; 00300 newEntry->fPreviousEntry = afterEntry; 00301 if (newEntry->fNextEntry == NULL) 00302 fListTail = newEntry; 00303 else 00304 newEntry->fNextEntry->fPreviousEntry = newEntry; 00305 } 00306 fEntryCount++; 00307 } 00308 00309 HRESULT STDMETHODCALLTYPE CTravelLog::AddEntry(IUnknown *punk, BOOL fIsLocalAnchor) 00310 { 00311 CComObject<CTravelEntry> *newEntry; 00312 long itemSize; 00313 00314 if (punk == NULL) 00315 return E_INVALIDARG; 00316 ATLTRY (newEntry = new CComObject<CTravelEntry>); 00317 if (newEntry == NULL) 00318 return E_OUTOFMEMORY; 00319 newEntry->AddRef(); 00320 if (fCurrentEntry != NULL && fCurrentEntry->fNextEntry != NULL) 00321 DeleteChain(fCurrentEntry->fNextEntry); 00322 AppendEntry(fCurrentEntry, newEntry); 00323 itemSize = newEntry->GetSize(); 00324 fCurrentSize += itemSize; 00325 fCurrentEntry = newEntry; 00326 return S_OK; 00327 } 00328 00329 HRESULT STDMETHODCALLTYPE CTravelLog::UpdateEntry(IUnknown *punk, BOOL fIsLocalAnchor) 00330 { 00331 if (punk == NULL) 00332 return E_INVALIDARG; 00333 if (fCurrentEntry == NULL) 00334 return E_UNEXPECTED; 00335 return fCurrentEntry->Update(punk, fIsLocalAnchor); 00336 } 00337 00338 HRESULT STDMETHODCALLTYPE CTravelLog::UpdateExternal(IUnknown *punk, IUnknown *punkHLBrowseContext) 00339 { 00340 return E_NOTIMPL; 00341 } 00342 00343 HRESULT STDMETHODCALLTYPE CTravelLog::Travel(IUnknown *punk, int iOffset) 00344 { 00345 CTravelEntry *destinationEntry; 00346 HRESULT hResult; 00347 00348 hResult = FindRelativeEntry(iOffset, &destinationEntry); 00349 if (FAILED(hResult)) 00350 return hResult; 00351 fCurrentEntry = destinationEntry; 00352 hResult = destinationEntry->Invoke(punk); 00353 if (FAILED(hResult)) 00354 return hResult; 00355 return S_OK; 00356 } 00357 00358 HRESULT STDMETHODCALLTYPE CTravelLog::GetTravelEntry(IUnknown *punk, int iOffset, ITravelEntry **ppte) 00359 { 00360 CTravelEntry *destinationEntry; 00361 HRESULT hResult; 00362 00363 hResult = FindRelativeEntry(iOffset, &destinationEntry); 00364 if (FAILED(hResult)) 00365 return hResult; 00366 return destinationEntry->QueryInterface(IID_ITravelEntry, (void **)ppte); 00367 } 00368 00369 HRESULT STDMETHODCALLTYPE CTravelLog::FindTravelEntry(IUnknown *punk, LPCITEMIDLIST pidl, ITravelEntry **ppte) 00370 { 00371 if (ppte == NULL) 00372 return E_POINTER; 00373 if (punk == NULL || pidl == NULL) 00374 return E_INVALIDARG; 00375 return E_NOTIMPL; 00376 } 00377 00378 HRESULT STDMETHODCALLTYPE CTravelLog::GetToolTipText(IUnknown *punk, int iOffset, int idsTemplate, LPWSTR pwzText, DWORD cchText) 00379 { 00380 CTravelEntry *destinationEntry; 00381 wchar_t tempString[MAX_PATH]; 00382 wchar_t templateString[200]; 00383 HRESULT hResult; 00384 00385 if (pwzText == NULL) 00386 return E_POINTER; 00387 if (punk == NULL || cchText == 0) 00388 return E_INVALIDARG; 00389 hResult = FindRelativeEntry(iOffset, &destinationEntry); 00390 if (FAILED(hResult)) 00391 return hResult; 00392 hResult = destinationEntry->GetToolTipText(punk, tempString); 00393 if (FAILED(hResult)) 00394 return hResult; 00395 if (iOffset < 0) 00396 { 00397 wcscpy(templateString, L"Back to %s"); 00398 } 00399 else 00400 { 00401 wcscpy(templateString, L"Forward to %s"); 00402 } 00403 _snwprintf(pwzText, cchText, templateString, tempString); 00404 return S_OK; 00405 } 00406 00407 static void FixAmpersands(wchar_t *buffer) 00408 { 00409 wchar_t tempBuffer[MAX_PATH * 2]; 00410 wchar_t ch; 00411 wchar_t *srcPtr; 00412 wchar_t *dstPtr; 00413 00414 srcPtr = buffer; 00415 dstPtr = tempBuffer; 00416 while (*srcPtr != 0) 00417 { 00418 ch = *srcPtr++; 00419 *dstPtr++ = ch; 00420 if (ch == '&') 00421 *dstPtr++ = '&'; 00422 } 00423 *dstPtr = 0; 00424 wcscpy(buffer, tempBuffer); 00425 } 00426 00427 HRESULT STDMETHODCALLTYPE CTravelLog::InsertMenuEntries(IUnknown *punk, HMENU hmenu, int nPos, int idFirst, int idLast, DWORD dwFlags) 00428 { 00429 CTravelEntry *currentItem; 00430 MENUITEMINFO menuItemInfo; 00431 wchar_t itemTextBuffer[MAX_PATH * 2]; 00432 HRESULT hResult; 00433 00434 // TLMENUF_BACK - include back entries 00435 // TLMENUF_INCLUDECURRENT - include current entry, if TLMENUF_CHECKCURRENT then check the entry 00436 // TLMENUF_FORE - include next entries 00437 // if fore+back, list from oldest to newest 00438 // if back, list from newest to oldest 00439 // if fore, list from newest to oldest 00440 00441 // don't forget to patch ampersands before adding to menu 00442 if (punk == NULL) 00443 return E_INVALIDARG; 00444 if (idLast <= idFirst) 00445 return E_INVALIDARG; 00446 menuItemInfo.cbSize = sizeof(menuItemInfo); 00447 menuItemInfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_STRING; 00448 menuItemInfo.fType = MFT_STRING; 00449 menuItemInfo.wID = idFirst; 00450 menuItemInfo.fState = MFS_ENABLED; 00451 menuItemInfo.dwTypeData = itemTextBuffer; 00452 if ((dwFlags & TLMENUF_BACK) != 0) 00453 { 00454 if ((dwFlags & TLMENUF_FORE) != 0) 00455 { 00456 currentItem = fCurrentEntry; 00457 if (currentItem != NULL) 00458 { 00459 while (currentItem->fPreviousEntry != NULL) 00460 currentItem = currentItem->fPreviousEntry; 00461 } 00462 while (currentItem != fCurrentEntry) 00463 { 00464 hResult = currentItem->GetToolTipText(punk, itemTextBuffer); 00465 if (SUCCEEDED(hResult)) 00466 { 00467 FixAmpersands(itemTextBuffer); 00468 if (InsertMenuItem(hmenu, nPos, TRUE, &menuItemInfo)) 00469 { 00470 nPos++; 00471 menuItemInfo.wID++; 00472 } 00473 } 00474 currentItem = currentItem->fNextEntry; 00475 } 00476 } 00477 else 00478 { 00479 currentItem = fCurrentEntry; 00480 if (currentItem != NULL) 00481 currentItem = currentItem->fPreviousEntry; 00482 while (currentItem != NULL) 00483 { 00484 hResult = currentItem->GetToolTipText(punk, itemTextBuffer); 00485 if (SUCCEEDED(hResult)) 00486 { 00487 FixAmpersands(itemTextBuffer); 00488 if (InsertMenuItem(hmenu, nPos, TRUE, &menuItemInfo)) 00489 { 00490 nPos++; 00491 menuItemInfo.wID++; 00492 } 00493 } 00494 currentItem = currentItem->fPreviousEntry; 00495 } 00496 } 00497 } 00498 if ((dwFlags & TLMENUF_INCLUDECURRENT) != 0) 00499 { 00500 if (fCurrentEntry != NULL) 00501 { 00502 hResult = fCurrentEntry->GetToolTipText(punk, itemTextBuffer); 00503 if (SUCCEEDED(hResult)) 00504 { 00505 FixAmpersands(itemTextBuffer); 00506 if ((dwFlags & TLMENUF_CHECKCURRENT) != 0) 00507 menuItemInfo.fState |= MFS_CHECKED; 00508 if (InsertMenuItem(hmenu, nPos, TRUE, &menuItemInfo)) 00509 { 00510 nPos++; 00511 menuItemInfo.wID++; 00512 } 00513 menuItemInfo.fState &= ~MFS_CHECKED; 00514 } 00515 } 00516 } 00517 if ((dwFlags & TLMENUF_FORE) != 0) 00518 { 00519 currentItem = fCurrentEntry; 00520 if (currentItem != NULL) 00521 currentItem = currentItem->fNextEntry; 00522 while (currentItem != NULL) 00523 { 00524 hResult = currentItem->GetToolTipText(punk, itemTextBuffer); 00525 if (SUCCEEDED(hResult)) 00526 { 00527 FixAmpersands(itemTextBuffer); 00528 if (InsertMenuItem(hmenu, nPos, TRUE, &menuItemInfo)) 00529 { 00530 nPos++; 00531 menuItemInfo.wID++; 00532 } 00533 } 00534 currentItem = currentItem->fNextEntry; 00535 } 00536 } 00537 return S_OK; 00538 } 00539 00540 HRESULT STDMETHODCALLTYPE CTravelLog::Clone(ITravelLog **pptl) 00541 { 00542 if (pptl == NULL) 00543 return E_POINTER; 00544 *pptl = NULL; 00545 // duplicate the log 00546 return E_NOTIMPL; 00547 } 00548 00549 DWORD STDMETHODCALLTYPE CTravelLog::CountEntries(IUnknown *punk) 00550 { 00551 if (punk == NULL) 00552 return E_INVALIDARG; 00553 return fEntryCount; 00554 } 00555 00556 HRESULT STDMETHODCALLTYPE CTravelLog::Revert() 00557 { 00558 // remove the current entry? 00559 return E_NOTIMPL; 00560 } 00561 00562 HRESULT CreateTravelLog(REFIID riid, void **ppv) 00563 { 00564 CComObject<CTravelLog> *theTravelLog; 00565 HRESULT hResult; 00566 00567 if (ppv == NULL) 00568 return E_POINTER; 00569 *ppv = NULL; 00570 ATLTRY (theTravelLog = new CComObject<CTravelLog>); 00571 if (theTravelLog == NULL) 00572 return E_OUTOFMEMORY; 00573 hResult = theTravelLog->QueryInterface (riid, (void **)ppv); 00574 if (FAILED (hResult)) 00575 { 00576 delete theTravelLog; 00577 return hResult; 00578 } 00579 hResult = theTravelLog->Initialize(); 00580 if (FAILED(hResult)) 00581 return hResult; 00582 return S_OK; 00583 } Generated on Sun May 27 2012 04:22:55 for ReactOS by
1.7.6.1
|