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.

509 lines
13 KiB

  1. #include "precomp.h"
  2. #include "tasks.h"
  3. #include "prevwnd.h"
  4. void DeleteBuffer(Buffer * pBuf)
  5. {
  6. if (pBuf)
  7. {
  8. if (pBuf->hbmOld)
  9. SelectObject(pBuf->hdc, pBuf->hbmOld);
  10. if (pBuf->hPalOld)
  11. SelectPalette(pBuf->hdc, pBuf->hPalOld, FALSE);
  12. if (pBuf->hbm)
  13. DeleteObject(pBuf->hbm);
  14. if (pBuf->hPal)
  15. DeleteObject(pBuf->hPal);
  16. if (pBuf->hdc)
  17. DeleteDC(pBuf->hdc);
  18. delete pBuf;
  19. }
  20. }
  21. ////////////////////////////////////////////////////////////////////////////
  22. //
  23. // CDecodeTask
  24. //
  25. ////////////////////////////////////////////////////////////////////////////
  26. CDecodeTask::CDecodeTask() : CRunnableTask(RTF_DEFAULT)
  27. {
  28. InitializeCriticalSection(&_cs);
  29. };
  30. CDecodeTask::~CDecodeTask()
  31. {
  32. ATOMICRELEASE(_pstrm);
  33. ATOMICRELEASE(_pfactory);
  34. if (_pszFilename)
  35. LocalFree(_pszFilename);
  36. ATOMICRELEASE(_pSID);
  37. DeleteCriticalSection(&_cs);
  38. if (_ppi)
  39. delete [] _ppi;
  40. }
  41. HRESULT CDecodeTask::Create(IStream * pstrm, LPCWSTR pszFilename, UINT iItem, IShellImageDataFactory * pFactory, HWND hwnd, IRunnableTask ** ppTask)
  42. {
  43. *ppTask = NULL;
  44. CDecodeTask * pTask = new CDecodeTask();
  45. if (!pTask)
  46. return E_OUTOFMEMORY;
  47. HRESULT hr = pTask->_Initialize(pstrm, pszFilename, iItem, pFactory, hwnd);
  48. if (SUCCEEDED(hr))
  49. {
  50. *ppTask = (IRunnableTask*)pTask;
  51. }
  52. else
  53. {
  54. pTask->Release();
  55. }
  56. return hr;
  57. }
  58. HRESULT CDecodeTask::_Initialize(IStream *pstrm, LPCWSTR pszFilename, UINT iItem, IShellImageDataFactory *pFactory, HWND hwnd)
  59. {
  60. if (pstrm)
  61. {
  62. STATSTG stat;
  63. if (SUCCEEDED(pstrm->Stat(&stat, 0)))
  64. {
  65. _pszFilename = StrDup(stat.pwcsName);
  66. _fIsReadOnly = !(stat.grfMode & STGM_WRITE);
  67. CoTaskMemFree(stat.pwcsName);
  68. }
  69. _pstrm = pstrm;
  70. _pstrm->AddRef();
  71. }
  72. else
  73. {
  74. _pszFilename = StrDup(pszFilename);
  75. if (!_pszFilename)
  76. return E_OUTOFMEMORY;
  77. }
  78. if (!_pstrm && _pszFilename)
  79. {
  80. SHGetFileInfo(_pszFilename, 0, &_sfi, sizeof(_sfi), SHGFI_DISPLAYNAME | SHGFI_USEFILEATTRIBUTES);
  81. }
  82. else
  83. {
  84. ZeroMemory(&_sfi, sizeof(_sfi));
  85. }
  86. _pfactory = pFactory;
  87. _pfactory->AddRef();
  88. _hwndNotify = hwnd;
  89. _iItem = iItem;
  90. return S_OK;
  91. }
  92. HRESULT CDecodeTask::RunInitRT()
  93. {
  94. HRESULT hr;
  95. EnterCriticalSection(&_cs);
  96. if (_pstrm)
  97. {
  98. hr = _pfactory->CreateImageFromStream(_pstrm, &_pSID);
  99. }
  100. else
  101. {
  102. hr = _pfactory->CreateImageFromFile(_pszFilename, &_pSID);
  103. _fIsReadOnly = (GetFileAttributes(_pszFilename) & FILE_ATTRIBUTE_READONLY);
  104. }
  105. if (SUCCEEDED(hr))
  106. {
  107. hr = _pSID->Decode(SHIMGDEC_LOADFULL,0,0);
  108. if (SUCCEEDED(hr))
  109. {
  110. _pSID->GetPageCount(&_cImages);
  111. _ppi = new PageInfo[_cImages];
  112. if (_ppi)
  113. {
  114. _iCurrent = 0;
  115. _fAnimated = (S_OK == _pSID->IsAnimated());
  116. _fEditable = (S_OK == _pSID->IsEditable());
  117. PixelFormat pf;
  118. _pSID->GetPixelFormat(&pf);
  119. _fExtendedPF = IsExtendedPixelFormat(pf);
  120. _pSID->GetRawDataFormat(&_guidFormat);
  121. for (ULONG i = 0; i < _cImages; i++)
  122. {
  123. _pSID->SelectPage(i); // this works for animated and multipage
  124. _pSID->GetSize(&_ppi[i].szImage);
  125. _pSID->GetResolution(&_ppi[i].xDPI, &_ppi[i].yDPI);
  126. if (_fAnimated)
  127. _pSID->GetDelay(&_ppi[i].dwDelay);
  128. }
  129. }
  130. else
  131. hr = E_OUTOFMEMORY;
  132. }
  133. if (FAILED(hr))
  134. {
  135. ATOMICRELEASE(_pSID);
  136. }
  137. }
  138. LeaveCriticalSection(&_cs);
  139. AddRef();
  140. _hr = hr;
  141. if (!PostMessage(_hwndNotify, IV_SETIMAGEDATA, (WPARAM)this, NULL))
  142. {
  143. Release();
  144. }
  145. return S_OK;
  146. }
  147. BOOL CDecodeTask::GetSize(SIZE * psz)
  148. {
  149. if (!_ppi)
  150. return FALSE;
  151. *psz = _ppi[_iCurrent].szImage;
  152. return TRUE;
  153. }
  154. BOOL CDecodeTask::GetResolution(ULONG * px, ULONG * py)
  155. {
  156. if (!_ppi)
  157. return FALSE;
  158. *px = _ppi[_iCurrent].xDPI;
  159. *py = _ppi[_iCurrent].yDPI;
  160. return TRUE;
  161. }
  162. DWORD CDecodeTask::GetDelay()
  163. {
  164. if (!_ppi)
  165. return 0;
  166. return _ppi[_iCurrent].dwDelay;
  167. }
  168. BOOL CDecodeTask::NextPage()
  169. {
  170. if (_iCurrent >= _cImages-1)
  171. return FALSE;
  172. _iCurrent++;
  173. return TRUE;
  174. }
  175. BOOL CDecodeTask::PrevPage()
  176. {
  177. if (_iCurrent == 0)
  178. return FALSE;
  179. _iCurrent--;
  180. return TRUE;
  181. }
  182. BOOL CDecodeTask::NextFrame()
  183. {
  184. EnterCriticalSection(&_cs);
  185. HRESULT hr = _pSID->NextFrame();
  186. LeaveCriticalSection(&_cs);
  187. if (S_OK==hr)
  188. {
  189. _iCurrent = (_iCurrent+1) % _cImages;
  190. }
  191. return (S_OK == hr);
  192. }
  193. BOOL CDecodeTask::SelectPage(ULONG nPage)
  194. {
  195. if (nPage >= _cImages)
  196. return FALSE;
  197. _iCurrent = nPage;
  198. return TRUE;
  199. }
  200. BOOL CDecodeTask::ChangePage(CAnnotationSet& Annotations)
  201. {
  202. BOOL bResult = FALSE;
  203. EnterCriticalSection(&_cs);
  204. HRESULT hr = _pSID->SelectPage(_iCurrent);
  205. if (SUCCEEDED(hr))
  206. {
  207. // If we are moving onto a page that was previously rotated
  208. // but not saved then our cached size and resolution will be wrong
  209. _pSID->GetSize(&_ppi[_iCurrent].szImage);
  210. _pSID->GetResolution(&_ppi[_iCurrent].xDPI, &_ppi[_iCurrent].yDPI);
  211. Annotations.SetImageData(_pSID);
  212. bResult = TRUE;
  213. }
  214. LeaveCriticalSection(&_cs);
  215. return bResult;
  216. }
  217. HRESULT CDecodeTask::Rotate(DWORD dwAngle)
  218. {
  219. HRESULT hr;
  220. EnterCriticalSection(&_cs);
  221. hr = _pSID->Rotate(dwAngle);
  222. if (SUCCEEDED(hr))
  223. {
  224. ULONG dwTmp = _ppi[_iCurrent].szImage.cx;
  225. _ppi[_iCurrent].szImage.cx = _ppi[_iCurrent].szImage.cy;
  226. _ppi[_iCurrent].szImage.cy = dwTmp;
  227. if (dwAngle == 90 || dwAngle == 270)
  228. {
  229. dwTmp = _ppi[_iCurrent].xDPI;
  230. _ppi[_iCurrent].xDPI =_ppi[_iCurrent].yDPI;
  231. _ppi[_iCurrent].yDPI = dwTmp;
  232. }
  233. }
  234. LeaveCriticalSection(&_cs);
  235. return hr;
  236. }
  237. HRESULT CDecodeTask::Lock(IShellImageData ** ppSID)
  238. {
  239. if (_pSID)
  240. {
  241. EnterCriticalSection(&_cs);
  242. *ppSID = _pSID;
  243. return S_OK;
  244. }
  245. *ppSID = NULL;
  246. return E_FAIL;
  247. }
  248. HRESULT CDecodeTask::Unlock()
  249. {
  250. LeaveCriticalSection(&_cs);
  251. return S_OK;
  252. }
  253. BOOL CDecodeTask::DisplayName(LPTSTR psz, UINT cch)
  254. {
  255. // TODO: Just call the _pSID->DisplayName
  256. if (_sfi.szDisplayName[0])
  257. {
  258. StrCpyN(psz, _sfi.szDisplayName, cch);
  259. return TRUE;
  260. }
  261. return FALSE;
  262. }
  263. ////////////////////////////////////////////////////////////////////////////
  264. //
  265. // CDrawTask
  266. //
  267. ////////////////////////////////////////////////////////////////////////////
  268. CDrawTask::CDrawTask() : CRunnableTask(RTF_SUPPORTKILLSUSPEND)
  269. {
  270. }
  271. CDrawTask::~CDrawTask()
  272. {
  273. if (_pImgData)
  274. _pImgData->Release();
  275. // DeleteBuffer is going to check for NULL anyway
  276. DeleteBuffer(_pBuf);
  277. }
  278. HRESULT CDrawTask::QueryInterface(REFIID riid, LPVOID * ppvObj)
  279. {
  280. if (riid == IID_IShellImageDataAbort)
  281. {
  282. *ppvObj = static_cast<IShellImageDataAbort*>(this);
  283. AddRef();
  284. return S_OK;
  285. }
  286. return CRunnableTask::QueryInterface(riid, ppvObj);
  287. }
  288. HRESULT CDrawTask::Create(CDecodeTask * pImageData, COLORREF clr, RECT & rcSrc, RECT & rcDest, HWND hwnd, ULONG uMsg, IRunnableTask ** ppTask)
  289. {
  290. *ppTask = NULL;
  291. CDrawTask * pTask = new CDrawTask();
  292. if (!pTask)
  293. return E_OUTOFMEMORY;
  294. HRESULT hr = pTask->_Initialize(pImageData, clr, rcSrc, rcDest, hwnd, uMsg);
  295. if (SUCCEEDED(hr))
  296. {
  297. *ppTask = (IRunnableTask*)pTask;
  298. }
  299. else
  300. {
  301. pTask->Release();
  302. }
  303. return hr;
  304. }
  305. HRESULT CDrawTask::_Initialize(CDecodeTask * pImageData, COLORREF clr, RECT & rcSrc, RECT & rcDest, HWND hwnd, ULONG uMsg)
  306. {
  307. _pImgData = pImageData;
  308. _pImgData->AddRef();
  309. _dwPage = _pImgData->_iCurrent;
  310. _clrBkgnd = clr;
  311. _rcSrc = rcSrc;
  312. _hwndNotify = hwnd;
  313. _uMsgNotify = uMsg;
  314. _pBuf = new Buffer;
  315. if (!_pBuf)
  316. return E_OUTOFMEMORY;
  317. _pBuf->rc = rcDest;
  318. _pBuf->hPal = NULL;
  319. return S_OK;
  320. }
  321. typedef RGBQUAD RGBQUAD8[256];
  322. HBITMAP _CreateBitmap(HDC hdcWnd, Buffer *pBuf, SIZE *pSize)
  323. {
  324. int bpp = GetDeviceCaps(hdcWnd, BITSPIXEL);
  325. HBITMAP hbm = NULL;
  326. if (8==bpp)
  327. {
  328. PVOID pvBits = NULL;
  329. struct
  330. {
  331. BITMAPINFOHEADER bmih;
  332. RGBQUAD8 rgbquad8;
  333. } bmi;
  334. bmi.bmih.biSize = sizeof(bmi.bmih);
  335. bmi.bmih.biWidth = (int)pSize->cx;
  336. bmi.bmih.biHeight = (int)pSize->cy;
  337. bmi.bmih.biPlanes = 1;
  338. bmi.bmih.biBitCount = 8;
  339. bmi.bmih.biCompression = BI_RGB;
  340. bmi.bmih.biSizeImage = 0;
  341. bmi.bmih.biXPelsPerMeter = 0;
  342. bmi.bmih.biYPelsPerMeter = 0;
  343. bmi.bmih.biClrUsed = 0; // only used for <= 16bpp
  344. bmi.bmih.biClrImportant = 0;
  345. //
  346. // Use the halftone palette
  347. //
  348. pBuf->hPal = DllExports::GdipCreateHalftonePalette();
  349. pBuf->hPalOld = SelectPalette(pBuf->hdc, pBuf->hPal, FALSE);
  350. BYTE aj[sizeof(PALETTEENTRY) * 256];
  351. LPPALETTEENTRY lppe = (LPPALETTEENTRY) aj;
  352. RGBQUAD *prgb = (RGBQUAD *) &bmi.rgbquad8;
  353. if (GetPaletteEntries(pBuf->hPal, 0, 256, lppe))
  354. {
  355. UINT i;
  356. for (i = 0; i < 256; i++)
  357. {
  358. prgb[i].rgbRed = lppe[i].peRed;
  359. prgb[i].rgbGreen = lppe[i].peGreen;
  360. prgb[i].rgbBlue = lppe[i].peBlue;
  361. prgb[i].rgbReserved = 0;
  362. }
  363. }
  364. hbm = CreateDIBSection(hdcWnd,(BITMAPINFO*)&bmi,DIB_RGB_COLORS,&pvBits,NULL,0);
  365. }
  366. else
  367. {
  368. hbm = CreateCompatibleBitmap(hdcWnd,pSize->cx, pSize->cy);
  369. }
  370. return hbm;
  371. }
  372. HRESULT CDrawTask::InternalResumeRT()
  373. {
  374. HRESULT hr = E_FAIL;
  375. HDC hdcScreen = GetDC(NULL);
  376. if (!_pBuf->hdc)
  377. {
  378. _pBuf->hdc = CreateCompatibleDC(hdcScreen);
  379. }
  380. if (_pBuf->hdc)
  381. {
  382. SIZE sz = {RECTWIDTH(_pBuf->rc), RECTHEIGHT(_pBuf->rc)};
  383. // If we were suspended and resumed, we will already have
  384. // a GDI bitmap from last time so don't make another one.
  385. if (!_pBuf->hbm)
  386. {
  387. BITMAP bm = {0};
  388. _pBuf->hbm = _CreateBitmap(hdcScreen, _pBuf, &sz);
  389. _pBuf->hbmOld = (HBITMAP)SelectObject(_pBuf->hdc, _pBuf->hbm);
  390. }
  391. if (_pBuf->hbm)
  392. {
  393. RECT rc = {0,0,sz.cx, sz.cy};
  394. SetBkColor(_pBuf->hdc, _clrBkgnd);
  395. ExtTextOut(_pBuf->hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  396. IShellImageData * pSID;
  397. if (SUCCEEDED(_pImgData->Lock(&pSID)))
  398. {
  399. pSID->SelectPage(_dwPage);
  400. IShellImageDataAbort *pAbortPrev = NULL;
  401. pSID->RegisterAbort(this, &pAbortPrev);
  402. hr = pSID->Draw(_pBuf->hdc, &rc, &_rcSrc);
  403. pSID->RegisterAbort(pAbortPrev, NULL);
  404. _pImgData->Unlock();
  405. }
  406. }
  407. }
  408. if (hdcScreen)
  409. {
  410. ReleaseDC(NULL, hdcScreen);
  411. }
  412. if (QueryAbort() == S_FALSE)
  413. {
  414. // We were cancelled or suspended, so don't notify our parent
  415. // because we have nothing to show for our efforts.
  416. hr = (_lState == IRTIR_TASK_SUSPENDED) ? E_PENDING : E_FAIL;
  417. }
  418. else
  419. {
  420. // Ran to completion - clean up and notify main thread
  421. UINT iIndex = _pImgData->_iItem;
  422. ATOMICRELEASE(_pImgData);
  423. if (FAILED(hr))
  424. {
  425. DeleteBuffer(_pBuf);
  426. _pBuf = NULL;
  427. }
  428. if (PostMessage(_hwndNotify, _uMsgNotify, (WPARAM)_pBuf, (LPARAM)IntToPtr(iIndex)))
  429. {
  430. _pBuf = NULL;
  431. }
  432. hr = S_OK;
  433. }
  434. return hr;
  435. }
  436. HRESULT CDrawTask::QueryAbort()
  437. {
  438. // BUGBUG not rady for prime tome - need to return E_PENDING
  439. // if state is SUSPENDED
  440. if (WaitForSingleObject(_hDone, 0) == WAIT_OBJECT_0)
  441. {
  442. return S_FALSE; // Abort
  443. }
  444. return S_OK;
  445. }