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.

933 lines
29 KiB

  1. #include "shellprv.h"
  2. #include "ids.h"
  3. #include "util.h"
  4. #include "datautil.h"
  5. #include "foldertypes.h"
  6. #include "basefvcb.h"
  7. #define PROPSTR_LOGO L"Logo"
  8. typedef struct
  9. {
  10. UINT uIDFriendly;
  11. LPCTSTR pszFolderType;
  12. DWORD dwFlags;
  13. } WEBVIEWTEMPLATEINFO;
  14. #define WVTI_SHOWIFOLDTEMPLATE 0x00000001
  15. // documents must be first.
  16. const WEBVIEWTEMPLATEINFO c_wvtiList[] =
  17. {
  18. { IDS_CUSTOMIZE_USELEGACYHTT, STR_TYPE_USELEGACYHTT, WVTI_SHOWIFOLDTEMPLATE },
  19. { IDS_CUSTOMIZE_DOCUMENTS, STR_TYPE_DOCUMENTS, 0 },
  20. { IDS_CUSTOMIZE_PICTURES, STR_TYPE_PICTURES, 0 },
  21. { IDS_CUSTOMIZE_PHOTOALBUM, STR_TYPE_PHOTOALBUM, 0 },
  22. { IDS_CUSTOMIZE_MUSIC, STR_TYPE_MUSIC, 0 },
  23. { IDS_CUSTOMIZE_MUSICARTIST, STR_TYPE_MUSICARTIST, 0 },
  24. { IDS_CUSTOMIZE_MUSICALBUM, STR_TYPE_MUSICALBUM, 0 },
  25. { IDS_CUSTOMIZE_VIDEOS, STR_TYPE_VIDEOS, 0 },
  26. // note: are these gonna happen?
  27. // { IDS_CUSTOMIZE_VIDEOALBUM, STR_TYPE_VIDEOALBUM, 0 },
  28. // { IDS_CUSTOMIZE_BOOKS, STR_TYPE_BOOKS, 0 }
  29. };
  30. typedef enum
  31. {
  32. FOLDERCUST_MODE_GENERATING,
  33. FOLDERCUST_MODE_ICON,
  34. FOLDERCUST_MODE_BITMAP
  35. } FOLDERCUSTMODE;
  36. class CFolderCustomize : public IShellExtInit,
  37. public IShellPropSheetExt
  38. {
  39. public:
  40. // IUnknown
  41. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  42. STDMETHODIMP_(ULONG) AddRef(void);
  43. STDMETHODIMP_(ULONG) Release(void);
  44. // IShellExtInit
  45. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID);
  46. // IShellPropSheetExt
  47. STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
  48. STDMETHODIMP ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
  49. { return S_OK; };
  50. CFolderCustomize();
  51. private:
  52. ~CFolderCustomize();
  53. static UINT CALLBACK _PrshtCallback(HWND hwnd, UINT uMsg, PROPSHEETPAGE *ppsp);
  54. void _SetRecurseBox(HWND hwnd);
  55. void _HideIconSection(HWND hwnd);
  56. void _InitDialog(HWND hwnd);
  57. BOOL _HandleWMCommand(HWND hwndDlg, WORD wNotify, WORD wID, HWND hwndCtrl);
  58. void _EnableApply(HWND hwnd);
  59. static DWORD WINAPI _ExtractThreadProc(void *pv);
  60. HRESULT _ExtractOnSeparateThread(IPropertyBag *ppb, HWND hwndDlg);
  61. HRESULT _CreateThumbnailBitmap(HWND hwndDlg);
  62. HRESULT _CreateFolderIcon(HWND hwndDlg);
  63. void _SetThumbnail(HWND hwnd);
  64. void _FreeDlgItems(HWND hwndDlg);
  65. void _SetPreviewToNewState(HWND hwndDlg, FOLDERCUSTMODE fcMode, HBITMAP hbitmap, HICON hicon);
  66. BOOL _ShouldEnableChangeOfIcon();
  67. void _ChangeFolderIcon(HWND hwndDlg);
  68. HRESULT _ProcessIconChange(LPCTSTR pszPickIconDialogCaption, HWND hwndDlg);
  69. void _DirTouch(LPITEMIDLIST pidl);
  70. void _DeleteCustomizationInBag(IPropertyBag *ppb);
  71. BOOL _NotifyAboutWebView(HWND hwnd);
  72. static BOOL CALLBACK _RefreshView(HWND hwnd, LPCITEMIDLIST pidl, LPARAM lParam);
  73. void _RefreshWindows(BOOL fTurnOnWebView, BOOL fApplyToChildren);
  74. HRESULT _ApplyChangesToBag(HWND hwndDlg, IPropertyBag *ppb);
  75. HRESULT _ApplyChanges(HWND hwndDlg);
  76. void _UpdateViewState(HWND hwndDlg, IPropertyBag *ppb, int iIndex);
  77. void _FillTemplateComboBox(HWND hwndTemplates);
  78. int _GetTemplateIndexFromType(LPCTSTR pszType);
  79. static BOOL_PTR CALLBACK _DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  80. LONG _cRef;
  81. LPITEMIDLIST _pidl;
  82. IPropertyBag *_ppb;
  83. // used for background thread extraction
  84. HWND _hwnd;
  85. IPropertyBag *_ppbBackground;
  86. // cached info
  87. HBITMAP _hbmDefault;
  88. HBITMAP _hbmLogo;
  89. TCHAR _szCachedLogoFile[MAX_PATH];
  90. BOOL _fUsingThumb;
  91. ICustomIconManager *_pIconManager;
  92. TCHAR _szLogoFile[MAX_PATH];
  93. TCHAR _szIconPath[MAX_PATH];
  94. int _iIconIndex;
  95. HRESULT _hrFromIconChange;
  96. };
  97. CFolderCustomize::CFolderCustomize() : _cRef(1), _hrFromIconChange(E_FAIL)
  98. {
  99. }
  100. CFolderCustomize::~CFolderCustomize()
  101. {
  102. ILFree(_pidl);
  103. if (_ppb)
  104. _ppb->Release();
  105. if (_pIconManager)
  106. _pIconManager->Release();
  107. if (_ppbBackground)
  108. _ppbBackground->Release();
  109. if (_hbmDefault)
  110. DeleteObject(_hbmDefault);
  111. if (_hbmLogo)
  112. DeleteObject(_hbmLogo);
  113. }
  114. STDAPI CFolderCustomize_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvOut)
  115. {
  116. // aggregation checking is handled in class factory
  117. HRESULT hr = E_OUTOFMEMORY;
  118. CFolderCustomize* pfc = new CFolderCustomize();
  119. if (pfc)
  120. {
  121. hr = pfc->QueryInterface(riid, ppvOut);
  122. pfc->Release();
  123. }
  124. return hr;
  125. }
  126. HRESULT CFolderCustomize::QueryInterface(REFIID riid, void **ppvObj)
  127. {
  128. static const QITAB qit[] = {
  129. QITABENT(CFolderCustomize, IShellExtInit),
  130. QITABENT(CFolderCustomize, IShellPropSheetExt),
  131. { 0 }
  132. };
  133. return QISearch(this, qit, riid, ppvObj);
  134. }
  135. ULONG CFolderCustomize::AddRef()
  136. {
  137. return InterlockedIncrement(&_cRef);
  138. }
  139. ULONG CFolderCustomize::Release()
  140. {
  141. if (InterlockedDecrement(&_cRef))
  142. return _cRef;
  143. delete this;
  144. return 0;
  145. }
  146. STDMETHODIMP CFolderCustomize::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
  147. {
  148. HRESULT hr;
  149. if (!pidlFolder)
  150. {
  151. hr = PidlFromDataObject(pdtobj, &_pidl);
  152. }
  153. else
  154. {
  155. hr = Pidl_Set(&_pidl, pidlFolder) ? S_OK : E_OUTOFMEMORY;
  156. }
  157. if (SUCCEEDED(hr))
  158. {
  159. hr = SHGetViewStatePropertyBag(_pidl, VS_BAGSTR_EXPLORER, SHGVSPB_PERUSER | SHGVSPB_PERFOLDER, IID_PPV_ARG(IPropertyBag, &_ppb));
  160. }
  161. return hr;
  162. }
  163. // from defview.cpp
  164. BOOL IsCustomizable(LPCITEMIDLIST pidlFolder);
  165. UINT CALLBACK CFolderCustomize::_PrshtCallback(HWND hwnd, UINT uMsg, PROPSHEETPAGE *ppsp)
  166. {
  167. if (uMsg == PSPCB_RELEASE)
  168. {
  169. ((CFolderCustomize *)ppsp->lParam)->Release();
  170. }
  171. return 1;
  172. }
  173. STDMETHODIMP CFolderCustomize::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
  174. {
  175. HRESULT hr = E_FAIL;
  176. if (IsCustomizable(_pidl))
  177. {
  178. PROPSHEETPAGE psp = {0};
  179. psp.dwSize = sizeof(psp);
  180. psp.dwFlags = PSP_USECALLBACK;
  181. psp.hInstance = HINST_THISDLL;
  182. psp.pszTemplate = MAKEINTRESOURCE(DLG_FOLDER_CUSTOMIZE);
  183. psp.pfnDlgProc = _DlgProc;
  184. psp.pfnCallback = _PrshtCallback;
  185. psp.lParam = (LPARAM)this;
  186. HPROPSHEETPAGE hpsp = CreatePropertySheetPage(&psp);
  187. if (hpsp)
  188. {
  189. AddRef(); // HPROPSHEETPAGE holds ref, released on _PrshtCallback
  190. if (!pfnAddPage(hpsp, lParam))
  191. {
  192. DestroyPropertySheetPage(hpsp);
  193. }
  194. else
  195. {
  196. hr = S_OK;
  197. }
  198. }
  199. }
  200. return hr;
  201. }
  202. #define IDH_FOLDER_TEMPLATES 10005
  203. #define IDH_FOLDER_RECURSE 10006
  204. #define IDH_FOLDER_PICKBROWSE 10007
  205. #define IDH_FOLDER_DEFAULT 10008
  206. #define IDH_FOLDER_CHANGEICON 10009
  207. const static DWORD aPrshtHelpIDs[] =
  208. {
  209. IDC_FOLDER_TEMPLATES, IDH_FOLDER_TEMPLATES,
  210. IDC_FOLDER_RECURSE, IDH_FOLDER_RECURSE,
  211. IDC_FOLDER_PICKBROWSE, IDH_FOLDER_PICKBROWSE,
  212. IDC_FOLDER_DEFAULT, IDH_FOLDER_DEFAULT,
  213. IDC_FOLDER_CHANGEICON, IDH_FOLDER_CHANGEICON,
  214. IDC_FOLDER_PREVIEW_ICON, NO_HELP,
  215. IDC_FOLDER_PREVIEW_BITMAP, NO_HELP,
  216. IDC_FOLDER_ICON, NO_HELP,
  217. IDC_FOLDER_CHANGEICONTEXT, NO_HELP,
  218. IDC_FOLDER_CHANGEICONGROUP, NO_HELP,
  219. IDC_NO_HELP_1, NO_HELP,
  220. IDC_NO_HELP_2, NO_HELP,
  221. 0, 0
  222. };
  223. BOOL_PTR CALLBACK CFolderCustomize::_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  224. {
  225. BOOL fRet = FALSE;
  226. CFolderCustomize *pfc = (CFolderCustomize*)GetWindowLongPtr(hwnd, DWLP_USER);
  227. switch (uMsg)
  228. {
  229. case WM_INITDIALOG:
  230. pfc = (CFolderCustomize*)((PROPSHEETPAGE *)lParam)->lParam;
  231. SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pfc);
  232. pfc->_InitDialog(hwnd);
  233. break;
  234. case WM_HELP:
  235. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, L"filefold.hlp", HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aPrshtHelpIDs);
  236. break;
  237. case WM_CONTEXTMENU:
  238. WinHelp((HWND)wParam, L"filefold.hlp", HELP_CONTEXTMENU, (ULONG_PTR)(void *)aPrshtHelpIDs);
  239. break;
  240. case WM_COMMAND:
  241. fRet = pfc->_HandleWMCommand(hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
  242. break;
  243. case WM_NOTIFY:
  244. if (((LPNMHDR)lParam)->code == PSN_APPLY)
  245. {
  246. pfc->_ApplyChanges(hwnd);
  247. }
  248. fRet = TRUE;
  249. break;
  250. case WM_DESTROY:
  251. pfc->_FreeDlgItems(hwnd);
  252. break;
  253. }
  254. return fRet;
  255. }
  256. void CFolderCustomize::_FreeDlgItems(HWND hwndDlg)
  257. {
  258. HICON hicon = (HICON)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_ICON, STM_SETICON, NULL, NULL);
  259. if (hicon)
  260. DestroyIcon(hicon);
  261. HBITMAP hbitmap = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, NULL);
  262. if (hbitmap)
  263. DeleteObject(hbitmap);
  264. ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, NULL);
  265. }
  266. void CFolderCustomize::_SetPreviewToNewState(HWND hwndDlg, FOLDERCUSTMODE fcMode, HBITMAP hbitmap, HICON hicon)
  267. {
  268. // if fcMode == FOLDERCUST_MODE_ICON, we need hicon and not hbitmap
  269. // if fcMode == FOLDERCUST_MODE_BITMAP, we need hbitmap and not hicon.
  270. // otherwise we dont want either.
  271. ASSERT((fcMode != FOLDERCUST_MODE_ICON) || (hicon && !hbitmap));
  272. ASSERT((fcMode != FOLDERCUST_MODE_BITMAP) || (!hicon && hbitmap));
  273. ASSERT((fcMode != FOLDERCUST_MODE_GENERATING) || (!hicon && !hbitmap));
  274. switch (fcMode)
  275. {
  276. case FOLDERCUST_MODE_GENERATING:
  277. {
  278. TCHAR szText[100];
  279. LoadString(HINST_THISDLL, IDS_CUSTOMIZE_GENERATING, szText, ARRAYSIZE(szText));
  280. SetWindowText(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), szText);
  281. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), SW_SHOW);
  282. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_ICON), SW_HIDE);
  283. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP), SW_HIDE);
  284. }
  285. break;
  286. case FOLDERCUST_MODE_ICON:
  287. {
  288. HICON hiconOld = (HICON)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_ICON, STM_SETICON, NULL, NULL);
  289. if (hiconOld)
  290. DestroyIcon(hiconOld);
  291. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), SW_HIDE);
  292. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_ICON), SW_SHOW);
  293. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP), SW_HIDE);
  294. SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon);
  295. }
  296. break;
  297. case FOLDERCUST_MODE_BITMAP:
  298. {
  299. HBITMAP hbitmapOld = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, NULL);
  300. if (hbitmapOld)
  301. DeleteObject(hbitmapOld);
  302. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_TEXT), SW_HIDE);
  303. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_ICON), SW_HIDE);
  304. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP), SW_SHOW);
  305. SendDlgItemMessage(hwndDlg, IDC_FOLDER_PREVIEW_BITMAP, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap);
  306. }
  307. break;
  308. }
  309. }
  310. HRESULT CFolderCustomize::_CreateFolderIcon(HWND hwndDlg)
  311. {
  312. IExtractIcon *peic;
  313. HRESULT hr = SHGetUIObjectFromFullPIDL(_pidl, NULL, IID_PPV_ARG(IExtractIcon, &peic));
  314. if (SUCCEEDED(hr))
  315. {
  316. TCHAR szPath[MAX_PATH];
  317. INT iIndex;
  318. UINT wFlags;
  319. hr = peic->GetIconLocation(0, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
  320. if (SUCCEEDED(hr))
  321. {
  322. UINT nIconSize = MAKELONG(32, 32); // 32 for both large and small
  323. HICON hiconLarge;
  324. hr = peic->Extract(szPath, iIndex, NULL, &hiconLarge, nIconSize);
  325. if (SUCCEEDED(hr))
  326. {
  327. ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, hiconLarge);
  328. }
  329. }
  330. peic->Release();
  331. }
  332. return hr;
  333. }
  334. DWORD WINAPI CFolderCustomize::_ExtractThreadProc(void *pv)
  335. {
  336. CFolderCustomize *pfc = (CFolderCustomize*)pv;
  337. pfc->_SetPreviewToNewState(pfc->_hwnd, FOLDERCUST_MODE_GENERATING, NULL, NULL);
  338. IExtractImage *pei;
  339. HRESULT hr = SHGetUIObjectFromFullPIDL(pfc->_pidl, NULL, IID_PPV_ARG(IExtractImage, &pei));
  340. if (SUCCEEDED(hr))
  341. {
  342. hr = SHLoadFromPropertyBag(pei, pfc->_ppbBackground);
  343. if (SUCCEEDED(hr))
  344. {
  345. TCHAR szPath[MAX_PATH];
  346. SIZE sz = {96, 96};
  347. DWORD dwFlags = IEIFLAG_QUALITY;
  348. hr = pei->GetLocation(szPath, ARRAYSIZE(szPath), NULL, &sz, 24, &dwFlags);
  349. if (SUCCEEDED(hr))
  350. {
  351. HBITMAP hbitmap;
  352. hr = pei->Extract(&hbitmap);
  353. if (SUCCEEDED(hr))
  354. {
  355. pfc->_SetPreviewToNewState(pfc->_hwnd, FOLDERCUST_MODE_BITMAP, hbitmap, NULL);
  356. TCHAR szLogo[MAX_PATH];
  357. if (SUCCEEDED(SHPropertyBag_ReadStr(pfc->_ppbBackground, PROPSTR_LOGO, szLogo, ARRAYSIZE(szLogo))))
  358. {
  359. HBITMAP *phbm = szLogo[0] ? &pfc->_hbmLogo : &pfc->_hbmDefault;
  360. if (*phbm)
  361. DeleteObject(*phbm);
  362. *phbm = (HBITMAP)CopyImage(hbitmap, IMAGE_BITMAP, 0, 0, 0);
  363. if (szLogo[0])
  364. {
  365. lstrcpyn(pfc->_szCachedLogoFile, szLogo, ARRAYSIZE(pfc->_szCachedLogoFile));
  366. }
  367. }
  368. }
  369. }
  370. }
  371. pei->Release();
  372. }
  373. if (FAILED(hr))
  374. {
  375. // IExtractImage on a folder without any jpegs inside will fail.
  376. // in that case we need IExtractIcon.
  377. IExtractIcon *peic;
  378. hr = SHGetUIObjectFromFullPIDL(pfc->_pidl, NULL, IID_PPV_ARG(IExtractIcon, &peic));
  379. if (SUCCEEDED(hr))
  380. {
  381. TCHAR szPath[MAX_PATH];
  382. INT iIndex;
  383. UINT wFlags;
  384. hr = peic->GetIconLocation(0, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
  385. if (SUCCEEDED(hr))
  386. {
  387. UINT nIconSize = MAKELONG(96, 96); // 96 for both large and small
  388. HICON hiconLarge;
  389. hr = peic->Extract(szPath, iIndex, NULL, &hiconLarge, nIconSize);
  390. if (SUCCEEDED(hr))
  391. {
  392. pfc->_SetPreviewToNewState(pfc->_hwnd, FOLDERCUST_MODE_ICON, NULL, hiconLarge);
  393. }
  394. }
  395. peic->Release();
  396. }
  397. }
  398. pfc->Release(); // this thread holds a ref
  399. return 0;
  400. }
  401. HRESULT CFolderCustomize::_ExtractOnSeparateThread(IPropertyBag *ppb, HWND hwndDlg)
  402. {
  403. HRESULT hr = E_OUTOFMEMORY;
  404. IUnknown_Set((IUnknown**)&_ppbBackground, ppb);
  405. _hwnd = hwndDlg;
  406. AddRef();
  407. if (SHCreateThread(_ExtractThreadProc, this, CTF_COINIT, NULL))
  408. {
  409. hr = S_OK;
  410. }
  411. else
  412. {
  413. Release(); // thread failed to take ref
  414. }
  415. return hr;
  416. }
  417. HRESULT CFolderCustomize::_CreateThumbnailBitmap(HWND hwndDlg)
  418. {
  419. HRESULT hr = S_OK;
  420. // see if the bitmap is one we've already extracted.
  421. // can't use the thumbs.db cache for this kind of stuff, since the changes
  422. // havent been committed yet we really shouldnt be poking around in data.
  423. if (!_fUsingThumb && _hbmDefault)
  424. {
  425. _SetPreviewToNewState(hwndDlg, FOLDERCUST_MODE_BITMAP, (HBITMAP)CopyImage(_hbmDefault, IMAGE_BITMAP, 0, 0, 0), NULL);
  426. }
  427. else if (_fUsingThumb && _hbmLogo && (lstrcmpi(_szLogoFile, _szCachedLogoFile) == 0))
  428. {
  429. _SetPreviewToNewState(hwndDlg, FOLDERCUST_MODE_BITMAP, (HBITMAP)CopyImage(_hbmLogo, IMAGE_BITMAP, 0, 0, 0), NULL);
  430. }
  431. else
  432. {
  433. // cache miss, figure it out again.
  434. IPropertyBag *ppb;
  435. hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &ppb));
  436. if (SUCCEEDED(hr))
  437. {
  438. hr = SHPropertyBag_WriteStr(ppb, PROPSTR_LOGO, _fUsingThumb ? _szLogoFile : TEXT(""));
  439. if (SUCCEEDED(hr))
  440. {
  441. hr = _ExtractOnSeparateThread(ppb, hwndDlg);
  442. }
  443. ppb->Release();
  444. }
  445. }
  446. return hr;
  447. }
  448. // dont want OFN_NODEREFERENCELINKS so use the rundlg.cpp helper directly
  449. STDAPI_(BOOL) _GetFileNameFromBrowse(HWND hwnd, LPTSTR szFilePath, UINT cbFilePath, LPCTSTR szWorkingDir, LPCTSTR szDefExt, LPCTSTR szFilters, LPCTSTR szTitle, DWORD dwFlags);
  450. BOOL CFolderCustomize::_HandleWMCommand(HWND hwndDlg, WORD wNotify, WORD wID, HWND hwndCtrl)
  451. {
  452. switch(wID)
  453. {
  454. case IDC_FOLDER_TEMPLATES:
  455. if (wNotify == LBN_SELCHANGE)
  456. {
  457. _EnableApply(hwndDlg);
  458. }
  459. break;
  460. case IDC_FOLDER_DEFAULT:
  461. _EnableApply(hwndDlg);
  462. _fUsingThumb = FALSE;
  463. _CreateThumbnailBitmap(hwndDlg);
  464. break;
  465. case IDC_FOLDER_CHANGEICON:
  466. _ChangeFolderIcon(hwndDlg);
  467. break;
  468. case IDC_FOLDER_PICKBROWSE:
  469. TCHAR szFilePath[MAX_PATH] = {0};
  470. TCHAR szInitialDir[MAX_PATH] = {0};
  471. // initial directory is current folder
  472. // todo: load supported file types at runtime
  473. if (SHGetPathFromIDList(_pidl, szInitialDir) &&
  474. _GetFileNameFromBrowse(hwndDlg, szFilePath, ARRAYSIZE(szFilePath), szInitialDir,
  475. MAKEINTRESOURCE(IDS_IMAGES), MAKEINTRESOURCE(IDS_IMAGESFILTER), MAKEINTRESOURCE(IDS_BROWSE),
  476. OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR))
  477. {
  478. _EnableApply(hwndDlg);
  479. _fUsingThumb = TRUE;
  480. lstrcpyn(_szLogoFile, szFilePath, ARRAYSIZE(_szLogoFile));
  481. _CreateThumbnailBitmap(hwndDlg);
  482. }
  483. break;
  484. }
  485. return FALSE;
  486. }
  487. BOOL CFolderCustomize::_NotifyAboutWebView(HWND hwnd)
  488. {
  489. BOOL fRet = FALSE;
  490. SHELLSTATE ss;
  491. SHGetSetSettings(&ss, SSF_WEBVIEW, FALSE);
  492. if (!ss.fWebView &&
  493. (IDYES == ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_CUSTOMIZE_TURNONWEBVIEW),
  494. MAKEINTRESOURCE(IDS_CUSTOMIZE), MB_YESNO | MB_ICONQUESTION)))
  495. {
  496. ss.fWebView = TRUE;
  497. SHGetSetSettings(&ss, SSF_WEBVIEW, TRUE);
  498. fRet = TRUE;
  499. }
  500. return fRet;
  501. }
  502. typedef struct
  503. {
  504. LPCITEMIDLIST pidlChanged;
  505. BOOL fTurnOnWebView;
  506. BOOL fApplyToChildren;
  507. } CUSTENUMSTRUCT;
  508. BOOL CALLBACK CFolderCustomize::_RefreshView(HWND hwnd, LPCITEMIDLIST pidl, LPARAM lParam)
  509. {
  510. CUSTENUMSTRUCT *pes = (CUSTENUMSTRUCT *)lParam;
  511. if (pes->fTurnOnWebView)
  512. {
  513. PostMessage(hwnd, WM_COMMAND, SFVIDM_MISC_SETWEBVIEW, TRUE);
  514. }
  515. if (ILIsEqual(pes->pidlChanged, pidl) || (pes->fApplyToChildren && ILIsParent(pes->pidlChanged, pidl, FALSE)))
  516. {
  517. PostMessage(hwnd, WM_COMMAND, SFVIDM_MISC_HARDREFRESH, 0L);
  518. }
  519. return TRUE;
  520. }
  521. void CFolderCustomize::_RefreshWindows(BOOL fTurnOnWebView, BOOL fApplyToChildren)
  522. {
  523. CUSTENUMSTRUCT es = { _pidl, fTurnOnWebView, fApplyToChildren };
  524. EnumShellWindows(_RefreshView, (LPARAM)&es);
  525. }
  526. void CFolderCustomize::_UpdateViewState(HWND hwndDlg, IPropertyBag *ppb, int iIndex)
  527. {
  528. TCHAR szOriginalType[25];
  529. szOriginalType[0] = 0;
  530. SHPropertyBag_ReadStr(ppb, PROPSTR_FOLDERTYPE, szOriginalType, ARRAYSIZE(szOriginalType));
  531. // only apply view state change if the folder type is changing.
  532. // also special case so that we dont apply a view state change if the folder has no
  533. // current folder type and the user didnt change the selection from "documents"
  534. // (i.e. they changed folder thumbnail but nothing else).
  535. if ((lstrcmpi(c_wvtiList[iIndex].pszFolderType, szOriginalType) != 0) &&
  536. (szOriginalType[0] || iIndex))
  537. {
  538. // knock out existing state, they don't want it any more.
  539. SHPropertyBag_Delete(ppb, VS_PROPSTR_MODE);
  540. SHPropertyBag_Delete(ppb, VS_PROPSTR_VID);
  541. SHPropertyBag_WriteStr(ppb, PROPSTR_FOLDERTYPE, c_wvtiList[iIndex].pszFolderType);
  542. _RefreshWindows(_NotifyAboutWebView(hwndDlg), Button_GetCheck(GetDlgItem(hwndDlg, IDC_FOLDER_RECURSE)) == BST_CHECKED);
  543. }
  544. }
  545. void CFolderCustomize::_DirTouch(LPITEMIDLIST pidl)
  546. {
  547. FILETIME ftCurrent;
  548. GetSystemTimeAsFileTime(&ftCurrent);
  549. TCHAR szPath[MAX_PATH];
  550. if (SHGetPathFromIDList(pidl, szPath))
  551. {
  552. // woohoo yay for private flags
  553. // 0x100 lets us open a directory in write access
  554. HANDLE h = CreateFile(szPath, GENERIC_READ | 0x100,
  555. FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
  556. OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  557. if (h != INVALID_HANDLE_VALUE)
  558. {
  559. SetFileTime(h, NULL, NULL, &ftCurrent);
  560. CloseHandle(h);
  561. }
  562. }
  563. }
  564. void CFolderCustomize::_DeleteCustomizationInBag(IPropertyBag *ppb)
  565. {
  566. // this is only called when the inherit bag is getting written out.
  567. // so we need to scorch the existing non-inherit bag so it doesn't
  568. // override the inherit bag.
  569. SHPropertyBag_Delete(ppb, PROPSTR_FOLDERTYPE);
  570. SHPropertyBag_Delete(ppb, PROPSTR_LOGO);
  571. SHPropertyBag_Delete(ppb, VS_PROPSTR_MODE);
  572. SHPropertyBag_Delete(ppb, VS_PROPSTR_VID);
  573. }
  574. HRESULT CFolderCustomize::_ApplyChangesToBag(HWND hwndDlg, IPropertyBag *ppb)
  575. {
  576. // handle webview template
  577. HWND hwndTemplates = GetDlgItem(hwndDlg, IDC_FOLDER_TEMPLATES);
  578. if (hwndTemplates)
  579. {
  580. int iIndex = ComboBox_GetCurSel(hwndTemplates);
  581. if (iIndex != CB_ERR)
  582. {
  583. int iViewIndex = (int)ComboBox_GetItemData(hwndTemplates, iIndex);
  584. _UpdateViewState(hwndDlg, ppb, iViewIndex);
  585. }
  586. }
  587. TCHAR szThumb[MAX_PATH];
  588. szThumb[0] = 0;
  589. if (_fUsingThumb)
  590. {
  591. lstrcpyn(szThumb, _szLogoFile, ARRAYSIZE(szThumb));
  592. }
  593. TCHAR szOriginalLogo[MAX_PATH];
  594. szOriginalLogo[0] = 0;
  595. SHPropertyBag_ReadStr(ppb, PROPSTR_LOGO, szOriginalLogo, ARRAYSIZE(szOriginalLogo));
  596. if (lstrcmpi(szThumb, szOriginalLogo) != 0)
  597. {
  598. SHPropertyBag_WriteStr(ppb, PROPSTR_LOGO, szThumb);
  599. _DirTouch(_pidl);
  600. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST, _pidl, NULL);
  601. }
  602. return S_OK;
  603. }
  604. HRESULT CFolderCustomize::_ApplyChanges(HWND hwndDlg)
  605. {
  606. // handle icon change
  607. switch (_hrFromIconChange)
  608. {
  609. case S_OK:
  610. _pIconManager->SetIcon(_szIconPath, _iIconIndex);
  611. break;
  612. case S_FALSE:
  613. _pIconManager->SetDefaultIcon();
  614. break;
  615. }
  616. if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_FOLDER_RECURSE)) == BST_CHECKED)
  617. {
  618. IPropertyBag *ppbInherit;
  619. if (SUCCEEDED(SHGetViewStatePropertyBag(_pidl, VS_BAGSTR_EXPLORER, SHGVSPB_INHERIT, IID_PPV_ARG(IPropertyBag, &ppbInherit))))
  620. {
  621. _DeleteCustomizationInBag(_ppb);
  622. _ApplyChangesToBag(hwndDlg, ppbInherit);
  623. ppbInherit->Release();
  624. }
  625. }
  626. else
  627. {
  628. _ApplyChangesToBag(hwndDlg, _ppb);
  629. }
  630. return S_OK;
  631. }
  632. int CFolderCustomize::_GetTemplateIndexFromType(LPCTSTR pszType)
  633. {
  634. // default to "documents"
  635. int iIndexFound = 0;
  636. for (int iIndex = 0; iIndex < ARRAYSIZE(c_wvtiList); iIndex++)
  637. {
  638. if (lstrcmpi(c_wvtiList[iIndex].pszFolderType, pszType) == 0)
  639. {
  640. iIndexFound = iIndex;
  641. break;
  642. }
  643. }
  644. return iIndexFound;
  645. }
  646. // Fill the combobox with templates' friendly names.
  647. void CFolderCustomize::_FillTemplateComboBox(HWND hwndTemplates)
  648. {
  649. // Disable redraws while we mess repeatedly with the contents.
  650. SendMessage(hwndTemplates, WM_SETREDRAW, FALSE, 0);
  651. TCHAR szType[25];
  652. szType[0] = 0;
  653. SHPropertyBag_ReadStr(_ppb, PROPSTR_FOLDERTYPE, szType, ARRAYSIZE(szType));
  654. int nFolderTypeIndex = _GetTemplateIndexFromType(szType); // store index into c_wvtiList
  655. int iIndex = 0; // index into combobox
  656. // Add each template to the listview.
  657. for (int nTemplate = 0; nTemplate < ARRAYSIZE(c_wvtiList); nTemplate++)
  658. {
  659. TCHAR szPath[MAX_PATH];
  660. SFVM_WEBVIEW_TEMPLATE_DATA wvData;
  661. if (!(c_wvtiList[nTemplate].dwFlags & WVTI_SHOWIFOLDTEMPLATE) ||
  662. (SHGetPathFromIDList(_pidl, szPath) && SUCCEEDED(DefaultGetWebViewTemplateFromPath(szPath, &wvData))))
  663. {
  664. TCHAR szFriendlyName[100];
  665. LoadString(HINST_THISDLL, c_wvtiList[nTemplate].uIDFriendly, szFriendlyName, ARRAYSIZE(szFriendlyName));
  666. int iIndexAdd = ComboBox_AddString(hwndTemplates, szFriendlyName);
  667. if (iIndexAdd != -1)
  668. {
  669. if (nTemplate == nFolderTypeIndex)
  670. {
  671. iIndex = iIndexAdd;
  672. }
  673. ComboBox_SetItemData(hwndTemplates, iIndexAdd, nTemplate);
  674. }
  675. }
  676. }
  677. // pick default
  678. ComboBox_SetCurSel(hwndTemplates, iIndex);
  679. // Reenable redraws.
  680. SendMessage(hwndTemplates, WM_SETREDRAW, TRUE, 0);
  681. InvalidateRect(hwndTemplates, NULL, TRUE);
  682. }
  683. void CFolderCustomize::_SetThumbnail(HWND hwnd)
  684. {
  685. _szLogoFile[0] = 0;
  686. SHPropertyBag_ReadStr(_ppb, PROPSTR_LOGO, _szLogoFile, ARRAYSIZE(_szLogoFile));
  687. _fUsingThumb = _szLogoFile[0];
  688. _CreateThumbnailBitmap(hwnd);
  689. }
  690. void CFolderCustomize::_SetRecurseBox(HWND hwnd)
  691. {
  692. IPropertyBag *ppbInherit;
  693. if (SUCCEEDED(SHGetViewStatePropertyBag(_pidl, VS_BAGSTR_EXPLORER, SHGVSPB_INHERIT, IID_PPV_ARG(IPropertyBag, &ppbInherit))))
  694. {
  695. TCHAR szTypeInherit[MAX_PATH];
  696. if (SUCCEEDED(SHPropertyBag_ReadStr(ppbInherit, PROPSTR_FOLDERTYPE, szTypeInherit, ARRAYSIZE(szTypeInherit))) && szTypeInherit[0])
  697. {
  698. TCHAR szType[MAX_PATH];
  699. if (SUCCEEDED(SHPropertyBag_ReadStr(_ppb, PROPSTR_FOLDERTYPE, szType, ARRAYSIZE(szType))) &&
  700. (lstrcmpi(szTypeInherit, szType) == 0))
  701. {
  702. Button_SetCheck(GetDlgItem(hwnd, IDC_FOLDER_RECURSE), TRUE);
  703. }
  704. }
  705. ppbInherit->Release();
  706. }
  707. }
  708. // since changing the icon isn't in the peruser property bag (yet [it was punted from whistler])
  709. // we need to disable this section if we know it can't be modified.
  710. void CFolderCustomize::_HideIconSection(HWND hwndDlg)
  711. {
  712. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_CHANGEICONGROUP), SW_HIDE);
  713. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_CHANGEICON), SW_HIDE);
  714. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_CHANGEICONTEXT), SW_HIDE);
  715. ShowWindow(GetDlgItem(hwndDlg, IDC_FOLDER_ICON), SW_HIDE);
  716. }
  717. void CFolderCustomize::_InitDialog(HWND hwndDlg)
  718. {
  719. HWND hwndTemplates = GetDlgItem(hwndDlg, IDC_FOLDER_TEMPLATES);
  720. if (hwndTemplates)
  721. {
  722. _FillTemplateComboBox(GetDlgItem(hwndDlg, IDC_FOLDER_TEMPLATES));
  723. EnableWindow(hwndTemplates, TRUE);
  724. _SetThumbnail(hwndDlg);
  725. // Disable the Icon Change button if we the IShellFolder doesn't support ICustomIconManager interface.
  726. if (_ShouldEnableChangeOfIcon())
  727. {
  728. _CreateFolderIcon(hwndDlg);
  729. }
  730. else
  731. {
  732. _HideIconSection(hwndDlg);
  733. }
  734. _SetRecurseBox(hwndDlg);
  735. }
  736. }
  737. // helpers moved from mulprsht
  738. // How do we selectively disable for .exe
  739. BOOL CFolderCustomize::_ShouldEnableChangeOfIcon()
  740. {
  741. if (!_pIconManager)
  742. {
  743. SHGetUIObjectFromFullPIDL(_pidl, NULL, IID_PPV_ARG(ICustomIconManager, &_pIconManager));
  744. }
  745. return BOOLIFY(_pIconManager);
  746. }
  747. void CFolderCustomize::_EnableApply(HWND hwnd)
  748. {
  749. PropSheet_Changed(GetParent(hwnd), hwnd);
  750. }
  751. void CFolderCustomize::_ChangeFolderIcon(HWND hwndDlg)
  752. {
  753. ASSERT(_pIconManager);
  754. TCHAR szDialogCaptionFmt[MAX_PATH];
  755. LoadString(HINST_THISDLL, IDS_FOLDER_PICKICONDLG_CAPTION, szDialogCaptionFmt, ARRAYSIZE(szDialogCaptionFmt));
  756. TCHAR szFileName[MAX_PATH], szDialogCaption[MAX_PATH];
  757. if (SUCCEEDED(SHGetNameAndFlags(_pidl, SHGDN_NORMAL, szFileName, ARRAYSIZE(szFileName), NULL)))
  758. {
  759. wnsprintf(szDialogCaption, ARRAYSIZE(szDialogCaption), szDialogCaptionFmt, PathFindFileName(szFileName));
  760. }
  761. if (SUCCEEDED(_ProcessIconChange(szDialogCaption, hwndDlg)))
  762. {
  763. _EnableApply(hwndDlg);
  764. }
  765. }
  766. HRESULT CFolderCustomize::_ProcessIconChange(LPCTSTR pszPickIconDialogCaption, HWND hwndDlg)
  767. {
  768. int nIconIndex = -1;
  769. TCHAR szIconPath[MAX_PATH];
  770. szIconPath[0] = 0;
  771. HRESULT hr = PickIconDlgWithTitle(hwndDlg, pszPickIconDialogCaption, TRUE, szIconPath, ARRAYSIZE(szIconPath), &nIconIndex);
  772. _hrFromIconChange = hr;
  773. switch (hr)
  774. {
  775. case S_OK:
  776. {
  777. HICON hIcon = ExtractIcon(HINST_THISDLL, szIconPath, nIconIndex);
  778. if (hIcon != NULL)
  779. {
  780. ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, hIcon);
  781. StrCpyN(_szIconPath, szIconPath, ARRAYSIZE(_szIconPath));
  782. _iIconIndex = nIconIndex;
  783. }
  784. else
  785. {
  786. _hrFromIconChange = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  787. }
  788. break;
  789. }
  790. case S_FALSE:
  791. {
  792. HICON hIcon;
  793. if (SUCCEEDED(_pIconManager->GetDefaultIconHandle(&hIcon)))
  794. {
  795. ReplaceDlgIcon(hwndDlg, IDC_FOLDER_ICON, hIcon);
  796. }
  797. else
  798. {
  799. _hrFromIconChange = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  800. }
  801. break;
  802. }
  803. case HRESULT_FROM_WIN32(ERROR_CANCELLED):
  804. {
  805. break;
  806. }
  807. }
  808. return hr;
  809. }