This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / IEShellTreeCtrl.cpp
diff --git a/subsys/system/explorer/Seashell/SeaShellExt/IEShellTreeCtrl.cpp b/subsys/system/explorer/Seashell/SeaShellExt/IEShellTreeCtrl.cpp
new file mode 100644 (file)
index 0000000..3b88fde
--- /dev/null
@@ -0,0 +1,691 @@
+//*******************************************************************************
+// COPYRIGHT NOTES
+// ---------------
+// You may use this source code, compile or redistribute it as part of your application 
+// for free. You cannot redistribute it as a part of a software development 
+// library without the agreement of the author. If the sources are 
+// distributed along with the application, you should leave the original 
+// copyright notes in the source code without any changes.
+// This code can be used WITHOUT ANY WARRANTIES at your own risk.
+// 
+// For the latest updates to this code, check this site:
+// http://www.masmex.com 
+// after Sept 2000
+// 
+// Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
+//*******************************************************************************
+
+// IEShellTreeCtrl.cpp : implementation file
+#include "stdafx.h"
+#include "IEShellTreeCtrl.h"
+#include "cbformats.h"
+#include "UIMessages.h"
+#include "dirwalk.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CIEShellTreeCtrl
+
+CIEShellTreeCtrl::CIEShellTreeCtrl()
+{
+       m_lptvid = NULL;
+       m_hListWnd = NULL;
+       m_hComboWnd = NULL;
+       m_nThreadCount = 0;
+       m_bRefreshAllowed = true;
+       m_bNotifyParent = false;
+       // Turn off WM_DROPFILES
+       SetDropFiles(false);
+}
+
+CIEShellTreeCtrl::~CIEShellTreeCtrl()
+{
+}
+
+void CIEShellTreeCtrl::ShellExecute(HTREEITEM hItem,LPCTSTR pszVerb)
+{
+       SHELLEXECUTEINFO si;
+       ZeroMemory(&si,sizeof(si));
+       si.cbSize = sizeof(si);
+       si.hwnd = GetSafeHwnd();
+       si.nShow = SW_SHOW;
+       si.lpIDList = (LPVOID)GetPathPidl(hItem);
+       si.fMask  = SEE_MASK_INVOKEIDLIST;
+       if (pszVerb)
+               si.lpVerb = pszVerb;
+       ShellExecuteEx(&si);
+}
+
+void CIEShellTreeCtrl::RefreshComboBox(LPTVITEMDATA lptvid)
+{
+       if (m_hComboWnd)
+       {
+               ::PostMessage(m_hComboWnd,WM_APP_CB_IE_POPULATE,(WPARAM)lptvid->lpifq,0);
+       }
+}
+
+void CIEShellTreeCtrl::SetNotificationObject(bool bNotify)
+{
+       if (bNotify)
+               CreateFileChangeThreads(GetSafeHwnd());
+       else
+               DestroyThreads();
+}
+
+void CIEShellTreeCtrl::UpOneLevel(HTREEITEM hItem)
+{
+       if (hItem == NULL)
+       {
+               hItem = GetSelectedItem();
+       }
+       if (hItem == NULL)
+               return;
+       HTREEITEM hParentItem = GetParentItem(hItem);
+       if (hParentItem)
+               Select(hParentItem,TVGN_CARET);
+}
+
+void CIEShellTreeCtrl::DestroyThreads()
+{
+    if (m_nThreadCount == 0) 
+               return;
+    for (UINT i=0;i < m_nThreadCount; i++)
+           m_event[i].SetEvent();
+    ::WaitForMultipleObjects (m_nThreadCount, m_hThreads, TRUE, INFINITE);
+    for (i=0; i < m_nThreadCount; i++)
+        delete m_pThreads[i];
+    m_nThreadCount = 0;
+}
+
+void CIEShellTreeCtrl::CreateFileChangeThreads(HWND hwnd)
+{
+       if (m_nThreadCount)
+               return;
+       TCHAR szDrives[MAX_PATH];
+       DWORD dwSize = sizeof(szDrives)/sizeof(TCHAR);
+       DWORD dwChars = GetLogicalDriveStrings(dwSize,szDrives);
+       if (dwChars == 0 || dwChars > dwSize) 
+       {
+               TRACE(_T("Warning: CreateFileChangeThreads failed in GetLogicalDriveStrings\n"));
+               return;
+       }
+       UINT nType;
+       CString sDrive;
+       LPCTSTR pszDrives=szDrives;
+       while (*pszDrives != '\0')
+       {
+               sDrive = pszDrives;
+               nType = ::GetDriveType(sDrive);
+               if (nType == DRIVE_FIXED || nType == DRIVE_REMOTE || nType == DRIVE_RAMDISK)
+               {
+                       CreateFileChangeThread(sDrive,hwnd);
+               }
+#if 1 // bugfix by mad79
+               pszDrives=pszDrives+sDrive.GetLength()+1;
+#else
+               pszDrives = _tcsninc(pszDrives,sDrive.GetLength()+1);
+#endif
+       }
+}
+
+void CIEShellTreeCtrl::CreateFileChangeThread(const CString& sPath,HWND hwnd)
+{
+       if (m_nThreadCount >= MAX_THREADS)
+               return;
+    PDC_THREADINFO pThreadInfo = new DC_THREADINFO; // Thread will delete
+    pThreadInfo->sPath = sPath;
+    pThreadInfo->hEvent = m_event[m_nThreadCount].m_hObject;
+    pThreadInfo->pTreeCtrl = this;
+
+    CWinThread* pThread = AfxBeginThread (ThreadFunc, pThreadInfo,
+        THREAD_PRIORITY_IDLE);
+
+    pThread->m_bAutoDelete = FALSE;
+    m_hThreads[m_nThreadCount] = pThread->m_hThread;
+    m_pThreads[m_nThreadCount++] = pThread;
+}
+
+HTREEITEM CIEShellTreeCtrl::SearchSiblings(HTREEITEM hItem,LPITEMIDLIST pidlAbs)
+{
+       LPTVITEMDATA pItem = NULL;
+       HTREEITEM hChildItem = GetChildItem(hItem);
+       HTREEITEM hFoundItem;
+       while (hChildItem) 
+       {
+                       pItem = (LPTVITEMDATA)GetItemData(hChildItem);
+                       if (GetShellPidl().ComparePidls(NULL,pItem->lpifq,pidlAbs))
+                          break;
+                       hFoundItem = SearchSiblings(hChildItem,pidlAbs);
+                       if (hFoundItem)
+                               return hFoundItem;
+                       hChildItem = GetNextSiblingItem(hChildItem);
+       }
+       return hChildItem;
+}
+
+HTREEITEM CIEShellTreeCtrl::ExpandMyComputer(LPITEMIDLIST pidlAbs)
+{
+       HTREEITEM hItem=NULL;
+       if (pidlAbs == NULL)
+               return hItem;
+       LPITEMIDLIST pidlMyComputer=NULL;
+       LPITEMIDLIST pidlFirst=GetShellPidl().CopyItemID(pidlAbs);
+    SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer); 
+       if (GetShellPidl().ComparePidls(NULL,pidlMyComputer,pidlFirst))
+       {
+               hItem = ExpandPidl(pidlMyComputer);
+       }
+       if (pidlMyComputer)
+               GetShellPidl().FreePidl(pidlMyComputer);
+       if (pidlFirst)
+               GetShellPidl().FreePidl(pidlFirst);
+       return hItem;
+}
+
+HTREEITEM CIEShellTreeCtrl::ExpandPidl(LPITEMIDLIST pidlAbs)
+{
+       HTREEITEM hItem = SearchSiblings(GetRootItem(),pidlAbs);
+       if (hItem)
+       {
+               Expand(hItem,TVE_EXPAND);
+       }
+       return hItem;
+}
+
+HTREEITEM CIEShellTreeCtrl::FindPidl(LPITEMIDLIST pidlAbs,BOOL bSelect)
+{
+       HTREEITEM hItem = NULL;
+       if (pidlAbs == NULL)
+               hItem = GetRootItem();
+       else
+               hItem = SearchSiblings(GetRootItem(),pidlAbs);
+       if (bSelect && hItem != GetSelectedItem())
+       {
+               SelectItem(hItem);
+               SelectionChanged(hItem,GetItemData(hItem));
+       }
+       return hItem;
+}
+
+HTREEITEM CIEShellTreeCtrl::FindItem (HTREEITEM hItem, const CString& strTarget)
+{
+    while (hItem != NULL) 
+       {
+        if (GetItemText (hItem) == strTarget)
+            break;
+        hItem = GetNextSiblingItem (hItem);
+    }
+    return hItem;
+}
+
+UINT CIEShellTreeCtrl::DeleteChildren (HTREEITEM hItem)
+{
+    UINT nCount = 0;
+    HTREEITEM hChild = GetChildItem (hItem);
+
+    while (hChild != NULL)
+       {
+        HTREEITEM hNextItem = GetNextSiblingItem (hChild);
+        DeleteItem (hChild);
+        hChild = hNextItem;
+        nCount++;
+    }
+    return nCount;
+}
+
+void CIEShellTreeCtrl::Init()
+{
+       ModifyStyle(0,TVS_EDITLABELS);
+       CIEFolderTreeCtrl::Init();
+}
+
+void CIEShellTreeCtrl::Refresh()
+{
+       SetRefreshAllowed(false);
+       CIEFolderTreeCtrl::Refresh();
+       SetRefreshAllowed(true);
+}
+
+bool CIEShellTreeCtrl::DragEnter(CDD_OleDropTargetInfo *pInfo)
+{
+       HTREEITEM hItem = pInfo->GetTreeItem(); 
+       if (hItem == NULL)
+               return false;
+       LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(hItem);
+       ASSERT(ptvid);
+       if (ptvid == NULL)
+               return false;
+       return m_ShellDragDrop.DragEnter(pInfo,ptvid->lpsfParent,ptvid->lpi);
+}
+
+bool CIEShellTreeCtrl::DragLeave(CDD_OleDropTargetInfo *pInfo)
+{
+       return m_ShellDragDrop.DragLeave(pInfo);
+}
+
+bool CIEShellTreeCtrl::DragOver(CDD_OleDropTargetInfo *pInfo)
+{
+       pInfo->SetDropEffect(DROPEFFECT_NONE);
+
+       HTREEITEM hItem = pInfo->GetTreeItem(); 
+       if (hItem == NULL)
+               return false;
+       LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(hItem);
+       ASSERT(ptvid);
+       if (ptvid == NULL)
+               return false;
+       return m_ShellDragDrop.DragOver(pInfo,ptvid->lpsfParent,ptvid->lpi);
+}
+
+bool CIEShellTreeCtrl::DragDrop(CDD_OleDropTargetInfo *pInfo)
+{
+       HTREEITEM hItem = pInfo->GetTreeItem(); 
+       if (hItem == NULL)
+               return false;
+       LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(hItem);
+       ASSERT(ptvid);
+       if (ptvid == NULL)
+               return false;
+       return m_ShellDragDrop.DragDrop(pInfo,ptvid->lpsfParent,ptvid->lpi);
+}
+
+DROPEFFECT CIEShellTreeCtrl::DoDragDrop(NM_TREEVIEW* pNMTreeView,COleDataSource *pOleDataSource)
+{
+       if (pNMTreeView->itemNew.hItem == GetRootItem())
+               return DROPEFFECT_NONE;
+       CCF_ShellIDList sl;
+       CShellPidl pidl;
+       HTREEITEM hParentItem = GetParentItem(pNMTreeView->itemNew.hItem);
+       LPTVITEMDATA ptvid = (LPTVITEMDATA)GetItemData(pNMTreeView->itemNew.hItem);
+       LPTVITEMDATA ptvid_parent = (LPTVITEMDATA)GetItemData(hParentItem);
+       ASSERT(ptvid);
+       ASSERT(ptvid_parent);
+       if (GetShellPidl().IsDesktopFolder(ptvid->lpsfParent))
+               sl.AddPidl(GetShellPidl().GetEmptyPidl());
+       else
+               sl.AddPidl(ptvid_parent->lpifq);
+       sl.AddPidl(ptvid->lpi);
+       CCF_HDROP cf_hdrop;
+       CCF_String cf_text;
+       CString sPath;
+       pidl.SHPidlToPathEx(ptvid->lpifq,sPath);
+       cf_hdrop.AddDropPoint(CPoint(pNMTreeView->ptDrag),FALSE);
+       cf_hdrop.AddFileName(sPath);
+       sPath += _T("\r\n");
+       cf_text.SetString(sPath);
+       CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_text,CWDClipboardData::e_cfString);
+       CWDClipboardData::Instance()->SetData(pOleDataSource,&cf_hdrop,CWDClipboardData::e_cfHDROP);
+       CWDClipboardData::Instance()->SetData(pOleDataSource,&sl,CWDClipboardData::e_cfShellIDList);
+       return GetShellPidl().GetDragDropAttributes(ptvid);
+}
+
+bool CIEShellTreeCtrl::EndLabelEdit(HTREEITEM hItem,LPCTSTR pszText)
+{
+       LPTVITEMDATA plvit = (LPTVITEMDATA)GetItemData(hItem);
+       CString sFromPath;
+       CString sToPath;
+       GetShellPidl().SHPidlToPathEx(plvit->lpifq,sFromPath);
+       sToPath = sFromPath;
+       sToPath.Replace(GetItemText(hItem),pszText);
+       SHFILEOPSTRUCT shf;
+       TCHAR szFrom[MAX_PATH+1];
+       TCHAR szTo[MAX_PATH+1];
+       ZeroMemory(szFrom,sizeof(szFrom));
+       lstrcpy(szFrom,sFromPath);
+       ZeroMemory(szTo,sizeof(szTo));
+       lstrcpy(szTo,sToPath);
+       ZeroMemory(&shf,sizeof(shf));
+       shf.hwnd = GetSafeHwnd();
+       shf.wFunc = FO_RENAME;
+       shf.pFrom = szFrom;
+       shf.pTo = szTo;
+#ifdef _DEBUG
+       CString sMess;
+       sMess = szFrom;
+       sMess += _T("\n");
+       sMess += szTo;
+       AfxMessageBox(sMess);
+#endif
+       if (SHFileOperation(&shf) == 0)
+               return true;
+       SetRefreshAllowed(false);
+       return false;
+}
+
+bool CIEShellTreeCtrl::SHMoveFile(HTREEITEM hSrcItem,HTREEITEM hDestItem)
+{
+       LPTVITEMDATA plvit_src = (LPTVITEMDATA)GetItemData(hSrcItem);
+       LPTVITEMDATA plvit_dest = (LPTVITEMDATA)GetItemData(hDestItem);
+       CString sFromPath;
+       CString sToPath;
+       GetShellPidl().SHPidlToPathEx(plvit_src->lpifq,sFromPath);
+       GetShellPidl().SHPidlToPathEx(plvit_dest->lpifq,sToPath);
+       SHFILEOPSTRUCT shf;
+       TCHAR szFrom[MAX_PATH+1];
+       TCHAR szTo[MAX_PATH+1];
+       ZeroMemory(szFrom,sizeof(szFrom));
+       lstrcpy(szFrom,sFromPath);
+       ZeroMemory(szTo,sizeof(szTo));
+       lstrcpy(szTo,sToPath);
+       ZeroMemory(&shf,sizeof(shf));
+       shf.hwnd = GetSafeHwnd();
+       shf.wFunc = FO_MOVE;
+       shf.pFrom = szFrom;
+       shf.pTo = szTo;
+       return SHFileOperation(&shf) == 0 ? true : false;
+}
+
+BOOL CIEShellTreeCtrl::TransferItem(HTREEITEM hitemDrag, HTREEITEM hitemDrop)
+{
+       return SHMoveFile(hitemDrag,hitemDrop) ? TRUE : FALSE;
+}
+
+bool CIEShellTreeCtrl::GetFolderInfo(HTREEITEM hItem,CString &sPath,CString &sName)
+{
+       LPTVITEMDATA lptvid = (LPTVITEMDATA)GetItemData(hItem);
+       if (lptvid == NULL)
+               return false;
+       GetShellPidl().SHPidlToPathEx(lptvid->lpifq,sPath,NULL,SHGDN_NORMAL);
+       GetShellPidl().GetDisplayName(lptvid->lpi,sName);
+       return true;
+}
+
+bool CIEShellTreeCtrl::LoadFolderItems(LPCTSTR pszPath)
+{
+       return LoadItems(pszPath);
+}
+
+CRefresh *CIEShellTreeCtrl::CreateRefreshObject(HTREEITEM hItem,LPARAM lParam)
+{
+       CRefreshShellFolder *pRefresh=NULL;
+       if (lParam)
+       {
+               pRefresh = new CRefreshShellFolder(hItem,lParam);
+       }
+       return pRefresh;
+}
+
+bool CIEShellTreeCtrl::Expanding(NM_TREEVIEW *nmtvw)
+{
+       if ((nmtvw->itemNew.state & TVIS_EXPANDEDONCE) || nmtvw->itemNew.hItem == GetRootItem())
+               return false;
+
+       LPSHELLFOLDER  pFolder=NULL;
+       CUIListCtrlData *pData = (CUIListCtrlData*)nmtvw->itemNew.lParam;
+       ASSERT(pData);
+       ASSERT_KINDOF(CUIListCtrlData,pData);
+       LPTVITEMDATA lptvid=(LPTVITEMDATA)pData->GetExtData();
+       if (lptvid)
+       {
+               HRESULT hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
+                       0, IID_IShellFolder,(LPVOID*)&pFolder);
+
+               if (SUCCEEDED(hr))
+               {
+                       if (!AddItems(nmtvw->itemNew.hItem,pFolder))
+                               SetButtonState(nmtvw->itemNew.hItem);
+               }
+               return false;
+       }
+       // prevent from expanding
+       return true;
+}
+
+BEGIN_MESSAGE_MAP(CIEShellTreeCtrl, CIEFolderTreeCtrl)
+       //{{AFX_MSG_MAP(CIEShellTreeCtrl)
+       ON_MESSAGE(WM_SETMESSAGESTRING,OnSetmessagestring)
+       ON_MESSAGE(WM_APP_CB_IE_HIT_ENTER,OnAppCbIeHitEnter)
+               // NOTE - the ClassWizard will add and remove mapping macros here.
+       ON_WM_DESTROY()
+       //}}AFX_MSG_MAP
+       ON_MESSAGE(WM_APP_POPULATE_TREE,OnAppPopulateTree)
+       ON_MESSAGE(WM_APP_CB_IE_SEL_CHANGE,OnCBIESelChange)
+       ON_MESSAGE(WM_APP_DIR_CHANGE_EVENT,OnAppDirChangeEvent)
+
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CIEShellTreeCtrl message handlers
+BOOL CIEShellTreeCtrl::OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult )
+{
+       if ((message == WM_MEASUREITEM || message == WM_DRAWITEM && wParam == 0) || message == WM_INITMENUPOPUP)
+       {
+               if (m_lptvid)
+               {
+                       return GetShellPidl().HandleMenuMsg(m_hWnd,m_lptvid->lpsfParent, m_lptvid->lpi,
+                                                                       message,wParam,lParam);
+               }
+       }
+       return CIEFolderTreeCtrl::OnWndMsg(message, wParam, lParam, pResult );
+}
+
+void CIEShellTreeCtrl::PreSubclassWindow()
+{
+       CIEFolderTreeCtrl::PreSubclassWindow();
+       CreateFileChangeThreads(GetSafeHwnd());
+}
+
+/////////////////////////////////////////////////////////////////////////
+// Thread function for detecting file system changes
+UINT CIEShellTreeCtrl::ThreadFunc (LPVOID pParam)
+{
+       ///////////////////////////////
+    PDC_THREADINFO pThreadInfo = (PDC_THREADINFO) pParam;
+    HANDLE hEvent = pThreadInfo->hEvent;
+       CIEShellTreeCtrl *pTreeCtrl = pThreadInfo->pTreeCtrl;
+    HWND hWnd = pTreeCtrl->GetSafeHwnd();
+       TCHAR szPath[MAX_PATH];
+       lstrcpy(szPath,pThreadInfo->sPath);
+    delete pThreadInfo;
+    ////////////////////////////////////
+
+    // Get a handle to a file change notification object.
+       TRACE(_T("Creating directory thread handler for %s\n"),szPath);
+    HANDLE hDirChange = ::FindFirstChangeNotification (szPath,TRUE,FILE_NOTIFY_CHANGE_DIR_NAME);
+
+    // Return now if ::FindFirstChangeNotification failed.
+    if (hDirChange == INVALID_HANDLE_VALUE)
+        return 1;
+       const int nHandles=2;
+    HANDLE aHandles[nHandles];
+    aHandles[0] = hDirChange;
+    aHandles[1] = hEvent;
+    BOOL bContinue = TRUE;
+
+    // Sleep until a file change notification wakes this thread or
+    // m_event becomes set indicating it's time for the thread to end.
+    while (bContinue)
+       {
+               TRACE(_T("TreeControl waiting for %u multiple objects\n"),nHandles);
+        DWORD dw = ::WaitForMultipleObjects (nHandles, aHandles, FALSE, INFINITE);
+        if (dw - WAIT_OBJECT_0 == 0) 
+               { // Respond to a change notification.
+            ::FindNextChangeNotification (hDirChange);
+                       TRACE(_T("-- Directory notify event was fired in CIEShellTreeCtrl --\n"));
+                       if (pTreeCtrl->RefreshAllowed())
+                       {
+                               ::PostMessage (hWnd, WM_APP_DIR_CHANGE_EVENT,0,0);
+                       }
+                       else
+                       {
+                               TRACE(_T("but not sending as refresh disallowed\n"));
+                               pTreeCtrl->SetRefreshAllowed(true);
+                               TRACE(_T("Refresh is now allowed\n"));
+                       }
+        }
+        else if(dw - WAIT_OBJECT_0 == 1) 
+               {
+            bContinue = FALSE;
+                       TRACE(_T("Directory Notify Thread was signalled to stop\n"));
+               }
+    }
+
+    // Close the file change notification handle and return.
+    ::FindCloseChangeNotification (hDirChange);
+       TRACE(_T("Directory Notify Thread is ending\n"));
+    return 0;
+}
+
+void CIEShellTreeCtrl::OnDestroy()
+{
+       DestroyThreads();
+       CIEFolderTreeCtrl::OnDestroy();
+}
+
+LRESULT CIEShellTreeCtrl::OnAppDirChangeEvent(WPARAM wParam, LPARAM lParam)
+{
+       if (!RefreshAllowed())
+               return 1L;
+       Refresh();
+       if (m_bNotifyParent)
+               GetParent()->SendMessage(WM_APP_UPDATE_ALL_VIEWS,(WPARAM)HINT_SHELL_DIR_CHANGED,(LPARAM)(LPCTSTR)GetRootPath());
+       return 1L;
+}
+
+LRESULT CIEShellTreeCtrl::OnCBIESelChange(WPARAM wParam,LPARAM lParam)
+{
+       LPITEMIDLIST pidl = (LPITEMIDLIST)wParam;
+       ExpandMyComputer(pidl);
+       FindPidl(pidl);                         
+       GetShellPidl().FreePidl(pidl);
+       SetFocus();
+       return 1L;
+}
+
+// Selection has changed
+void CIEShellTreeCtrl::UpdateEvent(LPARAM lHint,CObject *pHint)
+{
+       // TODO: Add your specialized code here and/or call the base class
+       // Notify the combo box
+       const CRefreshShellFolder *pRefresh = static_cast<CRefreshShellFolder*>(pHint);
+       LPTVITEMDATA lptvid = reinterpret_cast<LPTVITEMDATA>(pRefresh->GetItemData());
+       ASSERT(lptvid);
+       // Notify combo box
+       RefreshComboBox(lptvid);
+       // Notify list control
+       if (m_hListWnd)
+       {
+               ::SendMessage(m_hListWnd,WM_APP_UPDATE_ALL_VIEWS,(WPARAM)lHint,(LPARAM)pHint);
+               return;
+       }
+       // or let base class handle it
+       CUITreeCtrl::UpdateEvent(lHint,pHint);
+}
+
+LRESULT CIEShellTreeCtrl::OnAppPopulateTree(WPARAM wParam, LPARAM lParam)
+{
+       TRACE0("Selecting root item\n");
+       HTREEITEM hRoot = GetRootItem();
+       if (hRoot == NULL)
+               return 1L;      
+       SelectItem(hRoot);
+#ifndef _DEBUG
+       SelectionChanged(hRoot,GetItemData(hRoot));
+#else
+       LPTVITEMDATA lptvid = reinterpret_cast<LPTVITEMDATA>(GetItemData(hRoot));
+       RefreshComboBox(lptvid);
+#endif
+       return 1;
+}
+
+void CIEShellTreeCtrl::DeleteKey(HTREEITEM hItem)
+{
+       // TODO: Add your specialized code here and/or call the base class
+       SHFILEOPSTRUCT shf;
+       ZeroMemory(&shf,sizeof(shf));
+       TCHAR szFrom[MAX_PATH+1];
+       ZeroMemory(szFrom,sizeof(szFrom)*sizeof(TCHAR));
+       lstrcpy(szFrom,GetPathName(hItem));
+       shf.hwnd = GetSafeHwnd();
+       shf.wFunc = FO_DELETE;
+       shf.pFrom = szFrom;
+       shf.fFlags = GetKeyState(VK_SHIFT) < 0 ? 0 : FOF_ALLOWUNDO;
+       SHFileOperation(&shf);
+}
+
+void CIEShellTreeCtrl::DoubleClick(HTREEITEM hItem)
+{
+       // TODO: Add your specialized code here and/or call the base class
+       ShellExecute(hItem);
+}
+
+void CIEShellTreeCtrl::GoBack(HTREEITEM hItem)
+{
+       // TODO: Add your specialized code here and/or call the base class
+       UpOneLevel(hItem);
+}
+
+void CIEShellTreeCtrl::ShowPopupMenu(HTREEITEM hItem,CPoint point)
+{
+       // TODO: Add your specialized code here and/or call the base class
+       if (m_PopupID)
+       {
+               CUITreeCtrl::ShowPopupMenu(hItem,point);
+       }
+       // TODO: Add your control notification handler code here
+       m_lptvid = (LPTVITEMDATA)GetItemData(hItem);
+       if (m_lptvid)
+               GetShellPidl().PopupTheMenu(m_hWnd,m_lptvid->lpsfParent, &m_lptvid->lpi, 1, &point);
+}
+
+void CIEShellTreeCtrl::ShowProperties(HTREEITEM hItem)
+{
+       // TODO: Add your specialized code here and/or call the base class
+       ShellExecute(hItem,_T("properties"));
+}
+
+LRESULT CIEShellTreeCtrl::OnAppCbIeHitEnter(WPARAM wParam, LPARAM lParam)
+{
+       if (lParam == NULL)
+               return 0L;
+       LPCTSTR pszPath = (LPCTSTR)lParam;
+       LPITEMIDLIST pidl=NULL;
+       GetShellPidl().SHPathToPidlEx(pszPath,&pidl,NULL);
+       if (pidl == NULL)
+               return 0L;
+       int nCount = GetShellPidl().GetCount(pidl);
+       LPITEMIDLIST pidlPart=NULL;
+       LPITEMIDLIST pidlFull=NULL;
+       HTREEITEM hItem=NULL;
+       SetRedraw(FALSE);
+       for(int i=0;i < nCount;i++)
+       {
+               pidlPart=GetShellPidl().CopyItemID(pidl,i+1);
+               if (pidlPart)
+               {
+                       pidlFull = GetShellPidl().ConcatPidl(pidlFull,pidlPart);
+                       hItem = ExpandPidl(pidlFull);
+                       if (hItem == NULL)
+                               break;
+                       GetShellPidl().FreePidl(pidlPart);
+               }
+       }
+       if (hItem && GetShellPidl().ComparePidls(NULL,pidl,pidlFull))
+       {
+               Select(hItem,TVGN_CARET);
+       }
+       else
+       {
+               CString sMess;
+               sMess.Format(_T("%s was not found"),pszPath);
+               AfxMessageBox(sMess,MB_ICONSTOP);
+       }
+       if (pidl)
+               GetShellPidl().FreePidl(pidl);
+       if (pidlFull)
+               GetShellPidl().FreePidl(pidlFull);
+       SetRedraw(TRUE);
+       return 1;
+}
+
+LRESULT CIEShellTreeCtrl::OnSetmessagestring(WPARAM wParam, LPARAM lParam)
+{
+       if (GetParent())
+               return GetParent()->SendMessage(WM_SETMESSAGESTRING,wParam,lParam);
+       return 0;
+}