ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

travellog.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.