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.

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