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.

390 lines
13 KiB

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