// HistoryTree.cpp // // (c)1998-2025 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Resource.h" #include "HistoryTree.h" #include #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CHistoryTree CHistoryTree::CHistoryTree() { m_pMalloc = NULL; SHGetMalloc(&m_pMalloc); m_bIE4 = FALSE; } CHistoryTree::~CHistoryTree() { // m_wndHisTree.DeleteAllItems(); m_wndHisTree.m_astrHist.RemoveAll(); m_pMalloc->Release(); } void CHistoryTree::Destroy() { } ///////////////////////////////////////////////////////////////////////////// // CHistoryTree message handlers LPCTSTR CHistoryTree::GetTitle() { strTitle.LoadString(IDS_TITLE_HIS); return strTitle; } BOOL CHistoryTree::Initialize() { // TODO: Add your command handler code here m_wndHisTree.DeleteAllItems(); m_wndHisTree.m_astrHist.RemoveAll(); LPITEMIDLIST pidlHistory = NULL; HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_HISTORY, &pidlHistory); if (NOERROR != hr) { // AfxMessageBox("Can't get history folder."); m_bIE4 = TRUE; // for ie4 or win95 CWaitCursor wc; IUrlHistoryStg2* pUrlHistoryStg2 = NULL; hr = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC, IID_IUrlHistoryStg2, (void**)&pUrlHistoryStg2); if (SUCCEEDED(hr)) { IEnumSTATURL* pEnum; hr = pUrlHistoryStg2->EnumUrls(&pEnum); ULONG size; STATURL staturl; int ind = 1; hr = pEnum->Next(1, &staturl, &size); if (SUCCEEDED(hr)) { m_wndHisTree.DeleteAllItems(); m_wndHisTree.m_astrHist.RemoveAll(); } CTime ttime = CTime::GetCurrentTime(); today = ttime.GetDayOfWeek(); int t; if (today == 1) t = 8; else t = today; CTimeSpan tt(t - 2, 0, 0, 0); ttime = ttime - tt; CTime t2(ttime.GetYear(), ttime.GetMonth(), ttime.GetDay(), 0, 0, 0); montime = t2; while (size > 0) { if (insertUrl(&staturl, ind)) { m_wndHisTree.m_astrHist.Add(CString(staturl.pwcsUrl)); ind++; } pEnum->Next(1, &staturl, &size); } // open today pEnum->Release(); pUrlHistoryStg2->Release(); } return FALSE; } IShellFolder* psfDesktop; IShellFolder* psfHistory; hr = SHGetDesktopFolder(&psfDesktop); if (NOERROR != hr) { AfxMessageBox(_T("Can't get desktop.")); return FALSE; } hr = psfDesktop->BindToObject(pidlHistory, NULL, IID_IShellFolder, (LPVOID*)&psfHistory); psfDesktop->Release(); if (NOERROR != hr) { AfxMessageBox(_T("Can't bind history folder.")); return FALSE; } AddHistory(psfHistory, NULL); m_pMalloc->Free(pidlHistory); psfHistory->Release(); return TRUE; } BOOL CHistoryTree::Create(CWnd* pParent) { if (!m_wndHisTree.Create(WS_BORDER | WS_CHILD | WS_VISIBLE | TVS_SHOWSELALWAYS | TVS_LINESATROOT | TVS_FULLROWSELECT | TVS_TRACKSELECT, CRect(0, 0, 0, 0), pParent, 100)) { TRACE0("Failed to create instant bar child\n"); return 0; // fail to create } CWnd* pTT = m_wndHisTree.FromHandle((HWND)m_wndHisTree.SendMessage(TVM_GETTOOLTIPS)); if (pTT != NULL) pTT->SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); CImageList img; img.Create(16, 16, ILC_COLORDDB | ILC_MASK, 4, 1); HBITMAP hbmp = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP_TREE)); ImageList_AddMasked(img.GetSafeHandle(), hbmp, RGB(255, 0, 255)); m_wndHisTree.SetImageList(&img, TVSIL_NORMAL); img.Detach(); m_wndHisTree.m_pHisTree = this; return TRUE; } CWnd* CHistoryTree::GetWindow() { return (CWnd*)&m_wndHisTree; } // for ie4 and win95 BOOL CHistoryTree::insertUrl(LPSTATURL pSUrl, int ind) { // get host CString url(pSUrl->pwcsUrl); CString host; CString l = url.Left(5); int i; if (l == _T("https")) { host = url.Right(url.GetLength() - 8); i = host.Find('/'); if (i > 0) host = host.Left(i); } if (l == _T("http:")) { host = url.Right(url.GetLength() - 7); i = host.Find('/'); if (i > 0) host = host.Left(i); } else if (l == _T("ftp:/")) { host = url.Right(url.GetLength() - 6); i = host.Find('/'); if (i > 0) host = host.Left(i); } else if (l == _T("file:")) { host.LoadString(IDS_MY_COMPUTER); } else return FALSE; // get date CTime ttime(pSUrl->ftLastVisited); CTime ttime2(pSUrl->ftLastUpdated); if (ttime < ttime2) ttime = ttime2; CTime filetime(ttime.GetYear(), ttime.GetMonth(), ttime.GetDay(), 0, 0, 0); int d; int week = 0, data; CString root; CTimeSpan ts = montime - filetime; if (filetime < montime) { week = int(ts.GetDays() + 6) / 7; } if (week > 1) { CString tw; tw.Format(_T("%i"), week); root.LoadString(IDS_WEEKS_AGO); root = tw + root; data = -week - 7; } else if (week == 1) { root.LoadString(IDS_LAST_WEEK); data = -8; } else { d = filetime.GetDayOfWeek(); if (d == today) root.LoadString(IDS_TODAY); else root.LoadString(IDS_SUNDAY + d - 1); data = -9 + d; if (d == 1) data = -1; } HTREEITEM hitem; hitem = FindAndInsert(NULL, root, 0, 0, data); hitem = FindAndInsert(hitem, host, 1, 3); CString temp; temp = pSUrl->pwcsTitle; if (temp.IsEmpty()) { temp = pSUrl->pwcsUrl; i = temp.ReverseFind('/'); temp = temp.Right(temp.GetLength() - i - 1); } HTREEITEM hnode = m_wndHisTree.InsertItem(temp, 2, 2, hitem); m_wndHisTree.SetItemData(hnode, ind); return TRUE; } HTREEITEM CHistoryTree::FindAndInsert(HTREEITEM hRoot, LPCTSTR text, int nImg, int nOImg, int data) { HTREEITEM hit, hnode = NULL, pre = TVI_FIRST; BOOL found = FALSE; hit = m_wndHisTree.GetChildItem(hRoot); if (data >= 0) while (hit != NULL && !found) { if (m_wndHisTree.GetItemText(hit).CompareNoCase(text) == 1) { hnode = m_wndHisTree.InsertItem(text, nImg, nOImg, hRoot, TVI_SORT); found = TRUE; } else if (m_wndHisTree.GetItemText(hit).CompareNoCase(text) == 0) { found = TRUE; hnode = hit; } else hit = m_wndHisTree.GetNextSiblingItem(hit); } else // compare with data while (hit != NULL && !found) { if ((signed)m_wndHisTree.GetItemData(hit) > data) { hnode = m_wndHisTree.InsertItem(text, nImg, nOImg, hRoot, pre); found = TRUE; } else if ((signed)m_wndHisTree.GetItemData(hit) == data) { found = TRUE; hnode = hit; } else { pre = hit; hit = m_wndHisTree.GetNextSiblingItem(hit); } } if (!found) hnode = m_wndHisTree.InsertItem(text, nImg, nOImg, hRoot, TVI_LAST); m_wndHisTree.SetItemData(hnode, data); return hnode; } // end BOOL CHistoryTree::Update(int nLevel) { if (m_bIE4) { HTREEITEM hit, pre = NULL; BOOL found = FALSE; int d; CString text; text.LoadString(IDS_TODAY); // now only update today. if (nLevel == 0) { // get today item hit = m_wndHisTree.GetChildItem(NULL); while (hit != NULL && !found) { if (m_wndHisTree.GetItemText(hit).CompareNoCase(text) == 0) { found = TRUE; } else { pre = hit; hit = m_wndHisTree.GetNextSiblingItem(hit); } } int day; if (found) { d = (int)m_wndHisTree.GetItemData(hit); day = d + 9; if (d == -1) day = 1; // delete today m_wndHisTree.DeleteItem(hit); m_wndHisTree.Expand(pre, TVE_COLLAPSE); } else day = today; // insert history after that day CWaitCursor wc; IUrlHistoryStg2* pUrlHistoryStg2 = NULL; HRESULT hr = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC, IID_IUrlHistoryStg2, (void**)&pUrlHistoryStg2); if (SUCCEEDED(hr)) { IEnumSTATURL* pEnum; hr = pUrlHistoryStg2->EnumUrls(&pEnum); ULONG size; STATURL staturl; int ind = (int)m_wndHisTree.m_astrHist.GetUpperBound() + 2; hr = pEnum->Next(1, &staturl, &size); if (!SUCCEEDED(hr)) { return FALSE; } CTime ttime = CTime::GetCurrentTime(); today = ttime.GetDayOfWeek(); CTime lastday; if (today == day) { CTime t1(ttime.GetYear(), ttime.GetMonth(), ttime.GetDay(), 0, 0, 0); lastday = t1; } else { CTimeSpan tsp(1, 0, 0, 0); ttime = ttime - tsp; CTime t1(ttime.GetYear(), ttime.GetMonth(), ttime.GetDay(), 0, 0, 0); lastday = t1; ttime = ttime + tsp; } int t; if (today == 1) t = 8; else t = today; CTimeSpan tt(t - 2, 0, 0, 0); ttime = ttime - tt; CTime t2(ttime.GetYear(), ttime.GetMonth(), ttime.GetDay(), 0, 0, 0); montime = t2; while (size > 0) { CTime t3(staturl.ftLastVisited); if (t3 >= lastday) { if (insertUrl(&staturl, ind)) { m_wndHisTree.m_astrHist.Add(CString(staturl.pwcsUrl)); ind++; } } pEnum->Next(1, &staturl, &size); } // open today pEnum->Release(); pUrlHistoryStg2->Release(); } return TRUE; } return TRUE; } // following is for ie5 and win98 // remove the children of Today HTREEITEM hit; BOOL found = FALSE; CString text; text.LoadString(IDS_TODAY); // get today item hit = m_wndHisTree.GetChildItem(NULL); while (hit != NULL && !found) { if (m_wndHisTree.GetItemText(hit).CompareNoCase(text) == 0) found = TRUE; else hit = m_wndHisTree.GetNextSiblingItem(hit); } if (found) { // delete today m_wndHisTree.DeleteItem(hit); // m_wndHisTree.Expand(pre, TVE_COLLAPSE); } LPITEMIDLIST pidlHistory = NULL; HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_HISTORY, &pidlHistory); if (NOERROR != hr) return FALSE; IShellFolder* psfDesktop; IShellFolder* psfHistory; hr = SHGetDesktopFolder(&psfDesktop); if (NOERROR != hr) return FALSE; hr = psfDesktop->BindToObject(pidlHistory, NULL, IID_IShellFolder, (LPVOID*)&psfHistory); psfDesktop->Release(); if (NOERROR != hr) return FALSE; AddHistory(psfHistory, NULL, 0, 0, TRUE); m_pMalloc->Free(pidlHistory); psfHistory->Release(); return TRUE; } void CHistoryTree::AddHistory(IShellFolder* pFolder, HTREEITEM root, int nImg, int nOImg, BOOL bNeedCmp) { USES_CONVERSION; if (pFolder == NULL) return; // enum history IEnumIDList* pItems = NULL; LPITEMIDLIST pidlNext = NULL; CString lpszName; // TCHAR lpszFileName[MAX_PATH]; LPTSTR lpszURL = NULL; DWORD dwEntrySize = 0; // Enumerate all object in the given folder HRESULT hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &pItems); while (NOERROR == hr) { hr = pItems->Next(1, &pidlNext, NULL); if (NOERROR == hr) { GetName(pFolder, pidlNext, SHGDN_NORMAL, lpszName); // add folder BOOL found = FALSE; if (bNeedCmp) { HTREEITEM hit; // get today item hit = m_wndHisTree.GetChildItem(root); while (hit != NULL && !found) { if (m_wndHisTree.GetItemText(hit).CompareNoCase(lpszName) == 0) found = TRUE; else hit = m_wndHisTree.GetNextSiblingItem(hit); } } if (!found) { HTREEITEM hItem; if (nImg == 0) hItem = m_wndHisTree.InsertItem(lpszName, nImg, nOImg, root, TVI_LAST); else hItem = m_wndHisTree.InsertItem(lpszName, nImg, nOImg, root, TVI_SORT); if (nImg == 2) ResolveHistory(pFolder, pidlNext, &lpszURL); if (lpszURL) { // Add the URL to the array and free lpszURL // since it was created with IMalloc::Alloc m_wndHisTree.m_astrHist.Add(lpszURL); m_wndHisTree.SetItemData(hItem, m_wndHisTree.m_astrHist.GetSize()); // is the url cached? dwEntrySize = 0; if (_tcsncmp(lpszURL, _T("file:"), 5) != 0) { #if _MSC_VER < 1300 if (!GetUrlCacheEntryInfoExA(T2A(lpszURL), NULL, &dwEntrySize, NULL, NULL, NULL, 0)) #else if (!GetUrlCacheEntryInfoEx(lpszURL, NULL, &dwEntrySize, NULL, NULL, NULL, 0)) #endif { if (GetLastError() == ERROR_FILE_NOT_FOUND) { m_wndHisTree.SetItemState(hItem, TVIS_CUT, TVIS_CUT); } } } m_pMalloc->Free(lpszURL); lpszURL = NULL; } } if (pidlNext) m_pMalloc->Free(pidlNext); } } if (pItems) pItems->Release(); } BOOL CHistoryTree::ResolveHistory(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPTSTR* lpszURL) { IShellLink* pShellLink; *lpszURL = NULL; // Assume failure // Get a pointer to the IShellLink interface from the given folder HRESULT hr = pFolder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink); if (SUCCEEDED(hr)) { WIN32_FIND_DATA wfd; hr = pShellLink->Resolve(AfxGetApp()->m_pMainWnd->m_hWnd, SLR_NO_UI); if (NOERROR == hr) { // Get the path to the link target. *lpszURL = (LPTSTR)m_pMalloc->Alloc(MAX_PATH); // Must remember to Free later hr = pShellLink->GetPath(*lpszURL, MAX_PATH - 1, (WIN32_FIND_DATA*)&wfd, SLGP_UNCPRIORITY); } pShellLink->Release(); } if (SUCCEEDED(hr)) return TRUE; else return FALSE; }