Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

877 lines
26 KiB

  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 messed 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. }