Leaked source code of windows server 2003
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.

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