--- /dev/null
+//////////////////////////////////////////////////////////\r
+// MyTreeView.cpp\r
+// Definitions for the CMyTreeView and TreeItemData classes\r
+\r
+#include "stdafx.h"\r
+#include "ExplorerApp.h"\r
+#include "Mainfrm.h"\r
+#include "MyTreeView.h"\r
+#include "MyListView.h"\r
+#include "resource.h"\r
+\r
+////////////////////////////////\r
+//CMyTreeView function definitions\r
+CMyTreeView::CMyTreeView()\r
+{\r
+ SetImageLists();\r
+}\r
+\r
+CMyTreeView::~CMyTreeView()\r
+{\r
+ DeleteItems();\r
+}\r
+\r
+int CALLBACK CMyTreeView::CompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\r
+{\r
+ UNREFERENCED_PARAMETER(lParamSort);\r
+ TreeItemData* pItem1 = (TreeItemData*)lParam1;\r
+ TreeItemData* pItem2 = (TreeItemData*)lParam2;\r
+ HRESULT hr;\r
+\r
+ hr = pItem1->GetParentFolder().CompareIDs(0, pItem1->GetRelCpidl(), pItem2->GetRelCpidl());\r
+ if(FAILED(hr))\r
+ return 0;\r
+\r
+ return (short)SCODE_CODE(GetScode(hr));\r
+}\r
+\r
+void CMyTreeView::DeleteItems()\r
+{\r
+ m_pItems.clear();\r
+}\r
+\r
+void CMyTreeView::DoContextMenu(CPoint& ptScreen)\r
+{\r
+ TVHITTESTINFO tvhti;\r
+ tvhti.pt = ptScreen;\r
+ ScreenToClient(tvhti.pt);\r
+ tvhti.flags = LVHT_NOWHERE;\r
+ HitTest(tvhti);\r
+\r
+ if(TVHT_ONITEM & tvhti.flags)\r
+ DoItemMenu(tvhti.hItem , ptScreen);\r
+}\r
+\r
+void CMyTreeView::DoItemMenu(HTREEITEM hItem, CPoint& ptScreen)\r
+{\r
+ TVITEM tvItem = {0};\r
+ tvItem.mask = TVIF_PARAM;\r
+ tvItem.hItem = hItem;\r
+\r
+ if(GetItem(tvItem))\r
+ {\r
+ HRESULT hr;\r
+ TreeItemData* pInfo = (TreeItemData*)tvItem.lParam;\r
+ CContextMenu cm;\r
+ CShellFolder sf;\r
+\r
+ if (pInfo->GetParentFolder().GetIShellFolder() != NULL)\r
+ sf = pInfo->GetParentFolder();\r
+ else\r
+ sf.SHGetDesktopFolder();\r
+\r
+ if(sf.GetIShellFolder())\r
+ {\r
+ hr = sf.GetUIObjectOf(m_hWnd, 1, &(pInfo->GetRelCpidl()), IID_IContextMenu, 0, cm);\r
+\r
+ if(SUCCEEDED(hr))\r
+ {\r
+ CMenu Popup;\r
+ Popup.CreatePopupMenu();\r
+ if(Popup.GetHandle())\r
+ {\r
+ hr = cm.QueryContextMenu(Popup, 0, 1, 0x7fff, CMF_NORMAL | CMF_EXPLORE);\r
+\r
+ if(SUCCEEDED(hr))\r
+ {\r
+ cm.QueryInterface(IID_IContextMenu2, m_ccm2);\r
+\r
+ UINT idCmd = Popup.TrackPopupMenu(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON ,\r
+ ptScreen.x, ptScreen.y, this, NULL);\r
+\r
+ //A Treeview control sometimes requires this to end the\r
+ // TrackPopupMenu properly\r
+ GetParent()->PostMessage(WM_CANCELMODE, 0, 0);\r
+\r
+ if(idCmd)\r
+ {\r
+ CMINVOKECOMMANDINFO cmi = {0};\r
+ cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);\r
+ cmi.hwnd = m_hWnd;\r
+ cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - 1);\r
+ cmi.nShow = SW_SHOWNORMAL;\r
+ cm.InvokeCommand(cmi);\r
+ }\r
+\r
+ m_ccm2.Release();\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+LRESULT CMyTreeView::OnNotifyReflect(WPARAM, LPARAM lParam)\r
+{\r
+ LPNMHDR lpnmh = (LPNMHDR) lParam;\r
+\r
+ switch(lpnmh->code)\r
+ {\r
+ case NM_RCLICK:\r
+ {\r
+ CPoint ptScreen;\r
+ ::GetCursorPos(&ptScreen);\r
+ DoContextMenu(ptScreen);\r
+ }\r
+ break;\r
+ case TVN_GETDISPINFO:\r
+ {\r
+ LPNMTVDISPINFO lpdi = (LPNMTVDISPINFO)lParam;\r
+ TreeItemData* pItem = (TreeItemData*)lpdi->item.lParam;\r
+\r
+ //do we need to supply the text?\r
+ if(lpdi->item.mask & TVIF_TEXT)\r
+ {\r
+ SHFILEINFO sfi = {0};\r
+\r
+ //get the display name of the item\r
+ if(pItem->GetFullCpidl().SHGetFileInfo(0, sfi, SHGFI_PIDL | SHGFI_DISPLAYNAME))\r
+ ::lstrcpyn(lpdi->item.pszText, sfi.szDisplayName, lpdi->item.cchTextMax -1);\r
+ }\r
+\r
+ //do we need to supply the unselected image?\r
+ if(lpdi->item.mask & TVIF_IMAGE)\r
+ {\r
+ SHFILEINFO sfi = {0};\r
+\r
+ //get the unselected image for this item\r
+ if(pItem->GetFullCpidl().SHGetFileInfo(0, sfi, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_LINKOVERLAY))\r
+ lpdi->item.iImage = sfi.iIcon;\r
+ }\r
+\r
+ //do we need to supply the selected image?\r
+ if(lpdi->item.mask & TVIF_SELECTEDIMAGE)\r
+ {\r
+ SHFILEINFO sfi = {0};\r
+\r
+ //get the selected image for this item\r
+ if(pItem->GetFullCpidl().SHGetFileInfo(0, sfi, SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON))\r
+ lpdi->item.iSelectedImage = sfi.iIcon;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case TVN_ITEMEXPANDING:\r
+ {\r
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;\r
+\r
+ switch(pnmtv->action)\r
+ {\r
+ case TVE_EXPAND:\r
+ {\r
+ UINT ExpandedOnce = pnmtv->itemNew.state & TVIS_EXPANDEDONCE;\r
+ if (!ExpandedOnce)\r
+ GetChildItems(pnmtv->itemNew.hItem);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case TVN_SELCHANGED:\r
+ {\r
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;\r
+ TreeItemData* pItem = (TreeItemData*)pnmtv->itemNew.lParam;\r
+\r
+ CMyListView* LeftView = GetExplorerApp().GetMainFrame().GetListView();\r
+ LeftView->DisplayFolder(pItem->GetParentFolder(), pItem->GetFullCpidl(), pItem->GetRelCpidl());\r
+ }\r
+ break;\r
+ } // switch(lpnmh->code)\r
+\r
+ return 0;\r
+}\r
+\r
+void CMyTreeView::EnumObjects(HTREEITEM hParentItem, CShellFolder& cParentFolder, Cpidl& cpidlParent)\r
+{\r
+ CEnumIDList cEnum;\r
+ if(SUCCEEDED(cParentFolder.EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN, cEnum)))\r
+ {\r
+ ULONG ulFetched = 1;\r
+ Cpidl cpidlRel;\r
+\r
+ //enumerate the item's PIDLs\r
+ while(S_OK == (cEnum.Next(1, cpidlRel, ulFetched)) && ulFetched)\r
+ {\r
+ TVITEM tvItem = {0};\r
+ TVINSERTSTRUCT tvInsert = {0};\r
+ ULONG ulAttribs;\r
+\r
+ //fill in the TV_ITEM structure for this item\r
+ tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;\r
+\r
+ //Store a pointer to the TreeItemData in the lParam and m_pItems\r
+ TreeItemData* pItem = new TreeItemData(cpidlParent, cpidlRel, cParentFolder);\r
+ tvItem.lParam = (LPARAM)pItem;\r
+ m_pItems.push_back(pItem);\r
+\r
+ //text and images are done on a callback basis\r
+ tvItem.pszText = LPSTR_TEXTCALLBACK;\r
+ tvItem.iImage = tvItem.iSelectedImage = I_IMAGECALLBACK;\r
+\r
+ //determine if the item has children or shared\r
+ ulAttribs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_SHARE;\r
+ cParentFolder.GetAttributesOf(1, cpidlRel, ulAttribs);\r
+ tvItem.cChildren = (ulAttribs & SFGAO_HASSUBFOLDER);\r
+\r
+ //determine if the item is shared\r
+ if(ulAttribs & SFGAO_SHARE)\r
+ {\r
+ tvItem.mask |= TVIF_STATE;\r
+ tvItem.stateMask |= TVIS_OVERLAYMASK;\r
+ tvItem.state |= INDEXTOOVERLAYMASK(1); //1 is the index for the shared overlay image\r
+ }\r
+\r
+ //fill in the TV_INSERTSTRUCT structure for this item\r
+ tvInsert.item = tvItem;\r
+ tvInsert.hInsertAfter = TVI_LAST;\r
+ tvInsert.hParent = hParentItem;\r
+\r
+ InsertItem(tvInsert);\r
+ ulFetched = 0;\r
+ }\r
+ }\r
+}\r
+\r
+BOOL CMyTreeView::GetChildItems(HTREEITEM hParentItem)\r
+{\r
+ TVITEM tvItem = {0};\r
+ tvItem.mask = TVIF_PARAM;\r
+ tvItem.hItem = hParentItem;\r
+ if (!GetItem(tvItem))\r
+ return FALSE;\r
+\r
+ //change the cursor\r
+ HCURSOR hCursor = ::SetCursor(LoadCursor(NULL, IDC_WAIT));\r
+\r
+ //turn redawing off in the TreeView. This will speed things up as we add items\r
+ SendMessage(WM_SETREDRAW, FALSE, 0);\r
+\r
+ TreeItemData* pItem = (TreeItemData*)tvItem.lParam;\r
+ CShellFolder cParentFolder;\r
+ HRESULT hr;\r
+\r
+ //if the parent folder is NULL, then we are at the root of the namespace, so the parent of this item is the desktop folder\r
+ if(!pItem->GetParentFolder().GetIShellFolder())\r
+ hr = cParentFolder.SHGetDesktopFolder();\r
+\r
+ //otherwise we need to get the IShellFolder for this item\r
+ else\r
+ hr = pItem->GetParentFolder().BindToObject(pItem->GetRelCpidl(), NULL, IID_IShellFolder, cParentFolder);\r
+\r
+ if(FAILED(hr))\r
+ return FALSE;\r
+\r
+ EnumObjects(hParentItem, cParentFolder, pItem->GetFullCpidl());\r
+\r
+ //sort the new items\r
+ TV_SORTCB tvSort;\r
+ tvSort.hParent = hParentItem;\r
+ tvSort.lpfnCompare = CompareProc;\r
+ tvSort.lParam = 0;\r
+ SortChildrenCB(tvSort, 0);\r
+\r
+ //turn redawing back on in the TreeView\r
+ SendMessage(WM_SETREDRAW, TRUE, 0);\r
+\r
+ UpdateWindow();\r
+ ::SetCursor(hCursor);\r
+\r
+ return TRUE;\r
+}\r
+\r
+HIMAGELIST CMyTreeView::GetImageList(BOOL bLarge)\r
+{\r
+ if (bLarge)\r
+ return m_hLargeImageList;\r
+ else\r
+ return m_hSmallImageList;\r
+}\r
+\r
+BOOL CMyTreeView::GetRootItems()\r
+{\r
+ DeleteAllItems();\r
+\r
+ Cpidl cpidlDesk;\r
+ cpidlDesk.SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP);\r
+ if (cpidlDesk.GetPidl())\r
+ {\r
+ TV_ITEM tvItem = {0};\r
+ TV_INSERTSTRUCT tvInsert = {0};\r
+ HTREEITEM hParentItem;\r
+\r
+ //fill in the TVITEM structure for this item\r
+ tvItem.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN;\r
+\r
+ //Store a pointer to the TreeItemData in the lParam and m_pItems\r
+ TreeItemData* pItem = new TreeItemData(cpidlDesk);\r
+ tvItem.lParam = (LPARAM)pItem;\r
+ m_pItems.push_back(pItem);\r
+\r
+ //text and images are done on a callback basis\r
+ tvItem.pszText = LPSTR_TEXTCALLBACK;\r
+ tvItem.iImage = tvItem.iSelectedImage = I_IMAGECALLBACK;\r
+\r
+ //assume the desktop has children\r
+ tvItem.cChildren = TRUE;\r
+\r
+ //fill in the TV_INSERTSTRUCT structure for this item\r
+ tvInsert.item = tvItem;\r
+ tvInsert.hInsertAfter = TVI_LAST;\r
+ tvInsert.hParent = TVI_ROOT;\r
+\r
+ SetFocus();\r
+\r
+ //add the item\r
+ hParentItem = InsertItem(tvInsert);\r
+\r
+ //go ahead and expand this item\r
+ Expand(hParentItem, TVE_EXPAND);\r
+\r
+ //Select the next item\r
+ HTREEITEM hNext = GetNextItem(hParentItem, TVGN_CHILD);\r
+\r
+ //Expand this item\r
+ Expand(hNext, TVE_EXPAND);\r
+\r
+ //Select this item\r
+ SelectItem(hNext);\r
+\r
+ //Scroll this item into view\r
+ SelectSetFirstVisible(hNext);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+void CMyTreeView::OnInitialUpdate()\r
+{\r
+ //Set the image list\r
+ SendMessage(TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM) GetImageList(FALSE));\r
+}\r
+\r
+void CMyTreeView::PreCreate(CREATESTRUCT &cs)\r
+{\r
+ cs.dwExStyle = WS_EX_CLIENTEDGE;\r
+ cs.style = WS_TABSTOP | WS_CHILD | WS_VISIBLE | TVS_HASLINES |\r
+ TVS_HASBUTTONS | TVS_NOTOOLTIPS | TVS_SHOWSELALWAYS ;\r
+}\r
+\r
+BOOL CMyTreeView::SelectFromListView(Cpidl& cpidlFull)\r
+{\r
+ HTREEITEM hItem = GetSelection();\r
+\r
+ //Set parent item's has Children flag\r
+ TVITEM tvItem = {0};\r
+ tvItem.mask = TVIF_CHILDREN;\r
+ tvItem.cChildren = 1;\r
+ tvItem.hItem = hItem;\r
+ SetItem(tvItem);\r
+\r
+ //Expand the tree item\r
+ Expand(hItem, TVE_EXPAND);\r
+\r
+ //First Child\r
+ HTREEITEM hChild = GetChild(hItem);\r
+\r
+ while (hChild != NULL)\r
+ {\r
+ //Get the TVITEM structure for this item\r
+ TVITEM tvItem = {0};\r
+ tvItem.mask = TVIF_PARAM;\r
+ tvItem.hItem = hChild;\r
+ if(!GetItem(tvItem))\r
+ return FALSE;\r
+\r
+ //Get the TreeItemData pointer from the item's lParam\r
+ TreeItemData* pTD = (TreeItemData*)tvItem.lParam;\r
+\r
+ //Compare the pidls\r
+ if (pTD->GetFullCpidl() == cpidlFull)\r
+ {\r
+ SelectItem(hChild);\r
+ return TRUE;\r
+ }\r
+\r
+ //Next Sibling\r
+ hChild = GetNextSibling(hChild);\r
+ }\r
+ TRACE(_T("Item NOT found\n"));\r
+\r
+ return FALSE;\r
+}\r
+\r
+void CMyTreeView::SetImageLists()\r
+{\r
+ SHFILEINFO sfi;\r
+\r
+ // Get the system image list\r
+ m_hLargeImageList = (HIMAGELIST)::SHGetFileInfo(_T("C:\\"), 0, &sfi,\r
+ sizeof(SHFILEINFO), SHGFI_SYSICONINDEX);\r
+\r
+ m_hSmallImageList = (HIMAGELIST)::SHGetFileInfo(_T("C:\\"), 0, &sfi,\r
+ sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);\r
+}\r
+\r
+LRESULT CMyTreeView::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (uMsg)\r
+ {\r
+ case WM_DRAWITEM:\r
+ case WM_MENUCHAR:\r
+ case WM_MEASUREITEM:\r
+ case WM_INITMENUPOPUP:\r
+ {\r
+ if(m_ccm2.GetIContextMenu2())\r
+ m_ccm2.HandleMenuMsg(uMsg, wParam, lParam);\r
+ }\r
+ break;\r
+ case WM_DESTROY:\r
+ // Cleanup\r
+ m_pItems.clear();\r
+ break;\r
+ }\r
+\r
+ return WndProcDefault(uMsg, wParam, lParam);\r
+}\r
+\r
+///////////////////////////////////\r
+//TreeItemData function definitions\r
+CMyTreeView::TreeItemData::TreeItemData(Cpidl& cpidl)\r
+{\r
+ m_cpidlRel = cpidl;\r
+ m_cpidlFull = cpidl;\r
+}\r
+\r
+CMyTreeView::TreeItemData::TreeItemData(Cpidl& cpidlParent, Cpidl& cpidlRel, CShellFolder& cParentFolder)\r
+{\r
+ m_cParentFolder = cParentFolder;\r
+ m_cpidlFull = cpidlParent + cpidlRel;\r
+ m_cpidlRel = cpidlRel;\r
+}\r
+\r
+CMyTreeView::TreeItemData::~TreeItemData()\r
+{\r
+}\r