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.

385 lines
12 KiB

  1. #include "precomp.h"
  2. #include "thumbutil.h"
  3. HRESULT GetMediaManagerThumbnail(IPropertyStorage * pPropStg, const SIZE * prgSize,
  4. DWORD dwClrDepth, HPALETTE hpal, BOOL fOrigSize,
  5. HBITMAP * phBmpThumbnail);
  6. HRESULT GetDocFileThumbnail(IPropertyStorage * pPropStg, const SIZE * prgSize,
  7. DWORD dwClrDepth, HPALETTE hpal, BOOL fOrigSize,
  8. HBITMAP * phBmpThumbnail);
  9. // PACKEDMETA struct for DocFile thumbnails.
  10. typedef struct
  11. {
  12. WORD mm;
  13. WORD xExt;
  14. WORD yExt;
  15. WORD dummy;
  16. } PACKEDMETA;
  17. VOID CalcMetaFileSize(HDC hDC, PACKEDMETA * pMeta, const SIZEL * prgSize, RECT * pRect);
  18. CDocFileThumb::CDocFileThumb()
  19. {
  20. m_pszPath = NULL;
  21. }
  22. CDocFileThumb::~CDocFileThumb()
  23. {
  24. LocalFree(m_pszPath); // accepts NULL
  25. }
  26. STDMETHODIMP CDocFileThumb::GetLocation(LPWSTR pszFileName, DWORD cchMax,
  27. DWORD * pdwPriority, const SIZE * prgSize,
  28. DWORD dwRecClrDepth, DWORD *pdwFlags)
  29. {
  30. if (!m_pszPath)
  31. return E_UNEXPECTED;
  32. m_rgSize = *prgSize;
  33. m_dwRecClrDepth = dwRecClrDepth;
  34. // just copy the current path into the buffer as we do not share thumbnails...
  35. StrCpyNW(pszFileName, m_pszPath, cchMax);
  36. HRESULT hr = S_OK;
  37. if (*pdwFlags & IEIFLAG_ASYNC)
  38. {
  39. // we support async
  40. hr = E_PENDING;
  41. *pdwPriority = PRIORITY_EXTRACT_NORMAL;
  42. }
  43. m_fOrigSize = BOOLIFY(*pdwFlags & IEIFLAG_ORIGSIZE);
  44. // we don't want it cached....
  45. *pdwFlags &= ~IEIFLAG_CACHE;
  46. return hr;
  47. }
  48. HPALETTE PaletteFromClrDepth(DWORD dwRecClrDepth)
  49. {
  50. HPALETTE hpal = NULL;
  51. if (dwRecClrDepth == 8)
  52. {
  53. hpal = SHCreateShellPalette(NULL);
  54. }
  55. else if (dwRecClrDepth < 8)
  56. {
  57. hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
  58. }
  59. return hpal;
  60. }
  61. STDMETHODIMP CDocFileThumb::Extract(HBITMAP * phBmpThumbnail)
  62. {
  63. if (!m_pszPath)
  64. return E_UNEXPECTED;
  65. IStorage *pstg;
  66. HRESULT hr = StgOpenStorage(m_pszPath, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, NULL, &pstg);
  67. if (SUCCEEDED(hr))
  68. {
  69. IPropertySetStorage *pPropSetStg;
  70. hr = pstg->QueryInterface(IID_PPV_ARG(IPropertySetStorage, &pPropSetStg));
  71. if (SUCCEEDED(hr))
  72. {
  73. // "MIC" Microsoft Image Composer files needs special casing because they use
  74. // the Media Manager internal thumbnail propertyset ... (by what it would be like
  75. // to be standard for once ....)
  76. FMTID fmtidPropSet = StrCmpIW(PathFindExtensionW(m_pszPath), L".MIC") ?
  77. FMTID_SummaryInformation : FMTID_CmsThumbnailPropertySet;
  78. IPropertyStorage *pPropSet;
  79. hr = pPropSetStg->Open(fmtidPropSet, STGM_READ | STGM_SHARE_EXCLUSIVE, &pPropSet);
  80. if (SUCCEEDED(hr))
  81. {
  82. HPALETTE hpal = PaletteFromClrDepth(m_dwRecClrDepth);
  83. if (FMTID_CmsThumbnailPropertySet == fmtidPropSet)
  84. {
  85. hr = GetMediaManagerThumbnail(pPropSet, &m_rgSize, m_dwRecClrDepth, hpal, m_fOrigSize, phBmpThumbnail);
  86. }
  87. else
  88. {
  89. hr = GetDocFileThumbnail(pPropSet, &m_rgSize, m_dwRecClrDepth, hpal, m_fOrigSize, phBmpThumbnail);
  90. }
  91. if (hpal)
  92. DeleteObject(hpal);
  93. pPropSet->Release();
  94. }
  95. pPropSetStg->Release();
  96. }
  97. pstg->Release();
  98. }
  99. return hr;
  100. }
  101. STDMETHODIMP CDocFileThumb::Load(LPCOLESTR pszFileName, DWORD dwMode)
  102. {
  103. LocalFree(m_pszPath);
  104. return SHStrDup(pszFileName, &m_pszPath);
  105. }
  106. HRESULT GetMediaManagerThumbnail(IPropertyStorage * pPropStg,
  107. const SIZE * prgSize, DWORD dwClrDepth,
  108. HPALETTE hpal, BOOL fOrigSize, HBITMAP * phBmpThumbnail)
  109. {
  110. // current version of media manager simply stores the DIB data in a under a
  111. // named property Thumbnail...
  112. // read the thumbnail property from the property storage.
  113. PROPVARIANT pvarResult = {0};
  114. PROPSPEC propSpec;
  115. propSpec.ulKind = PRSPEC_LPWSTR;
  116. propSpec.lpwstr = L"Thumbnail";
  117. HRESULT hr = pPropStg->ReadMultiple(1, &propSpec, &pvarResult);
  118. if (SUCCEEDED(hr))
  119. {
  120. BITMAPINFO * pbi = (BITMAPINFO *)pvarResult.blob.pBlobData;
  121. void *pBits = CalcBitsOffsetInDIB(pbi);
  122. hr = E_FAIL;
  123. if (pbi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
  124. {
  125. if (ConvertDIBSECTIONToThumbnail(pbi, pBits, phBmpThumbnail, prgSize, dwClrDepth, hpal, 15, fOrigSize))
  126. {
  127. hr = S_OK;
  128. }
  129. }
  130. PropVariantClear(&pvarResult);
  131. }
  132. return hr;
  133. }
  134. HRESULT GetDocFileThumbnail(IPropertyStorage * pPropStg,
  135. const SIZE * prgSize, DWORD dwClrDepth,
  136. HPALETTE hpal, BOOL fOrigSize, HBITMAP * phBmpThumbnail)
  137. {
  138. HRESULT hr;
  139. HDC hDC = GetDC(NULL);
  140. HDC hMemDC = CreateCompatibleDC(hDC);
  141. if (hMemDC)
  142. {
  143. HBITMAP hBmp = NULL;
  144. PROPSPEC propSpec;
  145. PROPVARIANT pvarResult = {0};
  146. // read the thumbnail property from the property storage.
  147. propSpec.ulKind = PRSPEC_PROPID;
  148. propSpec.propid = PIDSI_THUMBNAIL;
  149. hr = pPropStg->ReadMultiple(1, &propSpec, &pvarResult);
  150. if (SUCCEEDED(hr))
  151. {
  152. // assume something is going to go terribly wrong
  153. hr = E_FAIL;
  154. // make sure we are dealing with a clipboard format. CLIPDATA
  155. if ((pvarResult.vt == VT_CF) && (pvarResult.pclipdata->ulClipFmt == -1))
  156. {
  157. LPDWORD pdwCF = (DWORD *)pvarResult.pclipdata->pClipData;
  158. LPBYTE pStruct = pvarResult.pclipdata->pClipData + sizeof(DWORD);
  159. if (*pdwCF == CF_METAFILEPICT)
  160. {
  161. SetMapMode(hMemDC, MM_TEXT);
  162. // handle thumbnail that is a metafile.
  163. PACKEDMETA * pMeta = (PACKEDMETA *)pStruct;
  164. LPBYTE pData = pStruct + sizeof(PACKEDMETA);
  165. RECT rect;
  166. UINT cbSize = pvarResult.pclipdata->cbSize - sizeof(DWORD) - sizeof(pMeta->mm) -
  167. sizeof(pMeta->xExt) - sizeof(pMeta->yExt) - sizeof(pMeta->dummy);
  168. // save as a metafile.
  169. HMETAFILE hMF = SetMetaFileBitsEx(cbSize, pData);
  170. if (hMF)
  171. {
  172. SIZE rgNewSize;
  173. // use the mapping mode to calc the current size
  174. CalcMetaFileSize(hMemDC, pMeta, prgSize, & rect);
  175. CalculateAspectRatio(prgSize, &rect);
  176. if (fOrigSize)
  177. {
  178. // use the aspect rect to refigure the size...
  179. rgNewSize.cx = rect.right - rect.left;
  180. rgNewSize.cy = rect.bottom - rect.top;
  181. prgSize = &rgNewSize;
  182. // adjust the rect to be the same as the size (which is the size of the metafile)
  183. rect.right -= rect.left;
  184. rect.bottom -= rect.top;
  185. rect.left = 0;
  186. rect.top = 0;
  187. }
  188. if (CreateSizedDIBSECTION(prgSize, dwClrDepth, hpal, NULL, &hBmp, NULL, NULL))
  189. {
  190. HGDIOBJ hOldBmp = SelectObject(hMemDC, hBmp);
  191. HGDIOBJ hBrush = GetStockObject(WHITE_BRUSH);
  192. HGDIOBJ hOldBrush = SelectObject(hMemDC, hBrush);
  193. HGDIOBJ hPen = GetStockObject(WHITE_PEN);
  194. HGDIOBJ hOldPen = SelectObject(hMemDC, hPen);
  195. Rectangle(hMemDC, 0, 0, prgSize->cx, prgSize->cy);
  196. SelectObject(hMemDC, hOldBrush);
  197. SelectObject(hMemDC, hOldPen);
  198. int iXBorder = 0;
  199. int iYBorder = 0;
  200. if (rect.left == 0)
  201. {
  202. iXBorder ++;
  203. }
  204. if (rect.top == 0)
  205. {
  206. iYBorder ++;
  207. }
  208. SetViewportExtEx(hMemDC, rect.right - rect.left - 2 * iXBorder, rect.bottom - rect.top - 2 * iYBorder, NULL);
  209. SetViewportOrgEx(hMemDC, rect.left + iXBorder, rect.top + iYBorder, NULL);
  210. SetMapMode(hMemDC, pMeta->mm);
  211. // play the metafile.
  212. BOOL bRet = PlayMetaFile(hMemDC, hMF);
  213. if (bRet)
  214. {
  215. *phBmpThumbnail = hBmp;
  216. if (*phBmpThumbnail)
  217. {
  218. // we got the thumbnail bitmap, return success.
  219. hr = S_OK;
  220. }
  221. }
  222. DeleteMetaFile(hMF);
  223. SelectObject(hMemDC, hOldBmp);
  224. if (FAILED(hr) && hBmp)
  225. {
  226. DeleteObject(hBmp);
  227. }
  228. }
  229. else
  230. {
  231. hr = DV_E_CLIPFORMAT;
  232. }
  233. }
  234. }
  235. else if (*pdwCF == CF_DIB)
  236. {
  237. // handle thumbnail that is a bitmap.
  238. BITMAPINFO * pDib = (BITMAPINFO *) pStruct;
  239. if (pDib->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
  240. {
  241. void *pBits = CalcBitsOffsetInDIB(pDib);
  242. if (ConvertDIBSECTIONToThumbnail(pDib, pBits, phBmpThumbnail, prgSize, dwClrDepth, hpal, 15, fOrigSize))
  243. {
  244. hr = S_OK;
  245. }
  246. else
  247. {
  248. hr = DV_E_CLIPFORMAT;
  249. }
  250. }
  251. }
  252. else
  253. {
  254. hr = DV_E_CLIPFORMAT;
  255. }
  256. }
  257. else
  258. {
  259. hr = DV_E_CLIPFORMAT;
  260. }
  261. PropVariantClear(&pvarResult);
  262. }
  263. DeleteDC(hMemDC);
  264. }
  265. else
  266. {
  267. hr = E_OUTOFMEMORY;
  268. }
  269. ReleaseDC(NULL, hDC);
  270. return hr;
  271. }
  272. VOID CalcMetaFileSize(HDC hDC, PACKEDMETA * prgMeta, const SIZEL * prgSize, RECT * prgRect)
  273. {
  274. ASSERT(prgMeta && prgRect);
  275. prgRect->left = 0;
  276. prgRect->top = 0;
  277. if (!prgMeta->xExt || !prgMeta->yExt)
  278. {
  279. // no size, then just use the size rect ...
  280. prgRect->right = prgSize->cx;
  281. prgRect->bottom = prgSize->cy;
  282. }
  283. else
  284. {
  285. // set the mapping mode....
  286. SetMapMode(hDC, prgMeta->mm);
  287. if (prgMeta->mm == MM_ISOTROPIC || prgMeta->mm == MM_ANISOTROPIC)
  288. {
  289. // we must set the ViewPortExtent and the window extent to get the scaling
  290. SetWindowExtEx(hDC, prgMeta->xExt, prgMeta->yExt, NULL);
  291. SetViewportExtEx(hDC, prgMeta->xExt, prgMeta->yExt, NULL);
  292. }
  293. POINT pt;
  294. pt.x = prgMeta->xExt;
  295. pt.y = prgMeta->yExt;
  296. // convert to pixels....
  297. LPtoDP(hDC, &pt, 1);
  298. prgRect->right = abs(pt.x);
  299. prgRect->bottom = abs(pt.y);
  300. }
  301. }
  302. STDMETHODIMP CDocFileThumb::GetClassID(CLSID * pCLSID)
  303. {
  304. return E_NOTIMPL;
  305. }
  306. STDMETHODIMP CDocFileThumb::IsDirty()
  307. {
  308. return S_FALSE;
  309. }
  310. STDMETHODIMP CDocFileThumb::Save(LPCOLESTR pszFileName, BOOL fRemember)
  311. {
  312. return E_NOTIMPL;
  313. }
  314. STDMETHODIMP CDocFileThumb::SaveCompleted(LPCOLESTR pszFileName)
  315. {
  316. return E_NOTIMPL;
  317. }
  318. STDMETHODIMP CDocFileThumb::GetCurFile(LPOLESTR * ppszFileName)
  319. {
  320. return E_NOTIMPL;
  321. }