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.

1052 lines
27 KiB

  1. //
  2. // Folder.C
  3. //
  4. // Copyright (C) Microsoft, 1994,1995 All Rights Reserved.
  5. //
  6. // History:
  7. // ral 6/23/94 - First pass
  8. // 3/20/95 [stevecat] - NT port & real clean up, unicode, etc.
  9. //
  10. //
  11. #include "priv.h"
  12. #include "appwiz.h"
  13. #include "help.h" // Help context IDs
  14. typedef struct _FILEITEMDATA {
  15. DWORD dwFlags;
  16. TCHAR szPath[1];
  17. } FILEITEMDATA, * LPFILEITEMDATA;
  18. #define FIDFLAG_CANADDNEW 0x00000001
  19. #define FIDFLAG_CANDEL 0x00000002
  20. #define FIDFLAG_ISFOLDER 0x00000004
  21. #define FIDFLAG_ISPROGS 0x00000008
  22. //
  23. //
  24. //
  25. int CALLBACK CompareFolderCB(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  26. {
  27. #define lpfid1 ((LPFILEITEMDATA)lParam1)
  28. #define lpfid2 ((LPFILEITEMDATA)lParam2)
  29. #define b1IsDir (lpfid1->dwFlags & FIDFLAG_ISFOLDER)
  30. #define b2IsDir (lpfid2->dwFlags & FIDFLAG_ISFOLDER)
  31. //
  32. // Programs folder always goes to top
  33. //
  34. if (lpfid1->dwFlags & FIDFLAG_ISPROGS)
  35. {
  36. return(-1);
  37. }
  38. if (lpfid2->dwFlags & FIDFLAG_ISPROGS)
  39. {
  40. return(1);
  41. }
  42. if (b1IsDir == b2IsDir)
  43. {
  44. return(lstrcmpi(lpfid1->szPath, lpfid2->szPath));
  45. }
  46. else
  47. {
  48. if (b1IsDir)
  49. {
  50. return(-1);
  51. }
  52. else
  53. {
  54. return(1);
  55. }
  56. }
  57. #undef b1IsDir
  58. #undef b2IsDir
  59. #undef lpfid1
  60. #undef lpfid2
  61. }
  62. //
  63. // Sorts the specified folder so that folders appear at the top and all
  64. // files appear in alphabetical order below.
  65. //
  66. void SortFolder(HWND hwndTree, HTREEITEM hParent)
  67. {
  68. TV_SORTCB sSortCB;
  69. sSortCB.hParent = hParent;
  70. sSortCB.lpfnCompare = CompareFolderCB;
  71. sSortCB.lParam = 0;
  72. TreeView_SortChildrenCB(hwndTree, &sSortCB, FALSE);
  73. }
  74. //
  75. // Adds a new folder for the specifed path and returns its HTREEITEM. If
  76. // it is unable to add the item then NULL is returned.
  77. // NOTE: If dwFileAttributes == AI_NOATTRIB (-1) then no attributes specified.
  78. // If pidl is NULL then no pidl specified.
  79. //
  80. HTREEITEM AddItem(HWND hwndTree, LPCTSTR pszPath,
  81. HTREEITEM hParent, LPITEMIDLIST pidl,
  82. DWORD dwFlags)
  83. {
  84. HTREEITEM newhti = NULL;
  85. LPFILEITEMDATA lpfid = (LPFILEITEMDATA)LocalAlloc(LMEM_FIXED,
  86. sizeof(FILEITEMDATA) + (lstrlen(pszPath) + 1)*sizeof(TCHAR));
  87. if (lpfid)
  88. {
  89. TV_INSERTSTRUCT tvis;
  90. lpfid->dwFlags = dwFlags;
  91. lstrcpy(lpfid->szPath, pszPath);
  92. tvis.item.pszText = LPSTR_TEXTCALLBACK;
  93. tvis.item.iImage = tvis.item.iSelectedImage = I_IMAGECALLBACK;
  94. tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  95. tvis.item.lParam = (LPARAM)lpfid;
  96. tvis.hParent = hParent;
  97. tvis.hInsertAfter = TVI_LAST;
  98. newhti = TreeView_InsertItem(hwndTree, &tvis);
  99. if (!newhti)
  100. LocalFree((LPVOID)lpfid);
  101. }
  102. return newhti;
  103. }
  104. //
  105. // Flags for FillFolder
  106. //
  107. #define FFF_AddFiles 1
  108. #define FFF_AddDirs 2
  109. //
  110. // Recursively add all folders below CurDir to the tree below hParent
  111. //
  112. BOOL IsFolderShortcut(LPCTSTR pszName)
  113. {
  114. SHFOLDERCUSTOMSETTINGS fcs = {0};
  115. CLSID clsid = {0};
  116. fcs.dwSize = sizeof(fcs);
  117. fcs.dwMask = FCSM_CLSID;
  118. fcs.pclsid = &clsid;
  119. if (SUCCEEDED(SHGetSetFolderCustomSettings(&fcs, pszName, FCS_READ)))
  120. {
  121. return IsEqualGUID(&clsid, &CLSID_FolderShortcut);
  122. }
  123. return FALSE;
  124. }
  125. void FillFolder(HWND hwndTree, LPTSTR lpszCurDir, LPTSTR lpszExclude,
  126. HTREEITEM hParent, DWORD dwFlags)
  127. {
  128. int iStrTerm = lstrlen(lpszCurDir);
  129. WIN32_FIND_DATA fd;
  130. HANDLE hfind;
  131. HTREEITEM hNewItem = NULL;
  132. #define bAddFiles (dwFlags & FFF_AddFiles)
  133. #define bAddDirs (dwFlags & FFF_AddDirs)
  134. lstrcat(lpszCurDir, TEXT("\\*.*"));
  135. hfind = FindFirstFile(lpszCurDir, &fd);
  136. if (hfind != INVALID_HANDLE_VALUE)
  137. {
  138. do
  139. {
  140. BOOL bIsDir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  141. if (((bAddFiles && !bIsDir) ||
  142. // skip "." and ".." and hidden files
  143. (bAddDirs && bIsDir && (fd.cFileName[0] != TEXT('.')))) &&
  144. !(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
  145. {
  146. lpszCurDir[iStrTerm] = TEXT('\\');
  147. lstrcpy(lpszCurDir + iStrTerm + 1, fd.cFileName);
  148. // let's fudge it -- if it's a folder shortcut, don't treat it
  149. // like a real folder, since we can't navigate into it anyway
  150. // and it's not worth the trouble to try.
  151. if (bIsDir && IsFolderShortcut(lpszCurDir))
  152. {
  153. bIsDir = FALSE;
  154. }
  155. //
  156. // Don't add this if it's supposed to be excluded
  157. //
  158. if (!lpszExclude || !bIsDir ||
  159. lstrcmpi(lpszExclude, lpszCurDir) != 0)
  160. {
  161. hNewItem = AddItem(hwndTree, lpszCurDir, hParent, NULL,
  162. FIDFLAG_CANADDNEW | FIDFLAG_CANDEL |
  163. (bIsDir ? FIDFLAG_ISFOLDER : 0));
  164. if (bIsDir)
  165. {
  166. FillFolder(hwndTree, lpszCurDir, NULL,
  167. hNewItem, dwFlags);
  168. }
  169. }
  170. }
  171. } while (FindNextFile(hfind, &fd));
  172. FindClose(hfind);
  173. }
  174. lpszCurDir[iStrTerm] = 0;
  175. //
  176. // Non-null if any items added to folder.
  177. //
  178. if (hNewItem)
  179. {
  180. SortFolder(hwndTree, hParent);
  181. if (!bAddFiles)
  182. {
  183. TreeView_Expand(hwndTree, hParent, TVE_EXPAND);
  184. }
  185. }
  186. #undef bAddFiles
  187. #undef bRecurse
  188. }
  189. //
  190. // Returns a pointer to the directory string for the currently selected
  191. // item.
  192. //
  193. LPFILEITEMDATA GetCurSel(HWND hwndTree, HTREEITEM * lphtiSel)
  194. {
  195. TV_ITEM tvi;
  196. tvi.hItem = TreeView_GetSelection(hwndTree);
  197. if (lphtiSel)
  198. {
  199. *lphtiSel = tvi.hItem;
  200. }
  201. if (tvi.hItem == NULL)
  202. {
  203. return(NULL);
  204. }
  205. tvi.mask = TVIF_PARAM;
  206. TreeView_GetItem(hwndTree, &tvi);
  207. return((LPFILEITEMDATA)tvi.lParam);
  208. }
  209. //
  210. // Add the specified special folder..
  211. //
  212. HTREEITEM AddSpecialFolder(HWND hwndTree, HTREEITEM htiParent, int nFolder,
  213. LPTSTR pszPath, DWORD dwFlags)
  214. {
  215. LPITEMIDLIST pidl = NULL;
  216. HTREEITEM hti = NULL;
  217. if (SUCCEEDED(SHGetSpecialFolderLocation(hwndTree, nFolder, &pidl)))
  218. {
  219. if (SHGetPathFromIDList(pidl, pszPath))
  220. {
  221. //
  222. // For the desktop, we want the desktop directory, but the icon
  223. // for the magic desktop PIDL.
  224. //
  225. if (nFolder == CSIDL_DESKTOPDIRECTORY)
  226. {
  227. SHFree(pidl);
  228. if (FAILED(SHGetSpecialFolderLocation(hwndTree, CSIDL_DESKTOP, &pidl)))
  229. {
  230. pidl = NULL;
  231. }
  232. }
  233. if (NULL != pidl)
  234. {
  235. hti = AddItem(hwndTree, pszPath, htiParent, pidl,
  236. FIDFLAG_ISFOLDER | dwFlags);
  237. }
  238. }
  239. }
  240. if (NULL != pidl)
  241. {
  242. SHFree(pidl);
  243. }
  244. return(hti);
  245. }
  246. BOOL _inline MakePrgIcon0Index(HWND hwndTree, HIMAGELIST himl)
  247. {
  248. LPITEMIDLIST pidl;
  249. if (SUCCEEDED(SHGetSpecialFolderLocation(hwndTree, CSIDL_PROGRAMS, &pidl)))
  250. {
  251. SHFILEINFO fi;
  252. BOOL_PTR fOk = SHGetFileInfo( (LPTSTR) pidl, 0, &fi, sizeof( fi ),
  253. SHGFI_ICON | SHGFI_SMALLICON | SHGFI_PIDL );
  254. SHFree( pidl );
  255. if (fOk)
  256. {
  257. ImageList_AddIcon(himl, fi.hIcon);
  258. DestroyIcon(fi.hIcon);
  259. return(TRUE);
  260. }
  261. }
  262. return FALSE;
  263. }
  264. //
  265. // Initialize the tree
  266. //
  267. void InitFolderTree( HWND hwndTree, BOOL bAddFiles, HIMAGELIST *phiml )
  268. {
  269. HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  270. HTREEITEM htiStart = NULL;
  271. HTREEITEM htiPrgs = NULL;
  272. TCHAR szPathStart[MAX_PATH];
  273. TCHAR szPathPrgs[MAX_PATH];
  274. UINT flags = ILC_MASK | ILC_COLOR32;
  275. HIMAGELIST himl;
  276. if(IS_WINDOW_RTL_MIRRORED(hwndTree))
  277. {
  278. flags |= ILC_MIRROR;
  279. }
  280. himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
  281. GetSystemMetrics(SM_CYSMICON),
  282. flags, 10, 1);
  283. if (phiml)
  284. *phiml = himl;
  285. if (!himl)
  286. {
  287. return;
  288. }
  289. TreeView_SetImageList(hwndTree, himl, TVSIL_NORMAL);
  290. //
  291. // Add the programs folder as index 0. All sub-folders of programs
  292. // will also have the same icon. This saves both memory and time.
  293. //
  294. if (!MakePrgIcon0Index(hwndTree, himl))
  295. {
  296. return;
  297. }
  298. if (!bAddFiles)
  299. {
  300. AddSpecialFolder(hwndTree, TVI_ROOT, CSIDL_DESKTOPDIRECTORY, szPathStart, 0);
  301. }
  302. htiStart = AddSpecialFolder(hwndTree, TVI_ROOT, CSIDL_STARTMENU, szPathStart, FIDFLAG_CANADDNEW);
  303. if (htiStart)
  304. {
  305. htiPrgs = AddSpecialFolder(hwndTree, htiStart, CSIDL_PROGRAMS, szPathPrgs, FIDFLAG_CANADDNEW | FIDFLAG_ISPROGS);
  306. if (htiPrgs)
  307. {
  308. FillFolder(hwndTree, szPathPrgs, NULL, htiPrgs,
  309. FFF_AddDirs | (bAddFiles ? FFF_AddFiles : 0));
  310. //
  311. // Now fill in the rest of the start menu, excluding programs
  312. //
  313. FillFolder(hwndTree, szPathStart, szPathPrgs, htiStart,
  314. FFF_AddDirs | (bAddFiles ? FFF_AddFiles : 0));
  315. }
  316. }
  317. //
  318. // Now select and expand the programs folder.
  319. //
  320. if (htiPrgs)
  321. {
  322. TreeView_SelectItem(hwndTree, htiPrgs);
  323. if (bAddFiles)
  324. {
  325. TreeView_Expand(hwndTree, htiPrgs, TVE_EXPAND);
  326. }
  327. }
  328. SetCursor(hcurOld);
  329. }
  330. //
  331. // Delete Selected Item
  332. //
  333. VOID RemoveSelItem(HWND hDlg, HWND hwndTree)
  334. {
  335. HTREEITEM hCur;
  336. LPFILEITEMDATA lpfid = GetCurSel(hwndTree, &hCur);
  337. if (!lpfid)
  338. {
  339. ShellMessageBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_NONESEL),
  340. 0, MB_OK | MB_ICONEXCLAMATION);
  341. }
  342. else
  343. {
  344. if (lpfid->dwFlags & FIDFLAG_CANDEL)
  345. {
  346. TCHAR szFileDblNull[MAX_PATH+1];
  347. SHFILEOPSTRUCT sFileOp =
  348. {
  349. hDlg,
  350. FO_DELETE,
  351. szFileDblNull,
  352. NULL,
  353. (lpfid->dwFlags & FIDFLAG_ISFOLDER) ?
  354. FOF_ALLOWUNDO :
  355. FOF_SILENT | FOF_ALLOWUNDO,
  356. };
  357. lstrcpy(szFileDblNull, lpfid->szPath);
  358. szFileDblNull[lstrlen(szFileDblNull)+1] = 0;
  359. if (!SHFileOperation(&sFileOp))
  360. {
  361. if (!(sFileOp.fAnyOperationsAborted))
  362. {
  363. TreeView_DeleteItem(hwndTree, hCur);
  364. }
  365. }
  366. }
  367. else
  368. {
  369. ShellMessageBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_CANTDELETE),
  370. 0, MB_OK | MB_ICONEXCLAMATION, PathFindFileName(lpfid->szPath));
  371. }
  372. }
  373. }
  374. /////////////////////////////////////////////////////////////////////////////
  375. // END SHARED CODE. BEGIN WIZARD SPECIFIC CODE.
  376. /////////////////////////////////////////////////////////////////////////////
  377. //
  378. // Returns -1 if no item is selected, otherwise, sets lpwd->lpszFolder
  379. // to point to the appropriate string, and returns 0.
  380. //
  381. LPARAM PickFolderNextHit(LPWIZDATA lpwd)
  382. {
  383. LPFILEITEMDATA lpfid = GetCurSel(GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE), NULL);
  384. if (lpfid)
  385. {
  386. lpwd->lpszFolder = (LPTSTR)&(lpfid->szPath);
  387. lpwd->szProgDesc[0] = 0;
  388. return(0);
  389. }
  390. else
  391. {
  392. return(-1);
  393. }
  394. }
  395. //
  396. // Creates a new, empty folder.
  397. //
  398. VOID CreateNewFolder(LPWIZDATA lpwd)
  399. {
  400. TCHAR szNewName[MAX_PATH];
  401. HTREEITEM hParent;
  402. LPFILEITEMDATA lpfidParent = GetCurSel(GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE), &hParent);
  403. if (lpfidParent && (lpfidParent->dwFlags & FIDFLAG_CANADDNEW))
  404. {
  405. int iDirLen = lstrlen(lpfidParent->szPath);
  406. TCHAR szNewShort[10];
  407. TCHAR szNewLong[80];
  408. LoadString(g_hinst, IDS_NEWFOLDERSHORT, szNewShort, ARRAYSIZE(szNewShort));
  409. LoadString(g_hinst, IDS_NEWFOLDERLONG, szNewLong, ARRAYSIZE(szNewLong));
  410. PathMakeUniqueName(szNewName, ARRAYSIZE(szNewName),
  411. szNewShort, szNewLong, lpfidParent->szPath);
  412. if (CreateDirectory(szNewName, NULL))
  413. {
  414. HWND hwndTree = GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE);
  415. HTREEITEM hNewDude = AddItem(hwndTree, szNewName, hParent, NULL,
  416. FIDFLAG_ISFOLDER | FIDFLAG_CANADDNEW | FIDFLAG_CANDEL);
  417. if (hNewDude == NULL)
  418. {
  419. TraceMsg(TF_ERROR, "%s", "Unable to add new folder to tree.");
  420. }
  421. if (hNewDude)
  422. {
  423. SortFolder(hwndTree, hParent);
  424. TreeView_SelectItem(hwndTree, hNewDude);
  425. TreeView_EditLabel(hwndTree, hNewDude);
  426. }
  427. }
  428. else
  429. {
  430. TraceMsg(TF_ERROR, "%s", "Unable to create new directory");
  431. }
  432. }
  433. else
  434. {
  435. TraceMsg(TF_ERROR, "%s", "No group selected. Can't create directory.");
  436. }
  437. }
  438. //
  439. // Begin editing a tree label. This function returns FALSE for success, and
  440. // TRUE for failure.
  441. //
  442. BOOL BeginEdit(LPWIZDATA lpwd, TV_DISPINFO * lptvdi)
  443. {
  444. if (TreeView_GetParent(lptvdi->hdr.hwndFrom, lptvdi->item.hItem))
  445. {
  446. lpwd->dwFlags |= WDFLAG_INEDITMODE;
  447. return FALSE;
  448. }
  449. else
  450. {
  451. return TRUE;
  452. }
  453. }
  454. //
  455. // Return FALSE if rename can't happen. True if it worked.
  456. //
  457. BOOL EndEdit(LPWIZDATA lpwd, TV_DISPINFO * lptvdi)
  458. {
  459. BOOL bWorked = FALSE;
  460. #define lpszNewName (LPTSTR)lptvdi->item.pszText
  461. #define lpfidOld ((LPFILEITEMDATA)(lptvdi->item.lParam))
  462. #define hCurItem lptvdi->item.hItem;
  463. lpwd->dwFlags &= ~WDFLAG_INEDITMODE;
  464. if (lpszNewName)
  465. {
  466. LPFILEITEMDATA lpfidNew = (LPFILEITEMDATA)LocalAlloc(LMEM_FIXED,
  467. sizeof(LPFILEITEMDATA)+MAX_PATH*sizeof(TCHAR));
  468. if (lpfidNew)
  469. {
  470. lpfidNew->dwFlags = lpfidOld->dwFlags;
  471. lstrcpy(lpfidNew->szPath, lpfidOld->szPath);
  472. PathRemoveFileSpec(lpfidNew->szPath);
  473. PathCleanupSpec(lpfidNew->szPath, lpszNewName);
  474. PathCombine(lpfidNew->szPath, lpfidNew->szPath, lpszNewName);
  475. if (MoveFile(lpfidOld->szPath, lpfidNew->szPath))
  476. {
  477. TV_ITEM tvi;
  478. tvi.hItem = hCurItem;
  479. tvi.mask = TVIF_PARAM;
  480. tvi.lParam = (LPARAM)lpfidNew;
  481. TreeView_SetItem(lptvdi->hdr.hwndFrom, &tvi);
  482. bWorked = TRUE;
  483. }
  484. else
  485. {
  486. TraceMsg(TF_ERROR, "%s", "Unable to rename directory");
  487. }
  488. LocalFree(bWorked ? lpfidOld : lpfidNew);
  489. }
  490. }
  491. return(bWorked);
  492. #undef lpszNewName
  493. #undef lpfidOld
  494. #undef hCurItem
  495. }
  496. //
  497. // Called when Next or Back is hit to force the end of label editing.
  498. //
  499. void ForceEndEdit(LPWIZDATA lpwd)
  500. {
  501. if (lpwd->dwFlags & WDFLAG_INEDITMODE)
  502. {
  503. TreeView_EndEditLabelNow(GetDlgItem(lpwd->hwnd, IDC_FOLDERTREE), FALSE);
  504. }
  505. }
  506. void FillInItem(TV_DISPINFO * ptvdi)
  507. {
  508. SHFILEINFO fi;
  509. #define lpfid ((LPFILEITEMDATA)(ptvdi->item.lParam))
  510. if (SHGetFileInfo(lpfid->szPath, 0, &fi, sizeof(fi),
  511. SHGFI_ICON | SHGFI_DISPLAYNAME | SHGFI_SMALLICON))
  512. {
  513. if (ptvdi->item.mask & TVIF_IMAGE)
  514. {
  515. ptvdi->item.iImage = ptvdi->item.iSelectedImage =
  516. ImageList_AddIcon(TreeView_GetImageList(ptvdi->hdr.hwndFrom, TVSIL_NORMAL),
  517. fi.hIcon);
  518. ptvdi->item.mask |= TVIF_SELECTEDIMAGE;
  519. }
  520. if (ptvdi->item.mask & TVIF_TEXT)
  521. {
  522. StrCpyN(ptvdi->item.pszText, fi.szDisplayName, ptvdi->item.cchTextMax);
  523. }
  524. DestroyIcon(fi.hIcon);
  525. ptvdi->item.mask |= TVIF_DI_SETITEM;
  526. }
  527. }
  528. //
  529. // Main dialog procedure for tree of folders
  530. //
  531. BOOL_PTR CALLBACK PickFolderDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  532. {
  533. NMHDR *lpnm = NULL;
  534. LPPROPSHEETPAGE lpp = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
  535. LPWIZDATA lpwd = lpp ? (LPWIZDATA)lpp->lParam : NULL;
  536. switch(message)
  537. {
  538. case WM_NOTIFY:
  539. lpnm = (NMHDR *)lParam;
  540. if(lpnm)
  541. {
  542. switch(lpnm->code)
  543. {
  544. case PSN_SETACTIVE:
  545. if(lpwd)
  546. {
  547. if (lpwd->dwFlags & WDFLAG_LINKHEREWIZ)
  548. {
  549. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  550. }
  551. else
  552. {
  553. lpwd->hwnd = hDlg;
  554. PropSheet_SetWizButtons(GetParent(hDlg),
  555. (lpwd->dwFlags & WDFLAG_NOBROWSEPAGE) ?
  556. PSWIZB_NEXT : PSWIZB_BACK | PSWIZB_NEXT);
  557. PostMessage(hDlg, WMPRIV_POKEFOCUS, 0, 0);
  558. }
  559. }
  560. break;
  561. case PSN_WIZBACK:
  562. if(lpwd)
  563. {
  564. ForceEndEdit(lpwd);
  565. SetDlgMsgResult(hDlg, WM_NOTIFY, 0);
  566. }
  567. break;
  568. case PSN_WIZNEXT:
  569. if(lpwd)
  570. {
  571. ForceEndEdit(lpwd);
  572. SetDlgMsgResult(hDlg, WM_NOTIFY, PickFolderNextHit(lpwd));
  573. }
  574. break;
  575. case PSN_RESET:
  576. if(lpwd)
  577. {
  578. CleanUpWizData(lpwd);
  579. }
  580. break;
  581. case NM_DBLCLK:
  582. PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
  583. break;
  584. #define lpfidNew ((LPFILEITEMDATA)(((LPNM_TREEVIEW)lParam)->itemNew.lParam))
  585. case TVN_SELCHANGED:
  586. Button_Enable(GetDlgItem(hDlg, IDC_NEWFOLDER),
  587. (lpfidNew->dwFlags & FIDFLAG_CANADDNEW));
  588. break;
  589. #undef lpfidNew
  590. #define lptvdi ((TV_DISPINFO *)lParam)
  591. case TVN_BEGINLABELEDIT:
  592. if(lpwd)
  593. {
  594. SetDlgMsgResult(hDlg, WM_NOTIFY, BeginEdit(lpwd, lptvdi));
  595. }
  596. break;
  597. case TVN_ENDLABELEDIT:
  598. if(lpwd)
  599. {
  600. SetDlgMsgResult(hDlg, WM_NOTIFY, EndEdit(lpwd, lptvdi));
  601. }
  602. break;
  603. #undef lptvdi
  604. #define lptvn ((LPNM_TREEVIEW)lParam)
  605. case TVN_ITEMEXPANDING:
  606. if (lptvn->action != TVE_EXPAND)
  607. {
  608. SetDlgMsgResult(hDlg, WM_NOTIFY, -1);
  609. }
  610. break;
  611. case TVN_DELETEITEM:
  612. if (lptvn->itemOld.lParam)
  613. {
  614. LocalFree((LPVOID)lptvn->itemOld.lParam);
  615. }
  616. break;
  617. #undef lptvn
  618. case TVN_GETDISPINFO:
  619. FillInItem(((TV_DISPINFO *)lParam));
  620. break;
  621. default:
  622. return FALSE;
  623. }
  624. }
  625. break;
  626. case WM_INITDIALOG:
  627. lpwd = InitWizSheet(hDlg, lParam, 0);
  628. if(lpwd)
  629. {
  630. lpwd->himl = NULL;
  631. if( !( lpwd->dwFlags & WDFLAG_LINKHEREWIZ ) )
  632. {
  633. InitFolderTree( GetDlgItem( hDlg, IDC_FOLDERTREE ),
  634. FALSE, &lpwd->himl );
  635. }
  636. }
  637. break;
  638. case WM_NCDESTROY:
  639. //
  640. // See if we should destroy the himl...
  641. //
  642. if(lpwd)
  643. {
  644. if (lpwd->himl)
  645. {
  646. ImageList_Destroy(lpwd->himl);
  647. lpwd->himl = NULL; // make sure not twice
  648. }
  649. }
  650. return FALSE;
  651. case WMPRIV_POKEFOCUS:
  652. SetFocus(GetDlgItem(hDlg, IDC_FOLDERTREE));
  653. break;
  654. case WM_COMMAND:
  655. switch (GET_WM_COMMAND_ID(wParam, lParam))
  656. {
  657. case IDC_NEWFOLDER:
  658. if(lpwd)
  659. {
  660. CreateNewFolder(lpwd);
  661. }
  662. break;
  663. /// case IDC_DELFOLDER:
  664. /// {
  665. /// HWND hTree = GetDlgItem(hDlg, IDC_FOLDERTREE);
  666. /// RemoveSelItem(hDlg, hTree);
  667. /// SetFocus(hTree);
  668. /// break;
  669. /// }
  670. }
  671. default:
  672. return FALSE;
  673. }
  674. return TRUE;
  675. }
  676. /////////////////////////////////////////////////////////////////////////////
  677. // END WIZARD SPECIFIC CODE. BEGIN DELETE ITEM DIALOG CODE.
  678. /////////////////////////////////////////////////////////////////////////////
  679. typedef struct _FOLDERTHREADINFO {
  680. HANDLE hThread;
  681. HWND hwndTree;
  682. HIMAGELIST himl;
  683. } FOLDERTHREADINFO, * PFOLDERTHREADINFO;
  684. void CALLBACK FolderEnumItems(PFOLDERTHREADINFO pfti, HTREEITEM hParent)
  685. {
  686. HTREEITEM hitem;
  687. hitem = hParent;
  688. while (hitem && pfti->hThread)
  689. {
  690. TV_ITEM tvi;
  691. tvi.mask = TVIF_IMAGE;
  692. tvi.hItem = hitem;
  693. TreeView_GetItem(pfti->hwndTree, &tvi);
  694. hitem = TreeView_GetNextSibling(pfti->hwndTree, hitem);
  695. }
  696. hitem = TreeView_GetChild(pfti->hwndTree, hParent);
  697. while (hitem && pfti->hThread)
  698. {
  699. FolderEnumItems(pfti, hitem);
  700. hitem = TreeView_GetNextSibling(pfti->hwndTree, hitem);
  701. }
  702. }
  703. DWORD CALLBACK FolderThread(PFOLDERTHREADINFO pfti)
  704. {
  705. HANDLE hThread = pfti->hThread;
  706. FolderEnumItems(pfti, TreeView_GetRoot(pfti->hwndTree));
  707. CloseHandle(hThread);
  708. pfti->hThread = 0;
  709. return 0;
  710. }
  711. VOID CreateFolderThread(PFOLDERTHREADINFO pfti)
  712. {
  713. //
  714. // Create background thread to force list view to draw items
  715. //
  716. DWORD idThread;
  717. if (pfti->hThread)
  718. {
  719. return;
  720. }
  721. pfti->hThread = CreateThread(NULL, 0, FolderThread, pfti, 0, &idThread);
  722. if(pfti->hThread)
  723. {
  724. SetThreadPriority(pfti->hThread, THREAD_PRIORITY_BELOW_NORMAL);
  725. }
  726. }
  727. //
  728. // Main dialog procedure for delete items dialog.
  729. //
  730. const static DWORD aDelItemHelpIDs[] = { // Context Help IDs
  731. IDC_TEXT, NO_HELP,
  732. IDC_FOLDERTREE, IDH_TRAY_REMOVEDLG_LIST,
  733. IDC_DELETEITEM, IDH_TRAY_REMOVEDLG_DEL,
  734. 0, 0
  735. };
  736. void WaitForThreadToFinish(HWND hDlg, FOLDERTHREADINFO *pfti)
  737. {
  738. if (pfti->hThread)
  739. {
  740. SHProcessSentMessagesUntilEvent(hDlg, pfti->hThread, 10000);
  741. CloseHandle(pfti->hThread);
  742. pfti->hThread = NULL;
  743. }
  744. }
  745. BOOL_PTR CALLBACK DelItemDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  746. {
  747. PFOLDERTHREADINFO pfti = (PFOLDERTHREADINFO)GetWindowLongPtr(hDlg, DWLP_USER);
  748. switch(message)
  749. {
  750. case WM_NOTIFY:
  751. #define lpnm ((NMHDR *)lParam)
  752. switch(lpnm->code)
  753. {
  754. #define lpfidNew ((LPFILEITEMDATA)(((LPNM_TREEVIEW)lParam)->itemNew.lParam))
  755. case TVN_SELCHANGED:
  756. {
  757. BOOL fCanDel = (lpfidNew->dwFlags & FIDFLAG_CANDEL);
  758. HWND hwndDelItem = GetDlgItem(hDlg, IDC_DELETEITEM);
  759. if ((!fCanDel) && (GetFocus() == hwndDelItem))
  760. {
  761. SetFocus(GetDlgItem(hDlg, IDOK));
  762. SendMessage(hDlg, DM_SETDEFID, IDOK, 0);
  763. }
  764. Button_Enable(hwndDelItem, fCanDel);
  765. break;
  766. }
  767. #undef lpfidNew
  768. #define lptvn ((LPNM_TREEVIEW)lParam)
  769. case TVN_DELETEITEM:
  770. if (lptvn->itemOld.lParam)
  771. {
  772. LocalFree((LPVOID)lptvn->itemOld.lParam);
  773. }
  774. break;
  775. #undef lptvn
  776. #define lptkd ((TV_KEYDOWN *)lParam)
  777. case TVN_KEYDOWN:
  778. if (lptkd->wVKey == VK_DELETE)
  779. {
  780. WaitForThreadToFinish(hDlg, pfti);
  781. RemoveSelItem(hDlg, GetDlgItem(hDlg, IDC_FOLDERTREE));
  782. CreateFolderThread(pfti);
  783. return TRUE;
  784. }
  785. break;
  786. #undef lptkd
  787. case TVN_GETDISPINFO:
  788. FillInItem(((TV_DISPINFO *)lParam));
  789. break;
  790. default:
  791. return FALSE;
  792. #undef lpnm
  793. }
  794. break;
  795. case WM_INITDIALOG:
  796. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  797. pfti = (PFOLDERTHREADINFO)lParam;
  798. InitFolderTree(GetDlgItem(hDlg, IDC_FOLDERTREE), TRUE, &pfti->himl);
  799. pfti->hwndTree = GetDlgItem(hDlg, IDC_FOLDERTREE);
  800. pfti->hThread = 0;
  801. CreateFolderThread(pfti);
  802. break;
  803. case WM_HELP:
  804. WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
  805. HELP_WM_HELP, (DWORD_PTR)(LPTSTR) aDelItemHelpIDs);
  806. break;
  807. case WM_CONTEXTMENU:
  808. WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  809. (DWORD_PTR)(LPVOID) aDelItemHelpIDs);
  810. break;
  811. case WM_COMMAND:
  812. switch (GET_WM_COMMAND_ID(wParam, lParam))
  813. {
  814. case IDOK:
  815. case IDCANCEL:
  816. WaitForThreadToFinish(hDlg, pfti);
  817. EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  818. break;
  819. case IDC_DELETEITEM:
  820. WaitForThreadToFinish(hDlg, pfti);
  821. RemoveSelItem(hDlg, GetDlgItem(hDlg, IDC_FOLDERTREE));
  822. CreateFolderThread(pfti);
  823. break;
  824. }
  825. default:
  826. return FALSE;
  827. }
  828. return TRUE;
  829. }
  830. BOOL RemoveItemsDialog( HWND hParent )
  831. {
  832. BOOL fReturn;
  833. FOLDERTHREADINFO fti;
  834. fti.himl = NULL; // incase we can not create the window
  835. fReturn = (int)DialogBoxParam( g_hinst, MAKEINTRESOURCE( DLG_DELITEM ),
  836. hParent, DelItemDlgProc, (LPARAM) &fti );
  837. if( fti.himl )
  838. ImageList_Destroy( fti.himl );
  839. return fReturn;
  840. }