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.

628 lines
23 KiB

  1. #include "precomp.h"
  2. #include <shutil.h>
  3. #include "prevwnd.h"
  4. #include "resource.h"
  5. #pragma hdrstop
  6. int DPA_ILFree(void *p, void *pData)
  7. {
  8. ILFree((LPITEMIDLIST)p);
  9. return 1;
  10. }
  11. BOOL _SamePath(LPITEMIDLIST pidl1, LPITEMIDLIST pidl2)
  12. {
  13. BOOL bSame = FALSE;
  14. TCHAR szName1[MAX_PATH];
  15. if (SUCCEEDED(SHGetNameAndFlags(pidl1, SHGDN_FORPARSING, szName1, ARRAYSIZE(szName1), NULL)))
  16. {
  17. TCHAR szName2[MAX_PATH];
  18. if (SUCCEEDED(SHGetNameAndFlags(pidl2, SHGDN_FORPARSING, szName2, ARRAYSIZE(szName2), NULL)))
  19. {
  20. bSame = (0 == StrCmpI(szName1, szName2));
  21. }
  22. }
  23. return bSame;
  24. }
  25. HRESULT _AddSuffix(LPCWSTR pwszSuffix, LPWSTR pwszBuffer, UINT cchBuffer)
  26. {
  27. ASSERTMSG(pwszBuffer && pwszSuffix, "_AddSuffix -- invalid params to internal function");
  28. HRESULT hr = E_FAIL;
  29. LPWSTR pwszExt = PathFindExtension(pwszBuffer);
  30. if (pwszExt)
  31. {
  32. UINT cchSuffix = lstrlenW(pwszSuffix);
  33. UINT cchExt = lstrlenW(pwszExt);
  34. if (((pwszExt - pwszBuffer) + cchSuffix + cchExt) < cchBuffer)
  35. {
  36. memmove(pwszExt + cchSuffix, pwszExt, sizeof(WCHAR) * (1 + cchExt));
  37. memcpy(pwszExt, pwszSuffix, cchSuffix * sizeof(WCHAR));
  38. hr = S_OK;
  39. }
  40. }
  41. return hr;
  42. }
  43. HRESULT _GetImageName(HDPA hdpaItems, UINT uiDex, BOOL fAddSuffix, LPSTR* ppszOut)
  44. {
  45. ASSERTMSG(hdpaItems && ppszOut && *ppszOut, "_GetImageName -- invalid params to internal function");
  46. HRESULT hr = E_FAIL;
  47. LPCITEMIDLIST pidl = (LPITEMIDLIST)DPA_GetPtr(hdpaItems, uiDex);
  48. if (pidl)
  49. {
  50. TCHAR szName[MAX_PATH];
  51. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName), NULL)))
  52. {
  53. if (fAddSuffix)
  54. {
  55. TCHAR szThumbSuffix[20];
  56. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_SUFFIX, szThumbSuffix, ARRAYSIZE(szThumbSuffix));
  57. if (FAILED(_AddSuffix(szThumbSuffix, szName, ARRAYSIZE(szName))))
  58. {
  59. return E_FAIL;
  60. }
  61. }
  62. USES_CONVERSION;
  63. *((*ppszOut)++) = '\"';
  64. StrCpyA(*ppszOut, W2A(szName));
  65. *ppszOut += lstrlenA(*ppszOut);
  66. *((*ppszOut)++) = '\"';
  67. hr = S_OK;
  68. }
  69. }
  70. return hr;
  71. }
  72. HRESULT GetFolderFromSite(IUnknown *punkSite, LPITEMIDLIST *ppidl)
  73. {
  74. *ppidl = NULL;
  75. IFolderView *pfv;
  76. HRESULT hr = IUnknown_QueryService(punkSite, SID_SFolderView, IID_PPV_ARG(IFolderView, &pfv));
  77. if (SUCCEEDED(hr))
  78. {
  79. IShellFolder *psf;
  80. hr = pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf));
  81. if (SUCCEEDED(hr))
  82. {
  83. hr = SHGetIDListFromUnk(psf, ppidl);
  84. psf->Release();
  85. }
  86. pfv->Release();
  87. }
  88. return hr;
  89. }
  90. HRESULT CPreviewWnd::_CreateWebViewer()
  91. {
  92. HRESULT hr = E_FAIL;
  93. TCHAR szPick[128];
  94. LoadString(_Module.GetModuleInstance(), IDS_CHOOSE_DIR, szPick, ARRAYSIZE(szPick));
  95. BROWSEINFO bi = { NULL, NULL, NULL, szPick, BIF_NEWDIALOGSTYLE, 0, 0 };
  96. LPITEMIDLIST pidlDest = SHBrowseForFolder(&bi);
  97. if (pidlDest)
  98. {
  99. // get the IStorage we'll write to
  100. IStorage* pstgDest;
  101. hr = SHBindToObjectEx(NULL, pidlDest, NULL, IID_PPV_ARG(IStorage, &pstgDest));
  102. if (SUCCEEDED(hr))
  103. {
  104. // get the images we'll write
  105. HDPA hdpaItems = NULL;
  106. hr = _GetSelectedImages(&hdpaItems);
  107. if (SUCCEEDED(hr))
  108. {
  109. LPITEMIDLIST pidlFolder;
  110. hr = GetFolderFromSite(m_punkSite, &pidlFolder);
  111. if (SUCCEEDED(hr))
  112. {
  113. UINT cItems = DPA_GetPtrCount(hdpaItems);
  114. // we may write them to the directory chosen if it's not the original dir
  115. if (!_SamePath(pidlFolder, pidlDest))
  116. {
  117. IStorage* pstgSrc;
  118. hr = SHBindToObjectEx(NULL, pidlFolder, NULL, IID_PPV_ARG(IStorage, &pstgSrc));
  119. if (SUCCEEDED(hr))
  120. {
  121. hr = _CopyImages(pstgSrc, pstgDest, cItems, hdpaItems);
  122. pstgSrc->Release();
  123. }
  124. }
  125. ILFree(pidlFolder);
  126. // write the thumbnails to the directory chosen
  127. if (SUCCEEDED(hr))
  128. {
  129. BOOL fThumbWritten;
  130. hr = _CopyThumbnails(pidlDest, cItems, hdpaItems, &fThumbWritten);
  131. if (SUCCEEDED(hr))
  132. {
  133. // write the HTML pages
  134. hr = _WriteHTML(pstgDest, cItems, hdpaItems);
  135. }
  136. }
  137. }
  138. DPA_DestroyCallback(hdpaItems, DPA_ILFree, NULL);
  139. }
  140. pstgDest->Release();
  141. }
  142. ILFree(pidlDest);
  143. }
  144. return hr;
  145. }
  146. HRESULT CPreviewWnd::_FormatHTML(UINT cItems, HDPA hdpaItems,
  147. LPSTR pszTemplate, DWORD cbTemplateSize,
  148. LPSTR psz1, LPSTR psz2, UINT ui1, LPSTR* ppszOut)
  149. {
  150. HRESULT hr = E_OUTOFMEMORY;
  151. *ppszOut = (LPSTR)LocalAlloc(LPTR, cbTemplateSize + lstrlenA(psz1) + lstrlenA(psz2) + 11);
  152. if (*ppszOut)
  153. {
  154. LPSTR pszSrc = pszTemplate;
  155. LPSTR pszDest = *ppszOut;
  156. UINT uiStage = 0;
  157. while (*pszSrc && ((pszSrc - pszTemplate) < (INT)cbTemplateSize))
  158. {
  159. if ('%' == *pszSrc && 's' == *(pszSrc + 1) && 0 == uiStage) // list of images
  160. {
  161. StrCpyA(pszDest, psz1);
  162. pszDest += lstrlenA(psz1);
  163. pszSrc += 2;
  164. uiStage++;
  165. }
  166. else if ('%' == *pszSrc && 's' == *(pszSrc + 1) && 1 == uiStage) // list of thumbnails
  167. {
  168. StrCpyA(pszDest, psz2);
  169. pszDest += lstrlenA(psz2);
  170. pszSrc += 2;
  171. uiStage++;
  172. }
  173. else if ('%' == *pszSrc && 'd' == *(pszSrc + 1) && 2 == uiStage) // number of images
  174. {
  175. pszDest += wsprintfA(pszDest, "%d", ui1);
  176. pszSrc += 2;
  177. uiStage++;
  178. }
  179. else
  180. {
  181. *pszDest = *pszSrc;
  182. pszSrc++;
  183. pszDest++;
  184. }
  185. }
  186. hr = S_OK;
  187. }
  188. return hr;
  189. }
  190. const char c_szNetText1[] = "<center><a href=\"#\" onclick=\"nextFilmImage()\"><img width=80% alt=%s src=%s></a></center>";
  191. const char c_szNetText2[] = "<td><a href=\"#\" onclick=\"filmSelect(%d)\"><img alt=%s src=%s></a></td>\r\n";
  192. const char c_szNetText3[] = "<center><a href=\"#\" onclick=\"nextImage()\"><img width=80% alt=%s src=%s></a></center>";
  193. const char c_szNetText4[] = "<td><a href=\"#\" onclick=\"contactSelect(%d)\"><img alt=%s src=%s></a></td>\r\n";
  194. HRESULT CPreviewWnd::_FormatHTMLNet(UINT cItems, HDPA hdpaItems,
  195. LPSTR pszTemplate, DWORD cbTemplateSize,
  196. LPSTR psz1, UINT ui1, LPSTR* ppszOut)
  197. {
  198. HRESULT hr = E_OUTOFMEMORY;
  199. USES_CONVERSION;
  200. *ppszOut = (LPSTR)LocalAlloc(LPTR, 2 * (cbTemplateSize + (11 * (cItems + 1)) + lstrlenA(psz1) * 4)); // ISSUE: we need to figure out how big this should be
  201. if (*ppszOut)
  202. {
  203. LPSTR pszSrc = pszTemplate;
  204. LPSTR pszDest = *ppszOut;
  205. UINT uiStage = 0;
  206. CHAR szStringFormatted[256];
  207. while (*pszSrc && ((pszSrc - pszTemplate) < (INT)cbTemplateSize))
  208. {
  209. if ('%' == *pszSrc && *(pszSrc + 1) == 's' && 0 == uiStage)
  210. {
  211. StrCpyA(pszDest, psz1);
  212. pszDest += lstrlenA(psz1);
  213. pszSrc += 2;
  214. uiStage++;
  215. }
  216. else if ('%' == *pszSrc && *(pszSrc + 1) == 'd' && 1 == uiStage)
  217. {
  218. pszDest += wsprintfA(pszDest, "%d", ui1);
  219. pszSrc += 2;
  220. uiStage++;
  221. }
  222. else if ('%' == *pszSrc && 's' == *(pszSrc + 1) && (2 == uiStage || 4 == uiStage)) // IDS_WEBVIEWER_NETTEXT_1, 3
  223. {
  224. CHAR szFirstImage[MAX_PATH];
  225. LPSTR pszFirstImage = szFirstImage;
  226. if (SUCCEEDED(_GetImageName(hdpaItems, 0, FALSE, &pszFirstImage)))
  227. {
  228. *pszFirstImage = 0;
  229. DWORD cchStringFormatted = wsprintfA(szStringFormatted, uiStage == 2 ? c_szNetText1 : c_szNetText3,
  230. szFirstImage, szFirstImage);
  231. StrCpyA(pszDest, szStringFormatted);
  232. pszDest += cchStringFormatted;
  233. pszSrc += 2;
  234. }
  235. uiStage++;
  236. }
  237. else if ('s' == *pszSrc && 's' == *(pszSrc + 1) && (3 == uiStage || 5 == uiStage)) // IDS_WEBVIEWER_NETTEXT_2, 4
  238. {
  239. WCHAR wszLoadStringThumb[20];
  240. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_SUFFIX, wszLoadStringThumb, ARRAYSIZE(wszLoadStringThumb));
  241. for (UINT i = 0; i < cItems; i++)
  242. {
  243. CHAR szImage[MAX_PATH];
  244. LPSTR pszImage = szImage;
  245. if (SUCCEEDED(_GetImageName(hdpaItems, i, TRUE, &pszImage)))
  246. {
  247. *pszImage = 0;
  248. DWORD cchStringFormatted = wsprintfA(szStringFormatted, 3 == uiStage ? c_szNetText2 : c_szNetText4,
  249. i, szImage, szImage);
  250. StrCpyA(pszDest, szStringFormatted);
  251. pszDest += cchStringFormatted;
  252. }
  253. }
  254. pszSrc += 2;
  255. uiStage++;
  256. }
  257. else
  258. {
  259. *pszDest = *pszSrc;
  260. pszSrc++;
  261. pszDest++;
  262. }
  263. }
  264. hr = S_OK;
  265. }
  266. return hr;
  267. }
  268. #define IE_VIEWER 1
  269. #define NET_VIEWER 2
  270. HRESULT CPreviewWnd::_WriteHTML(IStorage* pStgDest, UINT cItems, HDPA hdpaItems)
  271. {
  272. HRESULT hr = E_FAIL;
  273. const UINT rguiIDs[2] = { IDR_VIEWERHTML , IDR_VIEWERHTML_NET };
  274. LPCWSTR rgwszFiles[2] = { L"viewer.htm" , L"viewern.htm"};
  275. const DWORD rgdwTypes[2] = { IE_VIEWER, NET_VIEWER };
  276. LPSTR pszImages = _GetImageList(cItems, hdpaItems, FALSE);
  277. if (pszImages)
  278. {
  279. LPSTR pszThumbs = _GetImageList(cItems, hdpaItems, TRUE);
  280. if (pszThumbs)
  281. {
  282. hr = S_OK;
  283. for (int i = 0; i < ARRAYSIZE(rguiIDs) && SUCCEEDED(hr); i++)
  284. {
  285. HRSRC hrsrc = FindResource(_Module.GetModuleInstance(), MAKEINTRESOURCE(rguiIDs[i]), RT_HTML);
  286. if (hrsrc)
  287. {
  288. DWORD dwGlobSize = SizeofResource(_Module.GetModuleInstance(), hrsrc);
  289. HGLOBAL hglob = LoadResource(_Module.GetModuleInstance(), hrsrc);
  290. if (hglob)
  291. {
  292. LPSTR pszHTML = (LPSTR)LockResource(hglob);
  293. if (pszHTML)
  294. {
  295. LPSTR pszHTMLFormatted;
  296. if (IE_VIEWER == rgdwTypes[i]) // build the IE viewers
  297. {
  298. hr = _FormatHTML(cItems, hdpaItems, pszHTML, dwGlobSize, pszImages, pszThumbs, cItems, &pszHTMLFormatted);
  299. }
  300. else // build the netscape viewers
  301. {
  302. hr = _FormatHTMLNet(cItems, hdpaItems, pszHTML, dwGlobSize, pszImages, cItems, &pszHTMLFormatted);
  303. }
  304. if (SUCCEEDED(hr))
  305. {
  306. IStream* pStream;
  307. if (SUCCEEDED(pStgDest->CreateStream(rgwszFiles[i], STGM_WRITE | STGM_CREATE, 0, 0, &pStream)))
  308. {
  309. if (SUCCEEDED(pStream->Write(pszHTMLFormatted, lstrlenA(pszHTMLFormatted), NULL)))
  310. {
  311. hr = S_OK;
  312. }
  313. pStream->Release();
  314. }
  315. LocalFree(pszHTMLFormatted);
  316. }
  317. }
  318. FreeResource(hglob);
  319. }
  320. }
  321. }
  322. LocalFree(pszThumbs);
  323. }
  324. LocalFree(pszImages);
  325. }
  326. return hr;
  327. }
  328. LPSTR CPreviewWnd::_GetImageList(UINT cItems, HDPA hdpaItems, BOOL fAddSuffix)
  329. {
  330. LPSTR pszRetVal = (LPSTR)LocalAlloc(LPTR, cItems * MAX_PATH);
  331. if (pszRetVal)
  332. {
  333. LPSTR pszPtr = pszRetVal;
  334. for (UINT i = 0; (i < cItems); i++)
  335. {
  336. if (SUCCEEDED(_GetImageName (hdpaItems, i, fAddSuffix, &pszPtr)))
  337. {
  338. if (i != (cItems - 1))
  339. {
  340. *pszPtr++ = ',';
  341. }
  342. *pszPtr++ = '\r';
  343. *pszPtr++ = '\n';
  344. }
  345. }
  346. LocalReAlloc(pszRetVal, lstrlenA(pszRetVal), LMEM_MOVEABLE);
  347. }
  348. return pszRetVal;
  349. }
  350. // make sure it is not one of our generated thumbnails
  351. BOOL CPreviewWnd::_IsThumbnail(LPCTSTR pszPath)
  352. {
  353. // now check if is ???__thumb.gif or something, if so then is not a picture we should include
  354. TCHAR szThumbSuffix[20];
  355. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_SUFFIX, szThumbSuffix, ARRAYSIZE(szThumbSuffix));
  356. int cchThumbSuffix = lstrlen(szThumbSuffix);
  357. LPCTSTR pszDot = PathFindExtension(pszPath);
  358. BOOL fIsThumbnail = FALSE;
  359. if ((pszDot - pszPath) > cchThumbSuffix)
  360. {
  361. if (0 == lstrncmp(pszDot - cchThumbSuffix, szThumbSuffix, cchThumbSuffix))
  362. {
  363. fIsThumbnail = TRUE;
  364. }
  365. }
  366. return fIsThumbnail;
  367. }
  368. HRESULT CPreviewWnd::_GetSelectedImages(HDPA* phdpaItems)
  369. {
  370. HRESULT hr = E_OUTOFMEMORY;
  371. *phdpaItems = DPA_Create(5);
  372. if (*phdpaItems)
  373. {
  374. LPITEMIDLIST pidl;
  375. for (UINT i = 0; SUCCEEDED(_GetItem(i, &pidl)); i++)
  376. {
  377. TCHAR szName[MAX_PATH];
  378. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName), NULL);
  379. if (SUCCEEDED(hr) && !_IsThumbnail(szName))
  380. {
  381. if (DPA_AppendPtr(*phdpaItems, pidl) >= 0)
  382. {
  383. pidl = NULL; // don't free below
  384. }
  385. }
  386. ILFree(pidl); // accepts NULL
  387. }
  388. }
  389. return hr;
  390. }
  391. HRESULT CPreviewWnd::_CopyImages_SetupProgress(IProgressDialog** ppProgress,
  392. LPWSTR pwszBanner)
  393. {
  394. HRESULT hr = CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER,
  395. IID_PPV_ARG(IProgressDialog, ppProgress));
  396. if (SUCCEEDED(hr))
  397. {
  398. hr = (*ppProgress)->SetTitle(pwszBanner);
  399. if (SUCCEEDED(hr))
  400. {
  401. hr = (*ppProgress)->SetAnimation(_Module.GetModuleInstance(), IDA_FILECOPY);
  402. if (SUCCEEDED(hr))
  403. {
  404. hr = (*ppProgress)->StartProgressDialog(NULL, NULL, PROGDLG_NORMAL, NULL);
  405. if (SUCCEEDED(hr))
  406. {
  407. hr = (*ppProgress)->SetProgress(0, 1);
  408. }
  409. }
  410. }
  411. }
  412. return hr;
  413. }
  414. // note: this function will quite happily copy from istorage to itself, caller's responsibility
  415. // not to call with pstgSrc and pstgDest referring to same place
  416. HRESULT CPreviewWnd::_CopyImages(IStorage* pstgSrc, IStorage* pstgDest, UINT cItems, HDPA hdpaItems)
  417. {
  418. HRESULT hr = S_OK;
  419. ASSERTMSG(pstgSrc != NULL && pstgDest != NULL, "CPreviewWnd::_CopyImages -- invalid params to internal function");
  420. if (cItems > 0)
  421. {
  422. WCHAR wszMsgBox[128];
  423. WCHAR wszMsgBoxTitle[64];
  424. LoadString(_Module.GetModuleInstance(), IDS_COPYIMAGES_MSGBOX, wszMsgBox, ARRAYSIZE(wszMsgBox));
  425. LoadString(_Module.GetModuleInstance(), IDS_COPYIMAGES_MSGBOXTITLE, wszMsgBoxTitle, ARRAYSIZE(wszMsgBoxTitle));
  426. hr = S_OK;
  427. int iResult = MessageBox(wszMsgBox, wszMsgBoxTitle, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1 | MB_APPLMODAL);
  428. if (IDYES == iResult)
  429. {
  430. WCHAR wszProgressText[64];
  431. LoadString(_Module.GetModuleInstance(), IDS_COPYIMAGES_PROGRESSTEXT, wszProgressText, ARRAYSIZE(wszProgressText));
  432. IProgressDialog* pProgress;
  433. hr = _CopyImages_SetupProgress(&pProgress, wszProgressText);
  434. if (SUCCEEDED(hr))
  435. {
  436. for (UINT i = 0; (i < cItems) && SUCCEEDED(hr) && !pProgress->HasUserCancelled(); i++)
  437. {
  438. LPITEMIDLIST pidl = (LPITEMIDLIST)DPA_GetPtr(hdpaItems, i);
  439. WCHAR wszFullName[MAX_PATH];
  440. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, wszFullName, ARRAYSIZE(wszFullName), NULL);
  441. if (SUCCEEDED(hr))
  442. {
  443. LPTSTR pszName = PathFindFileName(wszFullName);
  444. hr = pProgress->SetLine(1, pszName, TRUE, NULL);
  445. if (SUCCEEDED(hr))
  446. {
  447. hr = pstgSrc->MoveElementTo(pszName, pstgDest, pszName, STGMOVE_COPY);
  448. if (SUCCEEDED(hr))
  449. {
  450. hr = pProgress->SetProgress(i, cItems);
  451. }
  452. }
  453. }
  454. }
  455. pProgress->StopProgressDialog();
  456. pProgress->Release();
  457. }
  458. }
  459. }
  460. return hr;
  461. }
  462. HRESULT CPreviewWnd::_CopyThumbnails(LPITEMIDLIST pidlDest, UINT cItems, HDPA hdpaItems, BOOL* fThumbWritten)
  463. {
  464. HRESULT hr = E_FAIL;
  465. ASSERTMSG(pidlDest != NULL && fThumbWritten != NULL, "CPreviewWnd::_CopyThumbnails -- invalid params to internal function");
  466. WCHAR pwszDestPath[MAX_PATH];
  467. hr = SHGetNameAndFlags(pidlDest, SHGDN_FORPARSING, pwszDestPath, ARRAYSIZE(pwszDestPath), NULL);
  468. *fThumbWritten = FALSE;
  469. WCHAR wszMsgBox[128];
  470. WCHAR wszMsgBoxTitle[64];
  471. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_MSGBOX, wszMsgBox, ARRAYSIZE(wszMsgBox));
  472. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_MSGBOXTITLE, wszMsgBoxTitle, ARRAYSIZE(wszMsgBoxTitle));
  473. hr = S_OK;
  474. if (IDYES == MessageBox(wszMsgBox, wszMsgBoxTitle, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1 | MB_APPLMODAL))
  475. {
  476. *fThumbWritten = TRUE;
  477. IProgressDialog* pProgress;
  478. WCHAR wszProgressText[64];
  479. hr = E_FAIL;
  480. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_PROGRESSTEXT, wszProgressText, ARRAYSIZE(wszProgressText));
  481. hr = _CopyImages_SetupProgress(&pProgress, wszProgressText);
  482. if (SUCCEEDED(hr))
  483. {
  484. IShellImageDataFactory * pImgFact;
  485. hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellImageDataFactory, &pImgFact));
  486. if (SUCCEEDED(hr))
  487. {
  488. for (UINT i = 0; (i < cItems) && SUCCEEDED(hr) && !pProgress->HasUserCancelled(); i++)
  489. {
  490. LPITEMIDLIST pidl = (LPITEMIDLIST)DPA_GetPtr(hdpaItems, i);
  491. WCHAR wszFullName[MAX_PATH];
  492. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, wszFullName, ARRAYSIZE(wszFullName), NULL);
  493. if (SUCCEEDED(hr))
  494. {
  495. IShellImageData* pImage;
  496. hr = pImgFact->CreateImageFromFile(wszFullName, &pImage);
  497. if (SUCCEEDED(hr))
  498. {
  499. SIZE size;
  500. hr = pImage->Decode(SHIMGDEC_DEFAULT, 0, 0);
  501. if (SUCCEEDED(hr))
  502. {
  503. hr = pImage->GetSize(&size);
  504. if (SUCCEEDED(hr))
  505. {
  506. if (size.cx > size.cy)
  507. {
  508. hr = pImage->Scale(100, 0, InterpolationModeDefault);
  509. }
  510. else
  511. {
  512. hr = pImage->Scale(0, 100, InterpolationModeDefault);
  513. }
  514. if (SUCCEEDED(hr))
  515. {
  516. // save the file
  517. IPersistFile *ppfImg;
  518. hr = pImage->QueryInterface(IID_PPV_ARG(IPersistFile, &ppfImg));
  519. if (SUCCEEDED(hr))
  520. {
  521. hr = E_FAIL;
  522. LPWSTR pwszFileName = PathFindFileName(wszFullName);
  523. if (pwszFileName)
  524. {
  525. memmove(wszFullName, pwszFileName, sizeof(WCHAR) * (1+ lstrlenW(pwszFileName)));
  526. TCHAR szThumbSuffix[20];
  527. LoadString(_Module.GetModuleInstance(), IDS_THUMBNAIL_SUFFIX, szThumbSuffix, ARRAYSIZE(szThumbSuffix));
  528. hr = _AddSuffix(szThumbSuffix, wszFullName, ARRAYSIZE(wszFullName));
  529. if (SUCCEEDED(hr))
  530. {
  531. WCHAR wszFileName[MAX_PATH];
  532. if (PathCombine(wszFileName, pwszDestPath, wszFullName))
  533. {
  534. pProgress->SetLine(1, wszFileName, TRUE, NULL); // ignore progress errors
  535. hr = ppfImg->Save(wszFileName, TRUE);
  536. pProgress->SetProgress(i, cItems); // ignore progress errors
  537. }
  538. }
  539. }
  540. ppfImg->Release();
  541. }
  542. }
  543. }
  544. }
  545. pImage->Release();
  546. }
  547. }
  548. }
  549. pImgFact->Release();
  550. }
  551. pProgress->StopProgressDialog();
  552. pProgress->Release();
  553. }
  554. }
  555. return hr;
  556. }