ShellTree.cpp
上传用户:yangzi5763
上传日期:2007-01-02
资源大小:239k
文件大小:26k
源码类别:

ActiveX/DCOM/ATL

开发平台:

Visual C++

  1. // ShellTree.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "ShellTree.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #undef THIS_FILE
  8. static char THIS_FILE[] = __FILE__;
  9. #endif
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CShellTree
  12. CShellTree::CShellTree()
  13. {
  14. }
  15. CShellTree::~CShellTree()
  16. {
  17. }
  18. BEGIN_MESSAGE_MAP(CShellTree, CTreeCtrl)
  19. //{{AFX_MSG_MAP(CShellTree)
  20. //}}AFX_MSG_MAP
  21. END_MESSAGE_MAP()
  22. /****************************************************************************
  23. *
  24. *    FUNCTION: PopulateTree()
  25. *
  26. *    PURPOSE:  Processes the File.Fill/RefreshTree command
  27. *
  28. ****************************************************************************/
  29. void CShellTree::PopulateTree() 
  30. {
  31.     LPSHELLFOLDER lpsf=NULL;
  32.     LPITEMIDLIST  lpi=NULL;
  33.     HRESULT hr;
  34.     TV_SORTCB      tvscb;
  35.    
  36.     // Get a pointer to the desktop folder.
  37.     hr=SHGetDesktopFolder(&lpsf);
  38.     if (SUCCEEDED(hr))
  39.     {
  40.        // Initialize the tree view to be empty.
  41.        DeleteAllItems();
  42.        // Fill in the tree view from the root.
  43.        FillTreeView(lpsf,
  44.                     NULL,
  45.                     TVI_ROOT);
  46.        // Release the folder pointer.
  47.        lpsf->Release();
  48.     }
  49.     tvscb.hParent     = TVI_ROOT;
  50.     tvscb.lParam      = 0;
  51.     tvscb.lpfnCompare = TreeViewCompareProc;
  52.     // Sort the items in the tree view
  53. SortChildrenCB(&tvscb/*, FALSE*/);
  54.     
  55. HTREEITEM hItem;
  56. hItem = GetRootItem();
  57. Expand(hItem,TVE_EXPAND);
  58. }
  59. /****************************************************************************
  60. *
  61. *  FUNCTION: FillTreeView( LPSHELLFOLDER lpsf,
  62. *                          LPITEMIDLIST  lpifq,
  63. *                          HTREEITEM     hParent)
  64. *
  65. *  PURPOSE: Fills a branch of the TreeView control.  Given the
  66. *           shell folder, enumerate the subitems of this folder,
  67. *           and add the appropriate items to the tree.
  68. *
  69. *  PARAMETERS:
  70. *    lpsf         - Pointer to shell folder that we want to enumerate items 
  71. *    lpifq        - Fully qualified item id list to the item that we are enumerating
  72. *                   items for.  In other words, this is the PIDL to the item
  73. *                   identified by the lpsf parameter.
  74. *    hParent      - Parent node
  75. *
  76. *  COMMENTS:
  77. *    This function enumerates the items in the folder identifed by lpsf.
  78. *    Note that since we are filling the left hand pane, we will only add
  79. *    items that are folders and/or have sub-folders.  We *could* put all
  80. *    items in here if we wanted, but that's not the intent.
  81. *
  82. ****************************************************************************/
  83. void CShellTree::FillTreeView(LPSHELLFOLDER lpsf, LPITEMIDLIST  lpifq, HTREEITEM     hParent)
  84. {
  85.     TV_ITEM         tvi;                          // TreeView Item.
  86.     TV_INSERTSTRUCT tvins;                        // TreeView Insert Struct.
  87.     HTREEITEM       hPrev = NULL;                 // Previous Item Added.
  88.     LPSHELLFOLDER   lpsf2=NULL;
  89.     LPENUMIDLIST    lpe=NULL;
  90.     LPITEMIDLIST    lpi=NULL, lpiTemp=NULL, lpifqThisItem;
  91.     LPTVITEMDATA    lptvid=NULL;
  92.     LPMALLOC        lpMalloc=NULL;
  93.     ULONG           ulFetched;
  94.     UINT            uCount=0;
  95.     HRESULT         hr;
  96.     TCHAR            szBuff[256];
  97.     HWND            hwnd=::GetParent(m_hWnd);
  98.     // Allocate a shell memory object. 
  99.     hr=::SHGetMalloc(&lpMalloc);
  100.     if (FAILED(hr))
  101.        return;
  102.     if (SUCCEEDED(hr))
  103.     {
  104.         // Get the IEnumIDList object for the given folder.
  105.         hr=lpsf->EnumObjects(hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &lpe);
  106.         if (SUCCEEDED(hr))
  107.         {
  108.             // Enumerate throught the list of folder and non-folder objects.
  109.             while (S_OK==lpe->Next(1, &lpi, &ulFetched))
  110.             {
  111.                 //Create a fully qualified path to the current item
  112.                 //The SH* shell api's take a fully qualified path pidl,
  113.                 //(see GetIcon above where I call SHGetFileInfo) whereas the
  114.                 //interface methods take a relative path pidl.
  115.                 ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER;
  116.                 // Determine what type of object we have.
  117.                 lpsf->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lpi, &ulAttrs);
  118.                 if (ulAttrs & (SFGAO_HASSUBFOLDER | SFGAO_FOLDER))
  119.                 {
  120.                    //We need this next if statement so that we don't add things like
  121.                    //the MSN to our tree.  MSN is not a folder, but according to the
  122.                    //shell it has subfolders.
  123.                    if (ulAttrs & SFGAO_FOLDER)
  124.                    {
  125.                       tvi.mask= TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  126.                       if (ulAttrs & SFGAO_HASSUBFOLDER)
  127.                       {
  128.                          //This item has sub-folders, so let's put the + in the TreeView.
  129.                          //The first time the user clicks on the item, we'll populate the
  130.                          //sub-folders.
  131.                          tvi.cChildren=1;
  132.                          tvi.mask |= TVIF_CHILDREN;
  133.                       }
  134.                         
  135.                       //OK, let's get some memory for our ITEMDATA struct
  136.                       lptvid = (LPTVITEMDATA)lpMalloc->Alloc(sizeof(TVITEMDATA));
  137.                       if (!lptvid)
  138.                          goto Done;  // Error - could not allocate memory.
  139.    
  140.                       //Now get the friendly name that we'll put in the treeview.
  141.                       if (!GetName(lpsf, lpi, SHGDN_NORMAL, szBuff))
  142.                          goto Done; // Error - could not get friendly name.
  143.                       tvi.pszText    = szBuff;
  144.                       tvi.cchTextMax = MAX_PATH;
  145.     
  146.                       lpifqThisItem=ConcatPidls(lpifq, lpi);
  147.       
  148.                       //Now, make a copy of the ITEMIDLIST
  149.                       lptvid->lpi=CopyITEMID(lpMalloc, lpi);
  150.    
  151.                       GetNormalAndSelectedIcons(lpifqThisItem, &tvi);
  152.    
  153.                       lptvid->lpsfParent=lpsf;    //Store the parent folders SF
  154.                       lpsf->AddRef();
  155.                       lptvid->lpifq=ConcatPidls(lpifq, lpi);
  156.    
  157.                       tvi.lParam = (LPARAM)lptvid;
  158.    
  159.                       // Populate the TreeVeiw Insert Struct
  160.                       // The item is the one filled above.
  161.                       // Insert it after the last item inserted at this level.
  162.                       // And indicate this is a root entry.
  163.                       tvins.item         = tvi;
  164.                       tvins.hInsertAfter = hPrev;
  165.                       tvins.hParent      = hParent;
  166.    
  167.                       // Add the item to the tree
  168.                       hPrev = InsertItem(&tvins);
  169.                    }
  170.                    // Free this items task allocator.
  171.                    lpMalloc->Free(lpifqThisItem);  
  172.                    lpifqThisItem=0;
  173.                 }
  174.                 lpMalloc->Free(lpi);  //Free the pidl that the shell gave us.
  175.                 lpi=0;
  176.             }
  177.         }
  178.     }
  179.     else
  180.        return;
  181. Done:
  182.  
  183.     if (lpe)  
  184.         lpe->Release();
  185.     //The following 2 if statements will only be TRUE if we got here on an
  186.     //error condition from the "goto" statement.  Otherwise, we free this memory
  187.     //at the end of the while loop above.
  188.     if (lpi && lpMalloc)           
  189.         lpMalloc->Free(lpi);
  190.     if (lpifqThisItem && lpMalloc) 
  191.         lpMalloc->Free(lpifqThisItem);  
  192.     if (lpMalloc) 
  193.         lpMalloc->Release();
  194. }
  195. /****************************************************************************
  196. *
  197. *    FUNCTION: GetIcon(LPITEMIDLIST lpi, UINT uFlags)
  198. *
  199. *    PURPOSE:  Gets the index for the current icon.  Index is index into system
  200. *              image list.
  201. *
  202. *  PARAMETERS:
  203. *    lpi    - Fully qualified item id list for current item.
  204. *    uFlags - Flags for SHGetFileInfo()
  205. *
  206. *  RETURN VALUE:
  207. *    Icon index for current item.
  208. ****************************************************************************/
  209. int CShellTree::GetIcon(LPITEMIDLIST lpi, UINT uFlags)
  210. {
  211.    SHFILEINFO    sfi;
  212.    SHGetFileInfo((LPCTSTR)lpi, 
  213.                  0,
  214.                  &sfi, 
  215.                  sizeof(SHFILEINFO), 
  216.                  uFlags);
  217.    return sfi.iIcon;
  218. }
  219. /****************************************************************************
  220. *
  221. *    FUNCTION: GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem)
  222. *
  223. *    PURPOSE:  Gets the index for the normal and selected icons for the current item.
  224. *
  225. *    PARAMETERS:
  226. *    lpifq    - Fully qualified item id list for current item.
  227. *    lptvitem - Pointer to treeview item we are about to add to the tree.
  228. *
  229. ****************************************************************************/
  230. void CShellTree::GetNormalAndSelectedIcons(LPITEMIDLIST lpifq,
  231.                                LPTV_ITEM lptvitem)
  232. {
  233.    //Note that we don't check the return value here because if GetIcon()
  234.    //fails, then we're in big trouble...
  235.    lptvitem->iImage = GetIcon(lpifq, SHGFI_PIDL | 
  236.                               SHGFI_SYSICONINDEX | 
  237.                               SHGFI_SMALLICON);
  238.    
  239.    lptvitem->iSelectedImage = GetIcon(lpifq, SHGFI_PIDL | 
  240.                                       SHGFI_SYSICONINDEX | 
  241.                                       SHGFI_SMALLICON |
  242.                                       SHGFI_OPENICON);
  243.    
  244.    return;
  245. }
  246. /****************************************************************************
  247. *
  248. *  FUNCTION: DoTheMenuThing(HWND hwnd, 
  249. *                           LPSHELLFOLDER lpsfParent,
  250. *                           LPITEMIDLIST  lpi,
  251. *                           LPPOINT lppt)
  252. *
  253. *  PURPOSE: Displays a popup context menu, given a parent shell folder,
  254. *           relative item id and screen location.
  255. *
  256. *  PARAMETERS:
  257. *    hwnd       - Parent window handle
  258. *    lpsfParent - Pointer to parent shell folder.
  259. *    lpi        - Pointer to item id that is relative to lpsfParent
  260. *    lppt       - Screen location of where to popup the menu.
  261. *
  262. *  RETURN VALUE:
  263. *    Returns TRUE on success, FALSE on failure
  264. *
  265. ****************************************************************************/
  266. BOOL CShellTree::DoTheMenuThing(HWND hwnd, LPSHELLFOLDER lpsfParent,
  267.      LPITEMIDLIST  lpi, LPPOINT lppt)
  268. {
  269.     LPCONTEXTMENU lpcm;
  270.     HRESULT       hr;
  271.     TCHAR          szTemp[64];
  272.     CMINVOKECOMMANDINFO cmi;
  273.     DWORD               dwAttribs=0;
  274.     int                 idCmd;
  275.     HMENU               hMenu;
  276.     BOOL                bSuccess=TRUE;
  277.     hr=lpsfParent->GetUIObjectOf(hwnd,
  278.         1,  //Number of objects to get attributes of
  279.         (const struct _ITEMIDLIST **)&lpi,
  280.         IID_IContextMenu,
  281.         0,
  282.         (LPVOID *)&lpcm);
  283.     if (SUCCEEDED(hr))  
  284.     {
  285.        hMenu = CreatePopupMenu();
  286.        if (hMenu)
  287.        {
  288.           hr=lpcm->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_EXPLORE);
  289.           if (SUCCEEDED(hr))
  290.           {
  291.              idCmd=TrackPopupMenu(hMenu, 
  292.                 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON, 
  293.                 lppt->x, lppt->y, 0, hwnd, NULL);
  294.              if (idCmd)
  295.              {
  296.                 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
  297.                 cmi.fMask  = 0;
  298.                 cmi.hwnd   = hwnd;
  299.                 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCE(idCmd-1);
  300.                 cmi.lpParameters = NULL;
  301.                cmi.lpDirectory  = NULL;
  302.                 cmi.nShow        = SW_SHOWNORMAL;
  303.                 cmi.dwHotKey     = 0;
  304.                 cmi.hIcon        = NULL;
  305.                 hr=lpcm->InvokeCommand(&cmi);
  306.                 if (!SUCCEEDED(hr))  
  307.                 {
  308.                    wsprintf(szTemp, _T("InvokeCommand failed. hr=%lx"), hr);
  309.                    AfxMessageBox(szTemp);
  310.                 }
  311.              }
  312.           }
  313.           else
  314.              bSuccess = FALSE;
  315.           DestroyMenu(hMenu);
  316.        }
  317.        else
  318.           bSuccess = FALSE;
  319.        lpcm->Release();
  320.     } 
  321.     else
  322.     {
  323.        wsprintf(szTemp, _T("GetUIObjectOf failed! hr=%lx"), hr);
  324.        AfxMessageBox(szTemp );
  325.        bSuccess = FALSE;
  326.     }
  327.     return bSuccess;
  328. }
  329. /****************************************************************************
  330. *
  331. *    FUNCTION: TreeViewCompareProc(LPARAM, LPARAM, LPARAM)
  332. *
  333. *    PURPOSE:  Callback routine for sorting the tree 
  334. *
  335. ****************************************************************************/
  336. int CALLBACK CShellTree::TreeViewCompareProc(LPARAM lparam1, 
  337.     LPARAM lparam2, LPARAM lparamSort)
  338. {
  339.     LPTVITEMDATA lptvid1=(LPTVITEMDATA)lparam1;
  340.     LPTVITEMDATA lptvid2=(LPTVITEMDATA)lparam2;
  341.     HRESULT   hr;
  342.     hr = lptvid1->lpsfParent->CompareIDs(0,lptvid1->lpi,lptvid2->lpi);
  343.     if (FAILED(hr))
  344.        return 0;
  345.     return (short)SCODE_CODE(GetScode(hr));
  346. }
  347. // 
  348. // FUNCTIONS THAT DEAL WITH PIDLs
  349. //
  350. /****************************************************************************
  351. *
  352. *    FUNCTION: Next(LPCITEMIDLIST pidl)
  353. *
  354. *    PURPOSE:  Gets the next PIDL in the list 
  355. *
  356. ****************************************************************************/
  357. LPITEMIDLIST CShellTree::Next(LPCITEMIDLIST pidl)
  358. {
  359.    LPSTR lpMem=(LPSTR)pidl;
  360.    lpMem+=pidl->mkid.cb;
  361.    return (LPITEMIDLIST)lpMem;
  362. }
  363. /****************************************************************************
  364. *
  365. *    FUNCTION: GetSize(LPCITEMIDLIST pidl)
  366. *
  367. *    PURPOSE:  Gets the size of the PIDL 
  368. *
  369. ****************************************************************************/
  370. UINT CShellTree::GetSize(LPCITEMIDLIST pidl)
  371. {
  372.     UINT cbTotal = 0;
  373.     if (pidl)
  374.     {
  375.         cbTotal += sizeof(pidl->mkid.cb);       // Null terminator
  376.         while (pidl->mkid.cb)
  377.         {
  378.             cbTotal += pidl->mkid.cb;
  379.             pidl = Next(pidl);
  380.         }
  381.     }
  382.     return cbTotal;
  383. }
  384. /****************************************************************************
  385. *
  386. *    FUNCTION: CreatePidl(UINT cbSize)
  387. *
  388. *    PURPOSE:  Allocates a PIDL 
  389. *
  390. ****************************************************************************/
  391. LPITEMIDLIST CShellTree::CreatePidl(UINT cbSize)
  392. {
  393.     LPMALLOC lpMalloc;
  394.     HRESULT  hr;
  395.     LPITEMIDLIST pidl=NULL;
  396.     hr=SHGetMalloc(&lpMalloc);
  397.     if (FAILED(hr))
  398.        return 0;
  399.     pidl=(LPITEMIDLIST)lpMalloc->Alloc(cbSize);
  400.     if (pidl)
  401.         memset(pidl, 0, cbSize);      // zero-init for external task   alloc
  402.     if (lpMalloc) lpMalloc->Release();
  403.     return pidl;
  404. }
  405. /****************************************************************************
  406. *
  407. *    FUNCTION: ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  408. *
  409. *    PURPOSE:  Concatenates two PIDLs 
  410. *
  411. ****************************************************************************/
  412. LPITEMIDLIST CShellTree::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  413. {
  414.     LPITEMIDLIST pidlNew;
  415.     UINT cb1;
  416.     UINT cb2;
  417.     if (pidl1)  //May be NULL
  418.        cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
  419.     else
  420.        cb1 = 0;
  421.     cb2 = GetSize(pidl2);
  422.     pidlNew = CreatePidl(cb1 + cb2);
  423.     if (pidlNew)
  424.     {
  425.         if (pidl1)
  426.            memcpy(pidlNew, pidl1, cb1);
  427.         memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
  428.     }
  429.     return pidlNew;
  430. }
  431. /****************************************************************************
  432. *
  433. *    FUNCTION: CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
  434. *
  435. *    PURPOSE:  Copies the ITEMID 
  436. *
  437. ****************************************************************************/
  438. LPITEMIDLIST CShellTree::CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
  439. {
  440.    LPITEMIDLIST lpiTemp;
  441.    lpiTemp=(LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb+sizeof(lpi->mkid.cb));
  442.    CopyMemory((PVOID)lpiTemp, (CONST VOID *)lpi, lpi->mkid.cb+sizeof(lpi->mkid.cb));
  443.    return lpiTemp;
  444. }
  445. /****************************************************************************
  446. *
  447. *    FUNCTION: GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST  lpi,DWORD dwFlags,
  448. *             LPSTR         lpFriendlyName)
  449. *
  450. *    PURPOSE:  Gets the friendly name for the folder 
  451. *
  452. ****************************************************************************/
  453. BOOL CShellTree::GetName(LPSHELLFOLDER lpsf,
  454.              LPITEMIDLIST  lpi,
  455.  DWORD         dwFlags,
  456.              LPTSTR         lpFriendlyName)
  457. {
  458.    BOOL   bSuccess=TRUE;
  459.    STRRET str;
  460.    if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str))
  461.    {
  462.       switch (str.uType)
  463.       {
  464.          case STRRET_WSTR:
  465. #ifndef _UNICODE
  466.             WideCharToMultiByte(CP_ACP,                 // CodePage
  467.                                 0,                // dwFlags
  468.                                 str.pOleStr,            // lpWideCharStr
  469.                                 -1,                     // cchWideChar
  470.                                 lpFriendlyName,         // lpMultiByteStr
  471. MAX_PATH,
  472.                                 //sizeof(lpFriendlyName), // cchMultiByte, wrong. sizeof on a pointer, psk, psk
  473.                                 NULL,                   // lpDefaultChar,
  474.                                 NULL);                  // lpUsedDefaultChar
  475. #else
  476. lstrcpy(lpFriendlyName, str.pOleStr);
  477. #endif
  478.              break;
  479.          case STRRET_OFFSET:
  480.              lstrcpy(lpFriendlyName, CString((BYTE*)lpi+str.uOffset));
  481.              break;
  482.          case STRRET_CSTR:
  483.              lstrcpy(lpFriendlyName, CString(str.cStr));
  484.              break;
  485.          default:
  486.              bSuccess = FALSE;
  487.              break;
  488.       }
  489.    }
  490.    else
  491.       bSuccess = FALSE;
  492.    return bSuccess;
  493. }
  494. /****************************************************************************
  495. *
  496. *    FUNCTION: GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
  497. *
  498. *    PURPOSE:  Gets the Fully qualified Pidls for the folder 
  499. *
  500. ****************************************************************************/
  501. LPITEMIDLIST CShellTree::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
  502. {
  503.    TCHAR szBuff[MAX_PATH];
  504.    OLECHAR szOleChar[MAX_PATH];
  505.    LPSHELLFOLDER lpsfDeskTop;
  506.    LPITEMIDLIST  lpifq;
  507.    ULONG ulEaten, ulAttribs;
  508.    HRESULT hr;
  509.    if (!GetName(lpsf, lpi, SHGDN_FORPARSING, szBuff))
  510.       return NULL;
  511.    hr=SHGetDesktopFolder(&lpsfDeskTop);
  512.    if (FAILED(hr))
  513.       return NULL;
  514.    MultiByteToWideChar(CP_ACP,
  515.    MB_PRECOMPOSED,
  516.    (LPSTR)szBuff,
  517.    -1,
  518.    (USHORT *)szOleChar,
  519.    sizeof(szOleChar));
  520.    hr=lpsfDeskTop->ParseDisplayName(NULL,
  521. NULL,
  522. szOleChar,
  523. &ulEaten,
  524. &lpifq,
  525. &ulAttribs);
  526.    lpsfDeskTop->Release();
  527.    if (FAILED(hr))
  528.       return NULL;
  529.    return lpifq;
  530. }
  531. /////////////////////////////////////////////////////////////////////////////
  532. // CShellTree message handlers
  533. /****************************************************************************
  534. *
  535. * FUNCTION: OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) 
  536. *
  537. * PURPOSE: Reponds to an TVN_ITEMEXPANDING message in order to fill up
  538. * subdirectories. Pass the parameters from OnItemExpanding() to 
  539. * this function. You need to do that or your folders won't
  540. * expand.
  541. *
  542. * OTHER: It can also be used to update a corresponding listview. Seem MFCENUM
  543. *
  544. * MESSAGEMAP: TVN_ITEMEXPANDING
  545. *
  546. ****************************************************************************/
  547. void CShellTree::FolderExpanding(NMHDR* pNMHDR, LRESULT* pResult) 
  548. {
  549. LPTVITEMDATA   lptvid;  //Long pointer to TreeView item data
  550. HRESULT        hr;
  551. LPSHELLFOLDER  lpsf2=NULL;
  552. static char    szBuff[MAX_PATH];
  553. TV_SORTCB      tvscb;
  554. NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
  555. // TODO: Add your control notification handler code here
  556.     if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
  557.          return;
  558.     lptvid=(LPTVITEMDATA)pnmtv->itemNew.lParam;
  559.     if (lptvid)
  560.        {
  561.             hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
  562.                 0, IID_IShellFolder,(LPVOID *)&lpsf2);
  563.             if (SUCCEEDED(hr))
  564.             {
  565.                 FillTreeView(lpsf2,
  566.                        lptvid->lpifq,
  567.                        pnmtv->itemNew.hItem);
  568.             }
  569.             tvscb.hParent     = pnmtv->itemNew.hItem;
  570.             tvscb.lParam      = 0;
  571.             tvscb.lpfnCompare = TreeViewCompareProc;
  572.             SortChildrenCB(&tvscb /*, FALSE*/);
  573.     }
  574. *pResult = 0;
  575. }
  576. /****************************************************************************
  577. *
  578. * FUNCTION: FolderPopup(NMHDR* pNMHDR, LRESULT* pResult) 
  579. *
  580. * PURPOSE: Diplays a popup menu for the folder selected. Pass the
  581. * parameters from Rclick() to this function.
  582. *
  583. * MESSAGEMAP: NM_RCLICK;
  584. *
  585. ****************************************************************************/
  586. void CShellTree::FolderPopup(NMHDR* pNMHDR, LRESULT* pResult) 
  587. {
  588. // TODO: Add your control notification handler code here
  589. POINT pt;
  590. LPTVITEMDATA lptvid;  //Long pointer to TreeView item data
  591. LPSHELLFOLDER lpsf2=NULL;
  592. static char szBuff[MAX_PATH];
  593. TV_HITTESTINFO tvhti;
  594. TV_ITEM tvi;
  595. // TODO: Add your control notification handler code here
  596. ::GetCursorPos((LPPOINT)&pt);
  597. ScreenToClient(&pt);
  598. tvhti.pt=pt;
  599.     HitTest(&tvhti);
  600.     SelectItem(tvhti.hItem);
  601. if (tvhti.flags & (TVHT_ONITEMLABEL|TVHT_ONITEMICON))
  602. {
  603. ClientToScreen(&pt);
  604. tvi.mask=TVIF_PARAM;
  605. tvi.hItem=tvhti.hItem;
  606.         if (!GetItem(&tvi)){
  607. return;
  608. }
  609. lptvid=(LPTVITEMDATA)tvi.lParam;
  610. DoTheMenuThing(::GetParent(m_hWnd),
  611. lptvid->lpsfParent, lptvid->lpi, &pt);
  612. }
  613. *pResult = 0;
  614. }
  615. /****************************************************************************
  616. *
  617. * FUNCTION: FolderSelected(NMHDR* pNMHDR, LRESULT* pResult, CString &szFolderPath) 
  618. *
  619. * PURPOSE: Call this function if for example you want to put the path of the folder
  620. * selected inside a combobox or an edit window. You would pass the
  621. * parameters from OnSelChanged() to this function along with a CString object
  622. * that will hold the folder path. If the path is not
  623. * in the filesystem(eg MyComputer) it returns false.
  624. *
  625. * MESSAGEMAP: TVN_SELCHANGED
  626. *
  627. ****************************************************************************/
  628. BOOL CShellTree::FolderSelected(NMHDR* pNMHDR, LRESULT* pResult, CString &szFolderPath) 
  629. {
  630. // TODO: Add your control notification handler code here
  631. POINT pt;
  632. LPTVITEMDATA lptvid;  //Long pointer to TreeView item data
  633. LPSHELLFOLDER lpsf2=NULL;
  634. static TCHAR szBuff[MAX_PATH];
  635. TV_HITTESTINFO tvhti;
  636. TV_ITEM tvi;
  637. HRESULT hr;
  638. BOOL bRet=false;
  639. // TODO: Add your control notification handler code here
  640. ::GetCursorPos((LPPOINT)&pt);
  641. ScreenToClient(&pt);
  642. tvhti.pt=pt;
  643.     HitTest(&tvhti);
  644.     SelectItem(tvhti.hItem);
  645. if (tvhti.flags & (TVHT_ONITEMLABEL|TVHT_ONITEMICON))
  646. {
  647. ClientToScreen(&pt);
  648. tvi.mask=TVIF_PARAM;
  649. tvi.hItem=tvhti.hItem;
  650.         if (!GetItem(&tvi))
  651. return false;
  652. lptvid=(LPTVITEMDATA)tvi.lParam;
  653. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  654. {
  655. hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
  656.  0,IID_IShellFolder,(LPVOID *)&lpsf2);
  657. if (SUCCEEDED(hr))
  658. {
  659. ULONG ulAttrs = SFGAO_FILESYSTEM;
  660. // Determine what type of object we have.
  661. lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  662. if (ulAttrs & (SFGAO_FILESYSTEM))
  663. {
  664. if(SHGetPathFromIDList(lptvid->lpifq,szBuff)){
  665. szFolderPath = szBuff;
  666. bRet = true;
  667. }
  668. }
  669. }
  670. }
  671. if(lpsf2)
  672. lpsf2->Release();
  673. }
  674. *pResult = 0;
  675. return bRet;
  676. }
  677. /****************************************************************************
  678. *
  679. * FUNCTION: EnableImages()
  680. *
  681. * PURPOSE: Obtains a handle to the system image list and attaches it
  682. * to the tree control. DO NOT DELETE the imagelist
  683. *
  684. * MESSAGEMAP: NONE
  685. *
  686. ****************************************************************************/
  687. void CShellTree::EnableImages()
  688. {
  689. // Get the handle to the system image list, for our icons
  690.     HIMAGELIST  hImageList;
  691.     SHFILEINFO    sfi;
  692.     hImageList = (HIMAGELIST)SHGetFileInfo(_T("C:\"), 
  693.                                            0,
  694.                                            &sfi, 
  695.                                            sizeof(SHFILEINFO), 
  696.                                            SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  697.     // Attach ImageList to TreeView
  698.     if (hImageList)
  699.         ::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL,
  700.             (LPARAM)hImageList);
  701. }
  702. /****************************************************************************
  703. *
  704. * FUNCTION: GetSelectedFolderPath(CString &szFolderPath)
  705. *
  706. * PURPOSE: Retrieves the path of the currently selected string.
  707. * Pass a CString object that will hold the folder path. 
  708. * If the path is not in the filesystem(eg MyComputer) 
  709. * or none is selected it returns false.
  710. *
  711. * MESSAGEMAP: NONE
  712. *
  713. ****************************************************************************/
  714. BOOL CShellTree::GetSelectedFolderPath(CString &szFolderPath)
  715. {
  716. LPTVITEMDATA lptvid;  //Long pointer to TreeView item data
  717. LPSHELLFOLDER lpsf2=NULL;
  718. static TCHAR szBuff[MAX_PATH];
  719. HTREEITEM hItem;
  720. HRESULT hr;
  721. BOOL bRet=false;
  722. if((hItem = GetSelectedItem()))
  723. {
  724. lptvid=(LPTVITEMDATA)GetItemData(hItem);
  725. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  726. {
  727. hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
  728.  0,IID_IShellFolder,(LPVOID *)&lpsf2);
  729. if (SUCCEEDED(hr))
  730. {
  731. ULONG ulAttrs = SFGAO_FILESYSTEM;
  732. // Determine what type of object we have.
  733. lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  734. if (ulAttrs & (SFGAO_FILESYSTEM))
  735. {
  736. if(SHGetPathFromIDList(lptvid->lpifq,szBuff)){
  737. szFolderPath = szBuff;
  738. bRet = true;
  739. }
  740. }
  741. }
  742. }
  743. if(lpsf2)
  744. lpsf2->Release();
  745. }
  746. return bRet;
  747. }