browse.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 26k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //###########################################################################
  2. // Code for the Browse For Starting Folder
  3. //###########################################################################
  4. // Structure to pass information to browse for folder dialog
  5. typedef struct _bfsf
  6. {
  7.     HWND        hwndOwner;
  8.     LPCITEMIDLIST pidlRoot;      // Root of search.  Typically desktop or my net
  9.     LPSTR        pszDisplayName;// Return display name of item selected.
  10.     int          *piImage;      // where to return the Image index.
  11.     LPCSTR      lpszTitle;      // resource (or text to go in the banner over the tree.
  12.     UINT         ulFlags;       // Flags that control the return stuff
  13.     BFFCALLBACK  lpfn;
  14.     LPARAM      lParam;
  15.     HWND         hwndDlg;       // The window handle to the dialog
  16.     HWND         hwndTree;      // The tree control.
  17.     HTREEITEM    htiCurParent;  // tree item associated with Current shell folder
  18.     IShellFolder * psfParent;    // Cache of the last IShell folder I needed...
  19.     LPITEMIDLIST pidlCurrent;   // IDlist of current folder to select
  20.     BOOL         fShowAllObjects; // Should we Show all ?
  21. } BFSF, *PBFSF;
  22. BOOL CALLBACK _BFSFDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  23. LPITEMIDLIST _BFSFUpdateISHCache(PBFSF pbfsf, HTREEITEM hti, LPITEMIDLIST pidlItem);
  24. // _BrowseForStartingFolder - Browse for a folder to start the
  25. //         search from.
  26. // BUGBUG, give them a way to turn off the ok button.
  27. LPITEMIDLIST WINAPI SHBrowseForFolder(LPBROWSEINFO lpbi)
  28. {
  29.     LPITEMIDLIST lpRet;
  30.     BFSF bfsf =
  31.         {
  32.           lpbi->hwndOwner,
  33.           lpbi->pidlRoot,
  34.           lpbi->pszDisplayName,
  35.           &lpbi->iImage,
  36.           lpbi->lpszTitle,
  37.           lpbi->ulFlags,
  38.           lpbi->lpfn,
  39.           lpbi->lParam,
  40.         };
  41.     HCURSOR hcOld = SetCursor(LoadCursor(NULL,IDC_WAIT));
  42.     SHELLSTATE ss;
  43.     SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
  44.     bfsf.fShowAllObjects = ss.fShowAllObjects;
  45.     // Now Create the dialog that will be doing the browsing.
  46.     if (DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_BROWSEFORFOLDER),
  47.                        lpbi->hwndOwner, _BFSFDlgProc, (LPARAM)&bfsf))
  48.         lpRet = bfsf.pidlCurrent;
  49.     else
  50.         lpRet = NULL;
  51.     if (hcOld)
  52.         SetCursor(hcOld);
  53.     return lpRet;
  54. }
  55. void BFSFCallback(PBFSF pbfsf, UINT uMsg, LPARAM lParam)
  56. {
  57.     if (pbfsf->lpfn) {
  58.         pbfsf->lpfn(pbfsf->hwndDlg, uMsg, lParam, pbfsf->lParam);
  59.     }
  60. }
  61. // Some helper functions for processing the dialog
  62. HTREEITEM _AddItemToTree(HWND hwndTree, HTREEITEM htiParent, LPITEMIDLIST pidl, int cChildren)
  63. {
  64.     TV_INSERTSTRUCT tii;
  65.     // Initialize item to add with callback for everything
  66.     tii.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE |
  67.             TVIF_PARAM | TVIF_CHILDREN;
  68.     tii.hParent = htiParent;
  69.     tii.hInsertAfter = TVI_FIRST;
  70.     tii.item.iImage = I_IMAGECALLBACK;
  71.     tii.item.iSelectedImage = I_IMAGECALLBACK;
  72.     tii.item.pszText = LPSTR_TEXTCALLBACK;   //
  73.     tii.item.cChildren = cChildren; //  Assume it has children
  74.     tii.item.lParam = (LPARAM)pidl;
  75.     return TreeView_InsertItem(hwndTree, &tii);
  76. }
  77. LPITEMIDLIST _GetIDListFromTreeItem(HWND hwndTree, HTREEITEM hti)
  78. {
  79.     LPITEMIDLIST pidl;
  80.     LPITEMIDLIST pidlT;
  81.     TV_ITEM tvi;
  82.     // If no hti passed in, get the selected on.
  83.     if (hti == NULL)
  84.     {
  85.         hti = TreeView_GetSelection(hwndTree);
  86.         if (hti == NULL)
  87.             return(NULL);
  88.     }
  89.     // now lets get the information about the item
  90.     tvi.mask = TVIF_PARAM | TVIF_HANDLE;
  91.     tvi.hItem = hti;
  92.     if (!TreeView_GetItem(hwndTree, &tvi))
  93.         return NULL;   // Failed again
  94.     pidl = ILClone((LPITEMIDLIST)tvi.lParam);
  95.     // Now walk up parents.
  96.     while ((tvi.hItem = TreeView_GetParent(hwndTree, tvi.hItem)) && pidl)
  97.     {
  98.         if (!TreeView_GetItem(hwndTree, &tvi))
  99.             return(pidl);   // will assume I screwed up...
  100.         pidlT = ILCombine((LPITEMIDLIST)tvi.lParam, pidl);
  101.         ILFree(pidl);
  102.         pidl = pidlT;
  103.     }
  104.     return(pidl);
  105. }
  106. int CALLBACK _BFSFTreeCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  107. {
  108.     IShellFolder *psfParent = (IShellFolder *)lParamSort;
  109.     HRESULT hres = psfParent->lpVtbl->CompareIDs(psfParent, 0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2);
  110.     Assert(SUCCEEDED(hres));
  111.     return (short)SCODE_CODE(GetScode(hres));
  112. }
  113. void _BFSFSort(PBFSF pbfsf, HTREEITEM hti, IShellFolder * psf)
  114. {
  115.     TV_SORTCB sSortCB;
  116.     sSortCB.hParent = hti;
  117.     sSortCB.lpfnCompare = _BFSFTreeCompare;
  118.     psf->lpVtbl->AddRef(psf);
  119.     sSortCB.lParam = (LPARAM)psf;
  120.     TreeView_SortChildrenCB(pbfsf->hwndTree, &sSortCB, FALSE);
  121.     psf->lpVtbl->Release(psf);
  122. }
  123. BOOL _BFSFHandleItemExpanding(PBFSF pbfsf, LPNM_TREEVIEW pnmtv)
  124. {
  125.     LPITEMIDLIST pidlToExpand;
  126.     LPITEMIDLIST pidl;
  127.     IShellFolder * psf;
  128.     IShellFolder * psfDesktop = Desktop_GetShellFolder(TRUE);
  129.     BYTE bType;
  130.     DWORD grfFlags;
  131.     BOOL fPrinterTest = FALSE;
  132.     int cAdded = 0;
  133.     TV_ITEM tvi;
  134.     IEnumIDList *   penum;              // Enumerator in use.
  135.     if (pnmtv->action != TVE_EXPAND)
  136.         return FALSE;
  137.     if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
  138.         return FALSE;
  139.     // set this bit now because we might be reentered via the wnet apis
  140.     tvi.mask = TVIF_STATE;
  141.     tvi.hItem = pnmtv->itemNew.hItem;
  142.     tvi.state = TVIS_EXPANDEDONCE;
  143.     tvi.stateMask = TVIS_EXPANDEDONCE;
  144.     TreeView_SetItem(pbfsf->hwndTree, &tvi);
  145.     if (pnmtv->itemNew.hItem == NULL)
  146.     {
  147.         pnmtv->itemNew.hItem = TreeView_GetSelection(pbfsf->hwndTree);
  148.         if (pnmtv->itemNew.hItem == NULL)
  149.             return FALSE;
  150.     }
  151.     pidlToExpand = _GetIDListFromTreeItem(pbfsf->hwndTree, pnmtv->itemNew.hItem);
  152.     if (pidlToExpand == NULL)
  153.         return FALSE;
  154.     // Now lets get the IShellFolder and iterator for this object
  155.     // special case to handle if the Pidl is the desktop
  156.     // This is rather gross, but the desktop appears to be simply a pidl
  157.     // of length 0 and ILIsEqual will not work...
  158.     if (pidlToExpand->mkid.cb == 0)
  159.     {
  160.         psf = psfDesktop;
  161.         psfDesktop->lpVtbl->AddRef(psf);
  162.     }
  163.     else
  164.     {
  165.         if (FAILED(psfDesktop->lpVtbl->BindToObject(psfDesktop,
  166.                 pidlToExpand, NULL, &IID_IShellFolder, &psf)))
  167.         {
  168.             ILFree(pidlToExpand);
  169.             return FALSE; // Could not get IShellFolder.
  170.         }
  171.     }
  172.     // Need to do a couple of special cases here to allow us to
  173.     // browse for a network printer.  In this case if we are at server
  174.     // level we then need to change what we search for non folders when
  175.     // we are the level of a server.
  176.     if (pbfsf->ulFlags & BIF_BROWSEFORPRINTER)
  177.     {
  178.         grfFlags = SHCONTF_FOLDERS | SHCONTF_NETPRINTERSRCH;
  179.         pidl = ILFindLastID(pidlToExpand);
  180.         bType = SIL_GetType(pidl);
  181.         fPrinterTest = ((bType & (SHID_NET|SHID_INGROUPMASK))==SHID_NET_SERVER);
  182.         if (fPrinterTest)
  183.             grfFlags |= SHCONTF_NONFOLDERS;
  184.     }
  185.     else
  186.         grfFlags = SHCONTF_FOLDERS;
  187.     if (pbfsf->fShowAllObjects)
  188.         grfFlags |= SHCONTF_INCLUDEHIDDEN;
  189.     if (FAILED(psf->lpVtbl->EnumObjects(psf, pbfsf->hwndDlg, grfFlags, &penum)))
  190.     {
  191.         psf->lpVtbl->Release(psf);
  192.         ILFree(pidlToExpand);
  193.         return FALSE;
  194.     }
  195.     // psf->lpVtbl->AddRef(psf);
  196.     while (pidl = _NextIDL(psf, penum))
  197.     {
  198.         int cChildren = I_CHILDRENCALLBACK;  // Do call back for children
  199.         //
  200.         // We need to special case here in the netcase where we onlyu
  201.         // browse down to workgroups...
  202.         //
  203.         //
  204.         // Here is where I also need to special case to not go below
  205.         // workgroups when the appropriate option is set.
  206.         //
  207.         bType = SIL_GetType(pidl);
  208.         if ((pbfsf->ulFlags & BIF_DONTGOBELOWDOMAIN) && (bType & SHID_NET))
  209.         {
  210.             switch (bType & (SHID_NET | SHID_INGROUPMASK))
  211.             {
  212.             case SHID_NET_SERVER:
  213.                 ILFree(pidl);       // Dont want to add this one
  214.                 continue;           // Try the next one
  215.             case SHID_NET_DOMAIN:
  216.                 cChildren = 0;      // Force to not have children;
  217.             }
  218.         }
  219.         else if ((pbfsf->ulFlags & BIF_BROWSEFORCOMPUTER) && (bType & SHID_NET))
  220.         {
  221.             if ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SERVER)
  222.                 cChildren = 0;  // Don't expand below it...
  223.         }
  224.         else if (fPrinterTest)
  225.         {
  226.             // Special case when we are only allowing printers.
  227.             // for now I will simply key on the fact that it is non-FS.
  228.             ULONG ulAttr = SFGAO_FILESYSTEM;
  229.             psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &ulAttr);
  230.             if ((ulAttr & SFGAO_FILESYSTEM)== 0)
  231.             {
  232.                 cChildren = 0;      // Force to not have children;
  233.             }
  234.             else
  235.             {
  236.                 ILFree(pidl);       // Dont want to add this one
  237.                 continue;           // Try the next one
  238.             }
  239.         }
  240.         _AddItemToTree(pbfsf->hwndTree, pnmtv->itemNew.hItem,
  241.                 pidl, cChildren);
  242.         cAdded++;
  243.     }
  244.     // Now Cleanup after ourself
  245.     penum->lpVtbl->Release(penum);
  246.     _BFSFSort(pbfsf, pnmtv->itemNew.hItem, psf);
  247.     psf->lpVtbl->Release(psf);
  248.     ILFree(pidlToExpand);
  249.     // If we did not add anything we should update this item to let
  250.     // the user know something happened.
  251.     //
  252.     if (cAdded == 0)
  253.     {
  254.         TV_ITEM tvi;
  255.         tvi.mask = TVIF_CHILDREN | TVIF_HANDLE;   // only change the number of children
  256.         tvi.hItem = pnmtv->itemNew.hItem;
  257.         tvi.cChildren = 0;
  258.         TreeView_SetItem(pbfsf->hwndTree, &tvi);
  259.     }
  260.     return TRUE;
  261. }
  262. void _BFSFHandleDeleteItem(PBFSF pbfsf, LPNM_TREEVIEW pnmtv)
  263. {
  264.     // We need to free the IDLists that we allocated previously
  265.     if (pnmtv->itemOld.lParam != 0)
  266.         ILFree((LPITEMIDLIST)pnmtv->itemOld.lParam);
  267. }
  268. LPITEMIDLIST _BFSFUpdateISHCache(PBFSF pbfsf, HTREEITEM hti,
  269.         LPITEMIDLIST pidlItem)
  270. {
  271.     HTREEITEM htiParent;
  272.     IShellFolder * psfDesktop = Desktop_GetShellFolder(TRUE);
  273.     if (pidlItem == NULL)
  274.         return(NULL);
  275.     // Need to handle the root case here!
  276.     htiParent = TreeView_GetParent(pbfsf->hwndTree, hti);
  277.     if ((htiParent != pbfsf->htiCurParent) || (pbfsf->psfParent == NULL))
  278.     {
  279.         LPITEMIDLIST pidl;
  280.         if (pbfsf->psfParent)
  281.         {
  282.             if (pbfsf->psfParent != psfDesktop)
  283.                 pbfsf->psfParent->lpVtbl->Release(pbfsf->psfParent);
  284.             pbfsf->psfParent = NULL;
  285.         }
  286.         if (htiParent)
  287.         {
  288.             pidl = _GetIDListFromTreeItem(pbfsf->hwndTree, htiParent);
  289.         }
  290.         else
  291.         {
  292.             //
  293.             // If No Parent then the item here is one of our roots which
  294.             // should be fully qualified.  So try to get the parent by
  295.             // decomposing the ID.
  296.             //
  297.             LPITEMIDLIST pidlT = (LPITEMIDLIST)ILFindLastID(pidlItem);
  298.             if (pidlT != pidlItem)
  299.             {
  300.                 pidl = ILClone(pidlItem);
  301.                 ILRemoveLastID(pidl);
  302.                 pidlItem = pidlT;
  303.             }
  304.             else
  305.                 pidl = NULL;
  306.         }
  307.         pbfsf->htiCurParent = htiParent;
  308.         // If still NULL then we use root of evil...
  309.         if (pidl == NULL || (pidl->mkid.cb == 0))
  310.         {
  311.             // Still one m
  312.             pbfsf->psfParent = psfDesktop;
  313.             if (pidl)
  314.                 ILFree(pidl);
  315.         }
  316.         else
  317.         {
  318.             psfDesktop->lpVtbl->BindToObject(psfDesktop,
  319.                      pidl, NULL, &IID_IShellFolder, &pbfsf->psfParent);
  320.             ILFree(pidl);
  321.             if (pbfsf->psfParent == NULL)
  322.                 return NULL;
  323.         }
  324.     }
  325.     return(ILFindLastID(pidlItem));
  326. }
  327. void _BFSFGetDisplayInfo(PBFSF pbfsf, TV_DISPINFO *pnm)
  328. {
  329.     TV_ITEM ti;
  330.     LPITEMIDLIST pidlItem = (LPITEMIDLIST)pnm->item.lParam;
  331.     if ((pnm->item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN)) == 0)
  332.         return; // nothing for us to do here.
  333.     pidlItem = _BFSFUpdateISHCache(pbfsf, pnm->item.hItem, pidlItem);
  334.     ti.mask = 0;
  335.     ti.hItem = (HTREEITEM)pnm->item.hItem;
  336.     // They are asking for IconIndex.  See if we can find it now.
  337.     // Once found update their list, such that they wont call us back for
  338.     // it again.
  339.     if (pnm->item.mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE))
  340.     {
  341.         // We now need to map the item into the right image index.
  342.         ti.iImage = pnm->item.iImage = SHMapPIDLToSystemImageListIndex(
  343.                 pbfsf->psfParent, pidlItem, &ti.iSelectedImage);
  344.         // we should save it back away to
  345.         pnm->item.iSelectedImage = ti.iSelectedImage;
  346.         ti.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  347.     }
  348.     // Also see if this guy has any child folders
  349.     if (pnm->item.mask & TVIF_CHILDREN)
  350.     {
  351.         ULONG ulAttrs;
  352.         ulAttrs = SFGAO_HASSUBFOLDER;
  353.         pbfsf->psfParent->lpVtbl->GetAttributesOf(pbfsf->psfParent,
  354.                 1, &pidlItem, &ulAttrs);
  355.         ti.cChildren = pnm->item.cChildren =
  356.                 (ulAttrs & SFGAO_HASSUBFOLDER)? 1 : 0;
  357.         ti.mask |= TVIF_CHILDREN;
  358.     }
  359.     if (pnm->item.mask & TVIF_TEXT)
  360.     {
  361.         STRRET str;
  362.         pbfsf->psfParent->lpVtbl->GetDisplayNameOf(pbfsf->psfParent,
  363.                 pidlItem, SHGDN_INFOLDER, &str);
  364.         StrRetToStrN(pnm->item.pszText, pnm->item.cchTextMax, &str, pidlItem);
  365.         ti.mask |= TVIF_TEXT;
  366.         ti.pszText = pnm->item.pszText;
  367.     }
  368.     // Update the item now
  369.     TreeView_SetItem(pbfsf->hwndTree, &ti);
  370. }
  371. void _BFSFHandleSelChanged(PBFSF pbfsf, LPNM_TREEVIEW pnmtv)
  372. {
  373.     LPITEMIDLIST pidl;
  374.     ULONG ulAttrs = SFGAO_FILESYSTEM;
  375.     BYTE bType;
  376.     // We only need to do anything if we only want to return File system
  377.     // level objects.
  378.     if ((pbfsf->ulFlags & (BIF_RETURNONLYFSDIRS|BIF_RETURNFSANCESTORS|BIF_BROWSEFORPRINTER|BIF_BROWSEFORCOMPUTER)) == 0)
  379.         goto NotifySelChange;
  380.     // We need to get the attributes of this object...
  381.     pidl = _BFSFUpdateISHCache(pbfsf, pnmtv->itemNew.hItem,
  382.             (LPITEMIDLIST)pnmtv->itemNew.lParam);
  383.     if (pidl)
  384.     {
  385.         BOOL fEnable;
  386.         bType = SIL_GetType(pidl);
  387.         if ((pbfsf->ulFlags & (BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS)) != 0)
  388.         {
  389.             int i;
  390.             // if this is the root pidl, then do a get attribs on 0
  391.             // so that we'll get the attributes on the root, rather than
  392.             // random returned values returned by FSFolder
  393.             if (ILIsEmpty(pidl)) {
  394.                 i = 0;
  395.             } else
  396.                 i = 1;
  397.             pbfsf->psfParent->lpVtbl->GetAttributesOf(pbfsf->psfParent,
  398.                                                       i, &pidl, &ulAttrs);
  399.             fEnable = (((ulAttrs & SFGAO_FILESYSTEM) && (pbfsf->ulFlags & BIF_RETURNONLYFSDIRS)) ||
  400.                 ((ulAttrs & SFGAO_FILESYSANCESTOR) && (pbfsf->ulFlags & BIF_RETURNFSANCESTORS))) ||
  401.                     ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SERVER);
  402.         }
  403.         else if ((pbfsf->ulFlags & BIF_BROWSEFORCOMPUTER) != 0)
  404.             fEnable = ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SERVER);
  405.         else if ((pbfsf->ulFlags & BIF_BROWSEFORPRINTER) != 0)
  406.         {
  407.             // Printers are of type Share and usage Print...
  408.             fEnable = ((bType & (SHID_NET | SHID_INGROUPMASK)) == SHID_NET_SHARE);
  409.         }
  410.         EnableWindow(GetDlgItem(pbfsf->hwndDlg, IDOK),fEnable);
  411.     }
  412. NotifySelChange:
  413.     if (pbfsf->lpfn) {
  414.         pidl = _GetIDListFromTreeItem(pbfsf->hwndTree, pnmtv->itemNew.hItem);
  415.         BFSFCallback(pbfsf, BFFM_SELCHANGED, (LPARAM)pidl);
  416.         ILFree(pidl);
  417.     }
  418. }
  419. BOOL BrowseSelectPidl(PBFSF pbfsf, LPCITEMIDLIST pidl)
  420. {
  421.     HTREEITEM htiParent;
  422.     LPITEMIDLIST pidlTemp;
  423.     LPITEMIDLIST pidlNext = NULL;
  424.     LPITEMIDLIST pidlParent = NULL;
  425.     BOOL fRet = FALSE;
  426.     htiParent = TreeView_GetChild(pbfsf->hwndTree, NULL);
  427.     if (htiParent) {
  428.         // step through each item of the pidl
  429.         for (;;) {
  430.             TreeView_Expand(pbfsf->hwndTree, htiParent, TVE_EXPAND);
  431.             pidlParent = _GetIDListFromTreeItem(pbfsf->hwndTree, htiParent);
  432.             if (!pidlParent)
  433.                 break;
  434.             pidlNext = ILClone(pidl);
  435.             if (!pidlNext)
  436.                 break;
  437.             pidlTemp = ILFindChild(pidlParent, pidlNext);
  438.             if (!pidlTemp)
  439.                 break;
  440.             if (ILIsEmpty(pidlTemp)) {
  441.                 // found it!
  442.                 //
  443.                 TreeView_SelectItem(pbfsf->hwndTree, htiParent);
  444.                 fRet = TRUE;
  445.                 break;
  446.             } else {
  447.                 // loop to find the next item
  448.                 HTREEITEM htiChild;
  449.                 pidlTemp = ILGetNext(pidlTemp);
  450.                 if (!pidlTemp)
  451.                     break;
  452.                 else
  453.                     pidlTemp->mkid.cb = 0;
  454.                 htiChild = TreeView_GetChild(pbfsf->hwndTree, htiParent);
  455.                 while (htiChild) {
  456.                     BOOL fEqual;
  457.                     pidlTemp = _GetIDListFromTreeItem(pbfsf->hwndTree, htiChild);
  458.                     if (!pidlTemp) {
  459.                         htiChild = NULL;
  460.                         break;
  461.                     }
  462.                     fEqual = ILIsEqual(pidlTemp, pidlNext);
  463.                     ILFree(pidlTemp);
  464.                     if (fEqual) {
  465.                         break;
  466.                     } else {
  467.                         htiChild = TreeView_GetNextSibling(pbfsf->hwndTree, htiChild);
  468.                     }
  469.                 }
  470.                 if (!htiChild) {
  471.                     // we didn't find the next one... bail
  472.                     break;
  473.                 } else {
  474.                     // the found child becomes the next parent
  475.                     htiParent = htiChild;
  476.                     ILFree(pidlParent);
  477.                     ILFree(pidlNext);
  478.                 }
  479.             }
  480.         }
  481.     }
  482.     if (pidlParent) ILFree(pidlParent);
  483.     if (pidlNext) ILFree(pidlNext);
  484.     return fRet;
  485. }
  486. // _BFSFOnInitDlg - Process the init dialog
  487. BOOL _BFSFOnInitDlg(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  488. {
  489.     HTREEITEM hti;
  490.     PBFSF pbfsf = (PBFSF)lParam;
  491.     HIMAGELIST himl;
  492.     LPSTR lpsz;
  493.     char szTitle[80];    // no title should be bigger than this!
  494.     HWND hwndTree;
  495.     lpsz = ResourceCStrToStr(HINST_THISDLL, pbfsf->lpszTitle);
  496.     SetDlgItemText(hwnd, IDD_BROWSETITLE, lpsz);
  497.     if (lpsz != pbfsf->lpszTitle)
  498.     {
  499.         LocalFree(lpsz);
  500.         lpsz = NULL;
  501.     }
  502.     SetWindowLong(hwnd, DWL_USER, (LONG)lParam);
  503.     pbfsf->hwndDlg = hwnd;
  504.     hwndTree = pbfsf->hwndTree = GetDlgItem(hwnd, IDD_FOLDERLIST);
  505.     if (hwndTree)
  506.     {
  507.         UINT swpFlags = SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER
  508.                 | SWP_NOACTIVATE;
  509.         RECT rc;
  510.         POINT pt = {0,0};
  511.         if (!(pbfsf->ulFlags & BIF_STATUSTEXT)) {
  512.             HWND hwndStatus = GetDlgItem(hwnd, IDD_BROWSESTATUS);
  513.             // nuke the status window
  514.             ShowWindow(hwndStatus, SW_HIDE);
  515.             MapWindowPoints(hwndStatus, hwnd, &pt, 1);
  516.             GetClientRect(hwndTree, &rc);
  517.             MapWindowPoints(hwndTree, hwnd, (POINT*)&rc, 2);
  518.             rc.top = pt.y;
  519.             swpFlags =  SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
  520.         }
  521.         Shell_GetImageLists(NULL, &himl);
  522. TreeView_SetImageList(hwndTree, himl, TVSIL_NORMAL);
  523.         SetWindowLong(hwndTree, GWL_EXSTYLE,
  524.                 GetWindowLong(hwndTree, GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
  525.         // Now try to get this window to know to recalc
  526.         SetWindowPos(hwndTree, NULL, rc.left, rc.top,
  527.                      rc.right - rc.left, rc.bottom - rc.top, swpFlags);
  528.     }
  529.     // If they passed in a root, add it, else add the contents of the
  530.     // Root of evil... to the list as ROOT objects.
  531.     if (pbfsf->pidlRoot)
  532.     {
  533.         LPITEMIDLIST pidl;
  534.         if (!HIWORD(pbfsf->pidlRoot)) {
  535.             pidl = SHCloneSpecialIDList(NULL, (UINT)pbfsf->pidlRoot, TRUE);
  536.         } else {
  537.             pidl = ILClone(pbfsf->pidlRoot);
  538.         }
  539.         // Now lets insert the Root object
  540. hti = _AddItemToTree(hwndTree, TVI_ROOT, pidl, 1);
  541. // Still need to expand below this point. to the starting location
  542. // That was passed in. But for now expand the first level.
  543. TreeView_Expand(hwndTree, hti, TVE_EXPAND);
  544.     }
  545.     else
  546.     {
  547.         LPCITEMIDLIST pidlDrives = GetSpecialFolderIDList(NULL, CSIDL_DRIVES, FALSE);
  548. LPITEMIDLIST pidlDesktop = SHCloneSpecialIDList(NULL, CSIDL_DESKTOP, FALSE);
  549. HTREEITEM htiRoot = _AddItemToTree(hwndTree, TVI_ROOT, pidlDesktop, 1);
  550.         // Expand the first level under the desktop
  551.         TreeView_Expand(hwndTree, htiRoot, TVE_EXPAND);
  552.         // Lets Preexpand the Drives portion....
  553.         hti = TreeView_GetChild(hwndTree, htiRoot);
  554.         while (hti)
  555.         {
  556.             LPITEMIDLIST pidl = _GetIDListFromTreeItem(hwndTree, hti);
  557.             if (ILIsEqual(pidl, pidlDrives))
  558.             {
  559.                 TreeView_Expand(hwndTree, hti, TVE_EXPAND);
  560.                 TreeView_SelectItem(hwndTree, hti);
  561.                 ILFree(pidl);
  562.                 break;
  563.             }
  564.             ILFree(pidl);
  565.             hti = TreeView_GetNextSibling(hwndTree, hti);
  566.         }
  567.     }
  568.     // go to our internal selection changed code to do any window enabling needed
  569.     {
  570.         NM_TREEVIEW nmtv;
  571.         hti = TreeView_GetSelection(hwndTree);
  572.         if (hti) {
  573.             TV_ITEM ti;
  574.             ti.mask = TVIF_PARAM;
  575.             ti.hItem = hti;
  576.             TreeView_GetItem(hwndTree, &ti);
  577.             nmtv.itemNew.hItem = hti;
  578.             nmtv.itemNew.lParam = ti.lParam;
  579.             _BFSFHandleSelChanged(pbfsf, &nmtv);
  580.         }
  581.     }
  582.     if ((pbfsf->ulFlags & BIF_BROWSEFORCOMPUTER) != 0)
  583.     {
  584.         LoadString(HINST_THISDLL, IDS_FINDSEARCH_COMPUTER, szTitle, sizeof(szTitle));
  585.         SetWindowText(hwnd, szTitle);
  586.     }
  587.     else if ((pbfsf->ulFlags & BIF_BROWSEFORPRINTER) != 0)
  588.     {
  589.         LoadString(HINST_THISDLL, IDS_FINDSEARCH_PRINTER, szTitle, sizeof(szTitle));
  590.         SetWindowText(hwnd, szTitle);
  591.     }
  592.     BFSFCallback(pbfsf, BFFM_INITIALIZED, 0);
  593.     return TRUE;
  594. }
  595. void _BFSFSetStatusText(PBFSF pbfsf, LPCSTR lpszText)
  596. {
  597.     char szText[100];
  598.     if (!HIWORD(lpszText)) {
  599.         LoadString(HINST_THISDLL, LOWORD(lpszText), szText, sizeof(szText));
  600.         lpszText = szText;
  601.     }
  602.     SetDlgItemText(pbfsf->hwndDlg, IDD_BROWSESTATUS, lpszText);
  603. }
  604. // _BFSFOnCommand - Process the WM_COMMAND message
  605. void _BFSFOnCommand(PBFSF pbfsf, int id, HWND hwndCtl, UINT codeNotify)
  606. {
  607.     HTREEITEM hti;
  608.     switch (id)
  609.     {
  610.     case IDOK:
  611.         // We can now update the structure with the idlist of the item selected
  612.         hti = TreeView_GetSelection(pbfsf->hwndTree);
  613.         pbfsf->pidlCurrent = _GetIDListFromTreeItem(pbfsf->hwndTree,
  614.                 hti);
  615.         if (pbfsf->pszDisplayName || pbfsf->piImage)
  616.         {
  617.             TV_ITEM tvi;
  618.             tvi.mask = (pbfsf->pszDisplayName)? (TVIF_TEXT | TVIF_IMAGE) :
  619.                     TVIF_IMAGE;
  620.             tvi.hItem = hti;
  621.             tvi.pszText = pbfsf->pszDisplayName;
  622.             tvi.cchTextMax = MAX_PATH;
  623.             TreeView_GetItem(pbfsf->hwndTree, &tvi);
  624.             if (pbfsf->piImage)
  625.                 *pbfsf->piImage = tvi.iImage;
  626.         }
  627.         EndDialog(pbfsf->hwndDlg, 1);     // To return TRUE.
  628.         break;
  629.     case IDCANCEL:
  630.         EndDialog(pbfsf->hwndDlg, 0);     // to return FALSE from this.
  631.         break;
  632.     }
  633. }
  634. // _BSFSDlgProc - The dialog procedure for processing the browse
  635. //          for starting folder dialog.
  636. #pragma data_seg(".text", "CODE")
  637. const static DWORD aBrowseHelpIDs[] = {  // Context Help IDs
  638.     IDD_BROWSETITLE,  NO_HELP,
  639.     IDD_BROWSESTATUS, NO_HELP,
  640.     IDD_FOLDERLIST,   IDH_BROWSELIST,
  641.     0, 0
  642. };
  643. #pragma data_seg()
  644. BOOL CALLBACK _BFSFDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  645. {
  646.     PBFSF pbfsf = (PBFSF)GetWindowLong(hwndDlg, DWL_USER);
  647.     switch (msg) {
  648.     HANDLE_MSG(pbfsf, WM_COMMAND, _BFSFOnCommand);
  649.     HANDLE_MSG(hwndDlg, WM_INITDIALOG, _BFSFOnInitDlg);
  650.     case WM_DESTROY:
  651.         if (pbfsf->psfParent && (pbfsf->psfParent != Desktop_GetShellFolder(TRUE)))
  652.         {
  653.             pbfsf->psfParent->lpVtbl->Release(pbfsf->psfParent);
  654.             pbfsf->psfParent = NULL;
  655.         }
  656.         break;
  657.     case BFFM_SETSTATUSTEXT:
  658.         _BFSFSetStatusText(pbfsf, (LPCSTR)lParam);
  659.         break;
  660.     case BFFM_SETSELECTION:
  661.     {
  662.         BOOL fRet;
  663.         // wParam TRUE means path, not pidl
  664.         if (wParam) {
  665.             lParam = (LPARAM)SHSimpleIDListFromPath((LPSTR)lParam);
  666.             if (!lParam)
  667.                 return FALSE;
  668.         }
  669.         fRet = BrowseSelectPidl(pbfsf, (LPITEMIDLIST)lParam);
  670.         if (wParam)
  671.             ILFree((LPITEMIDLIST)lParam);
  672.         return fRet;
  673.     }
  674.     case BFFM_ENABLEOK:
  675.         EnableWindow(GetDlgItem(hwndDlg, IDOK), lParam);
  676.         break;
  677.     case WM_NOTIFY:
  678.         switch (((NMHDR *)lParam)->code)
  679.         {
  680.         case TVN_GETDISPINFO:
  681.             _BFSFGetDisplayInfo(pbfsf, (TV_DISPINFO *)lParam);
  682.             break;
  683.         case TVN_ITEMEXPANDING:
  684.             SetCursor(LoadCursor(NULL, IDC_WAIT));
  685.             _BFSFHandleItemExpanding(pbfsf, (LPNM_TREEVIEW)lParam);
  686.             break;
  687.         case TVN_ITEMEXPANDED:
  688.             SetCursor(LoadCursor(NULL, IDC_ARROW));
  689.             break;
  690.         case TVN_DELETEITEM:
  691.             _BFSFHandleDeleteItem(pbfsf, (LPNM_TREEVIEW)lParam);
  692.             break;
  693.         case TVN_SELCHANGED:
  694.             _BFSFHandleSelChanged(pbfsf, (LPNM_TREEVIEW)lParam);
  695.             break;
  696.         }
  697.         break;
  698.     case WM_HELP:
  699.         WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
  700.             HELP_WM_HELP, (DWORD)(LPSTR) aBrowseHelpIDs);
  701.         break;
  702.     case WM_CONTEXTMENU:
  703.         WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  704.             (DWORD)(LPVOID) aBrowseHelpIDs);
  705.         break;
  706.     default:
  707.         return FALSE;
  708.     }
  709.     return TRUE;
  710. }