ShellTree.cpp
上传用户:louyoung
上传日期:2007-01-02
资源大小:123k
文件大小: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.     char            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((LPCSTR)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.     char          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 = 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, "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, "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.              LPSTR         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.             WideCharToMultiByte(CP_ACP,                 // CodePage
  466.                                 0,                // dwFlags
  467.                                 str.pOleStr,            // lpWideCharStr
  468.                                 -1,                     // cchWideChar
  469.                                 lpFriendlyName,         // lpMultiByteStr
  470. MAX_PATH,
  471.                                 //sizeof(lpFriendlyName), // cchMultiByte, wrong. sizeof on a pointer, psk, psk
  472.                                 NULL,                   // lpDefaultChar,
  473.                                 NULL);                  // lpUsedDefaultChar
  474.              break;
  475.          case STRRET_OFFSET:
  476.              lstrcpy(lpFriendlyName, (LPSTR)lpi+str.uOffset);
  477.              break;
  478.          case STRRET_CSTR:
  479.              
  480.              lstrcpy(lpFriendlyName, (LPSTR)str.cStr);
  481.              break;
  482.          default:
  483.              bSuccess = FALSE;
  484.              break;
  485.       }
  486.    }
  487.    else
  488.       bSuccess = FALSE;
  489.    return bSuccess;
  490. }
  491. /****************************************************************************
  492. *
  493. *    FUNCTION: GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
  494. *
  495. *    PURPOSE:  Gets the Fully qualified Pidls for the folder 
  496. *
  497. ****************************************************************************/
  498. LPITEMIDLIST CShellTree::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
  499. {
  500.    char szBuff[MAX_PATH];
  501.    OLECHAR szOleChar[MAX_PATH];
  502.    LPSHELLFOLDER lpsfDeskTop;
  503.    LPITEMIDLIST  lpifq;
  504.    ULONG ulEaten, ulAttribs;
  505.    HRESULT hr;
  506.    if (!GetName(lpsf, lpi, SHGDN_FORPARSING, szBuff))
  507.       return NULL;
  508.    hr=SHGetDesktopFolder(&lpsfDeskTop);
  509.    if (FAILED(hr))
  510.       return NULL;
  511.    MultiByteToWideChar(CP_ACP,
  512.    MB_PRECOMPOSED,
  513.    szBuff,
  514.    -1,
  515.    (USHORT *)szOleChar,
  516.    sizeof(szOleChar));
  517.    hr=lpsfDeskTop->ParseDisplayName(NULL,
  518. NULL,
  519. szOleChar,
  520. &ulEaten,
  521. &lpifq,
  522. &ulAttribs);
  523.    lpsfDeskTop->Release();
  524.    if (FAILED(hr))
  525.       return NULL;
  526.    return lpifq;
  527. }
  528. /////////////////////////////////////////////////////////////////////////////
  529. // CShellTree message handlers
  530. /****************************************************************************
  531. *
  532. * FUNCTION: OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) 
  533. *
  534. * PURPOSE: Reponds to an TVN_ITEMEXPANDING message in order to fill up
  535. * subdirectories. Pass the parameters from OnItemExpanding() to 
  536. * this function. You need to do that or your folders won't
  537. * expand.
  538. *
  539. * OTHER: It can also be used to update a corresponding listview. Seem MFCENUM
  540. *
  541. * MESSAGEMAP: TVN_ITEMEXPANDING
  542. *
  543. ****************************************************************************/
  544. void CShellTree::FolderExpanding(NMHDR* pNMHDR, LRESULT* pResult) 
  545. {
  546. LPTVITEMDATA   lptvid;  //Long pointer to TreeView item data
  547. HRESULT        hr;
  548. LPSHELLFOLDER  lpsf2=NULL;
  549. static char    szBuff[MAX_PATH];
  550. TV_SORTCB      tvscb;
  551. NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
  552. // TODO: Add your control notification handler code here
  553.     if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
  554.          return;
  555.     lptvid=(LPTVITEMDATA)pnmtv->itemNew.lParam;
  556.     if (lptvid)
  557.        {
  558.             hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
  559.                 0, IID_IShellFolder,(LPVOID *)&lpsf2);
  560.             if (SUCCEEDED(hr))
  561.             {
  562.                 FillTreeView(lpsf2,
  563.                        lptvid->lpifq,
  564.                        pnmtv->itemNew.hItem);
  565.             }
  566.             tvscb.hParent     = pnmtv->itemNew.hItem;
  567.             tvscb.lParam      = 0;
  568.             tvscb.lpfnCompare = TreeViewCompareProc;
  569.             SortChildrenCB(&tvscb /*, FALSE*/);
  570.     }
  571. *pResult = 0;
  572. }
  573. /****************************************************************************
  574. *
  575. * FUNCTION: FolderPopup(NMHDR* pNMHDR, LRESULT* pResult) 
  576. *
  577. * PURPOSE: Diplays a popup menu for the folder selected. Pass the
  578. * parameters from Rclick() to this function.
  579. *
  580. * MESSAGEMAP: NM_RCLICK;
  581. *
  582. ****************************************************************************/
  583. void CShellTree::FolderPopup(NMHDR* pNMHDR, LRESULT* pResult) 
  584. {
  585. // TODO: Add your control notification handler code here
  586. POINT pt;
  587. LPTVITEMDATA lptvid;  //Long pointer to TreeView item data
  588. LPSHELLFOLDER lpsf2=NULL;
  589. static char szBuff[MAX_PATH];
  590. TV_HITTESTINFO tvhti;
  591. TV_ITEM tvi;
  592. // TODO: Add your control notification handler code here
  593. ::GetCursorPos((LPPOINT)&pt);
  594. ScreenToClient(&pt);
  595. tvhti.pt=pt;
  596.     HitTest(&tvhti);
  597.     SelectItem(tvhti.hItem);
  598. if (tvhti.flags & (TVHT_ONITEMLABEL|TVHT_ONITEMICON))
  599. {
  600. ClientToScreen(&pt);
  601. tvi.mask=TVIF_PARAM;
  602. tvi.hItem=tvhti.hItem;
  603.         if (!GetItem(&tvi)){
  604. return;
  605. }
  606. lptvid=(LPTVITEMDATA)tvi.lParam;
  607. DoTheMenuThing(::GetParent(m_hWnd),
  608. lptvid->lpsfParent, lptvid->lpi, &pt);
  609. }
  610. *pResult = 0;
  611. }
  612. /****************************************************************************
  613. *
  614. * FUNCTION: FolderSelected(NMHDR* pNMHDR, LRESULT* pResult, CString &szFolderPath) 
  615. *
  616. * PURPOSE: Call this function if for example you want to put the path of the folder
  617. * selected inside a combobox or an edit window. You would pass the
  618. * parameters from OnSelChanged() to this function along with a CString object
  619. * that will hold the folder path. If the path is not
  620. * in the filesystem(eg MyComputer) it returns false.
  621. *
  622. * MESSAGEMAP: TVN_SELCHANGED
  623. *
  624. ****************************************************************************/
  625. BOOL CShellTree::FolderSelected(NMHDR* pNMHDR, LRESULT* pResult, CString &szFolderPath) 
  626. {
  627. // TODO: Add your control notification handler code here
  628. POINT pt;
  629. LPTVITEMDATA lptvid;  //Long pointer to TreeView item data
  630. LPSHELLFOLDER lpsf2=NULL;
  631. static char szBuff[MAX_PATH];
  632. TV_HITTESTINFO tvhti;
  633. TV_ITEM tvi;
  634. HRESULT hr;
  635. BOOL bRet=false;
  636. // TODO: Add your control notification handler code here
  637. ::GetCursorPos((LPPOINT)&pt);
  638. ScreenToClient(&pt);
  639. tvhti.pt=pt;
  640.     HitTest(&tvhti);
  641.     SelectItem(tvhti.hItem);
  642. if (tvhti.flags & (TVHT_ONITEMLABEL|TVHT_ONITEMICON))
  643. {
  644. ClientToScreen(&pt);
  645. tvi.mask=TVIF_PARAM;
  646. tvi.hItem=tvhti.hItem;
  647.         if (!GetItem(&tvi))
  648. return false;
  649. lptvid=(LPTVITEMDATA)tvi.lParam;
  650. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  651. {
  652. hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
  653.  0,IID_IShellFolder,(LPVOID *)&lpsf2);
  654. if (SUCCEEDED(hr))
  655. {
  656. ULONG ulAttrs = SFGAO_FILESYSTEM;
  657. // Determine what type of object we have.
  658. lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  659. if (ulAttrs & (SFGAO_FILESYSTEM))
  660. {
  661. if(SHGetPathFromIDList(lptvid->lpifq,szBuff)){
  662. szFolderPath = szBuff;
  663. bRet = true;
  664. }
  665. }
  666. }
  667. }
  668. if(lpsf2)
  669. lpsf2->Release();
  670. }
  671. *pResult = 0;
  672. return bRet;
  673. }
  674. /****************************************************************************
  675. *
  676. * FUNCTION: EnableImages()
  677. *
  678. * PURPOSE: Obtains a handle to the system image list and attaches it
  679. * to the tree control. DO NOT DELETE the imagelist
  680. *
  681. * MESSAGEMAP: NONE
  682. *
  683. ****************************************************************************/
  684. void CShellTree::EnableImages()
  685. {
  686. // Get the handle to the system image list, for our icons
  687.     HIMAGELIST  hImageList;
  688.     SHFILEINFO    sfi;
  689.     hImageList = (HIMAGELIST)SHGetFileInfo((LPCSTR)"C:\", 
  690.                                            0,
  691.                                            &sfi, 
  692.                                            sizeof(SHFILEINFO), 
  693.                                            SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  694.     // Attach ImageList to TreeView
  695.     if (hImageList)
  696.         ::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL,
  697.             (LPARAM)hImageList);
  698. }
  699. /****************************************************************************
  700. *
  701. * FUNCTION: GetSelectedFolderPath(CString &szFolderPath)
  702. *
  703. * PURPOSE: Retrieves the path of the currently selected string.
  704. * Pass a CString object that will hold the folder path. 
  705. * If the path is not in the filesystem(eg MyComputer) 
  706. * or none is selected it returns false.
  707. *
  708. * MESSAGEMAP: NONE
  709. *
  710. ****************************************************************************/
  711. BOOL CShellTree::GetSelectedFolderPath(CString &szFolderPath)
  712. {
  713. LPTVITEMDATA lptvid;  //Long pointer to TreeView item data
  714. LPSHELLFOLDER lpsf2=NULL;
  715. static char szBuff[MAX_PATH];
  716. HTREEITEM hItem;
  717. HRESULT hr;
  718. BOOL bRet=false;
  719. if((hItem = GetSelectedItem()))
  720. {
  721. lptvid=(LPTVITEMDATA)GetItemData(hItem);
  722. if (lptvid && lptvid->lpsfParent && lptvid->lpi)
  723. {
  724. hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
  725.  0,IID_IShellFolder,(LPVOID *)&lpsf2);
  726. if (SUCCEEDED(hr))
  727. {
  728. ULONG ulAttrs = SFGAO_FILESYSTEM;
  729. // Determine what type of object we have.
  730. lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
  731. if (ulAttrs & (SFGAO_FILESYSTEM))
  732. {
  733. if(SHGetPathFromIDList(lptvid->lpifq,szBuff)){
  734. szFolderPath = szBuff;
  735. bRet = true;
  736. }
  737. }
  738. }
  739. }
  740. if(lpsf2)
  741. lpsf2->Release();
  742. }
  743. return bRet;
  744. }