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.

372 lines
11 KiB

  1. #include "shellprv.h"
  2. #include "runtask.h"
  3. #include "prop.h"
  4. #include "thumbutil.h"
  5. #include <cowsite.h>
  6. static const GUID TOID_Thumbnail = { 0xadec3450, 0xe907, 0x11d0, {0xa5, 0x7b, 0x00, 0xc0, 0x4f, 0xc2, 0xf7, 0x6a} };
  7. class CThumbnail : public IThumbnail2, public IParentAndItem, public CObjectWithSite
  8. {
  9. public:
  10. CThumbnail(void);
  11. // IUnknown
  12. STDMETHODIMP_(ULONG) AddRef(void);
  13. STDMETHODIMP_(ULONG) Release(void);
  14. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  15. // IThumbnail
  16. STDMETHODIMP Init(HWND hwnd, UINT uMsg);
  17. STDMETHODIMP GetBitmap(LPCWSTR pszFile, DWORD dwItem, LONG lWidth, LONG lHeight);
  18. // IThumbnail2
  19. STDMETHODIMP GetBitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight);
  20. // IParentAndItem
  21. STDMETHODIMP SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild);
  22. STDMETHODIMP GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidlChild);
  23. private:
  24. ~CThumbnail(void);
  25. HRESULT _CreateTask(IShellFolder *psf, LPCITEMIDLIST pidlLast, DWORD dwItem, SIZE rgSize, IExtractImage *pei, IRunnableTask **pprt);
  26. HRESULT _BitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight);
  27. HRESULT _InitTaskCancelItems();
  28. LONG _cRef;
  29. HWND _hwnd;
  30. UINT _uMsg;
  31. IShellTaskScheduler *_pScheduler;
  32. IShellFolder *_psf;
  33. LPITEMIDLIST _pidl;
  34. };
  35. class CGetThumbnailTask : public CRunnableTask
  36. {
  37. public:
  38. CGetThumbnailTask(IShellFolder *psf, LPCITEMIDLIST pidl, IExtractImage *pei, HWND hwnd, UINT uMsg, DWORD dwItem, SIZE rgSize);
  39. STDMETHODIMP RunInitRT(void);
  40. private:
  41. ~CGetThumbnailTask();
  42. HRESULT _PrepImage(HBITMAP *phBmp);
  43. HRESULT _BitmapReady(HBITMAP hImage);
  44. IShellFolder *_psf;
  45. IExtractImage *_pei;
  46. HWND _hwnd;
  47. UINT _uMsg;
  48. DWORD _dwItem;
  49. SIZE _rgSize;
  50. LPITEMIDLIST _pidlFolder; // folder where we test the cache
  51. LPITEMIDLIST _pidlLast;
  52. WCHAR _szPath[MAX_PATH]; // the item in that in folder parsing name for cache test
  53. };
  54. CThumbnail::CThumbnail(void) : _cRef(1)
  55. {
  56. DllAddRef();
  57. }
  58. CThumbnail::~CThumbnail(void)
  59. {
  60. if (_pScheduler)
  61. {
  62. _pScheduler->RemoveTasks(TOID_Thumbnail, ITSAT_DEFAULT_LPARAM, FALSE);
  63. _pScheduler->Release();
  64. _pScheduler = NULL;
  65. }
  66. if (_psf)
  67. _psf->Release();
  68. ILFree(_pidl);
  69. DllRelease();
  70. }
  71. STDAPI CThumbnail_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
  72. {
  73. HRESULT hr;
  74. CThumbnail *pThumb = new CThumbnail();
  75. if (pThumb)
  76. {
  77. hr = pThumb->QueryInterface(riid, ppv);
  78. pThumb->Release();
  79. }
  80. else
  81. hr = E_OUTOFMEMORY;
  82. return hr;
  83. }
  84. HRESULT CThumbnail::QueryInterface(REFIID riid, void **ppv)
  85. {
  86. static const QITAB qit[] = {
  87. QITABENT(CThumbnail, IThumbnail2),
  88. QITABENTMULTI(CThumbnail, IThumbnail, IThumbnail2),
  89. QITABENT(CThumbnail, IParentAndItem),
  90. QITABENT(CThumbnail, IObjectWithSite),
  91. { 0 },
  92. };
  93. return QISearch(this, qit, riid, ppv);
  94. }
  95. ULONG CThumbnail::AddRef(void)
  96. {
  97. return InterlockedIncrement(&_cRef);
  98. }
  99. ULONG CThumbnail::Release(void)
  100. {
  101. ASSERT( 0 != _cRef );
  102. ULONG cRef = InterlockedDecrement(&_cRef);
  103. if ( 0 == cRef )
  104. {
  105. delete this;
  106. }
  107. return cRef;
  108. }
  109. // IThumbnail
  110. HRESULT CThumbnail::Init(HWND hwnd, UINT uMsg)
  111. {
  112. _hwnd = hwnd;
  113. _uMsg = uMsg;
  114. ASSERT(NULL == _pScheduler);
  115. return S_OK;
  116. }
  117. HRESULT CThumbnail::_InitTaskCancelItems()
  118. {
  119. if (!_pScheduler)
  120. {
  121. if (!_punkSite || FAILED(IUnknown_QueryService(_punkSite, SID_ShellTaskScheduler,
  122. IID_PPV_ARG(IShellTaskScheduler, &_pScheduler))))
  123. {
  124. CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC_SERVER,
  125. IID_PPV_ARG(IShellTaskScheduler, &_pScheduler));
  126. }
  127. if (_pScheduler)
  128. {
  129. // make sure RemoveTasks() actually kills old tasks even if they're not done yet
  130. _pScheduler->Status(ITSSFLAG_KILL_ON_DESTROY, ITSS_THREAD_TIMEOUT_NO_CHANGE);
  131. }
  132. }
  133. if (_pScheduler)
  134. {
  135. // Kill any old tasks in the scheduler.
  136. _pScheduler->RemoveTasks(TOID_Thumbnail, ITSAT_DEFAULT_LPARAM, FALSE);
  137. }
  138. return _pScheduler ? S_OK : E_FAIL;
  139. }
  140. HRESULT CThumbnail::_CreateTask(IShellFolder *psf, LPCITEMIDLIST pidl, DWORD dwItem, SIZE rgSize, IExtractImage *pei, IRunnableTask **pprt)
  141. {
  142. *pprt = new CGetThumbnailTask(psf, pidl, pei, _hwnd, _uMsg, dwItem, rgSize);
  143. return *pprt ? S_OK : E_OUTOFMEMORY;
  144. }
  145. HRESULT CThumbnail::_BitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight)
  146. {
  147. LPCITEMIDLIST pidlLast;
  148. IShellFolder *psf;
  149. HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  150. if (SUCCEEDED(hr))
  151. {
  152. IExtractImage *pei;
  153. hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, IID_PPV_ARG_NULL(IExtractImage, &pei));
  154. if (SUCCEEDED(hr))
  155. {
  156. DWORD dwPriority = 0;
  157. DWORD dwFlags = IEIFLAG_ASYNC | IEIFLAG_SCREEN | IEIFLAG_OFFLINE;
  158. SIZEL rgSize = {lWidth, lHeight};
  159. WCHAR szLocation[MAX_PATH];
  160. hr = pei->GetLocation(szLocation, ARRAYSIZE(szLocation), &dwPriority, &rgSize, SHGetCurColorRes(), &dwFlags);
  161. if (SUCCEEDED(hr))
  162. {
  163. if (S_OK == hr)
  164. {
  165. HBITMAP hbm;
  166. hr = pei->Extract(&hbm);
  167. if (SUCCEEDED(hr))
  168. {
  169. if (!PostMessage(_hwnd, _uMsg, dwItem, (LPARAM)hbm))
  170. {
  171. DeleteObject(hbm);
  172. }
  173. }
  174. }
  175. else
  176. hr = E_FAIL;
  177. }
  178. else if (E_PENDING == hr)
  179. {
  180. IRunnableTask *prt;
  181. hr = _CreateTask(psf, pidlLast, dwItem, rgSize, pei, &prt);
  182. if (SUCCEEDED(hr))
  183. {
  184. // Add the task to the scheduler.
  185. hr = _pScheduler->AddTask(prt, TOID_Thumbnail, ITSAT_DEFAULT_LPARAM, dwPriority);
  186. prt->Release();
  187. }
  188. }
  189. pei->Release();
  190. }
  191. psf->Release();
  192. }
  193. return hr;
  194. }
  195. STDMETHODIMP CThumbnail::GetBitmap(LPCWSTR pszFile, DWORD dwItem, LONG lWidth, LONG lHeight)
  196. {
  197. HRESULT hr = _InitTaskCancelItems();
  198. if (pszFile)
  199. {
  200. LPITEMIDLIST pidl = ILCreateFromPathW(pszFile);
  201. if (pidl)
  202. {
  203. hr = _BitmapFromIDList(pidl, dwItem, lWidth, lHeight);
  204. ILFree(pidl);
  205. }
  206. else
  207. hr = E_FAIL;
  208. }
  209. return hr;
  210. }
  211. // IThumbnail2
  212. STDMETHODIMP CThumbnail::GetBitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight)
  213. {
  214. HRESULT hr = _InitTaskCancelItems();
  215. if (pidl)
  216. {
  217. hr = _BitmapFromIDList(pidl, dwItem, lWidth, lHeight);
  218. }
  219. return hr;
  220. }
  221. // IParentAndItem
  222. STDMETHODIMP CThumbnail::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild)
  223. {
  224. return E_NOTIMPL;
  225. }
  226. STDMETHODIMP CThumbnail::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl)
  227. {
  228. return E_NOTIMPL;
  229. }
  230. CGetThumbnailTask::CGetThumbnailTask(IShellFolder *psf, LPCITEMIDLIST pidl, IExtractImage *pei, HWND hwnd, UINT uMsg, DWORD dwItem, SIZE rgSize)
  231. : CRunnableTask(RTF_DEFAULT), _pei(pei), _hwnd(hwnd), _uMsg(uMsg), _dwItem(dwItem), _psf(psf), _rgSize(rgSize)
  232. {
  233. SHGetIDListFromUnk(psf, &_pidlFolder); // failure handled later
  234. _pidlLast = ILClone(pidl); // failure handled later
  235. DisplayNameOf(psf, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, _szPath, ARRAYSIZE(_szPath));
  236. _pei->AddRef();
  237. _psf->AddRef();
  238. }
  239. CGetThumbnailTask::~CGetThumbnailTask()
  240. {
  241. ILFree(_pidlLast);
  242. ILFree(_pidlFolder);
  243. _pei->Release();
  244. _psf->Release();
  245. }
  246. HRESULT CGetThumbnailTask::_PrepImage(HBITMAP *phBmp)
  247. {
  248. HRESULT hr = E_FAIL;
  249. DIBSECTION ds;
  250. if (GetObject(*phBmp, sizeof(ds), &ds))
  251. {
  252. // the disk cache only supports 32 Bpp DIBS now, so we can ignore the palette issue...
  253. ASSERT(ds.dsBm.bmBitsPixel == 32);
  254. HPALETTE hPal = (SHGetCurColorRes() == 8) ? SHCreateShellPalette(NULL) : NULL;
  255. HBITMAP hBmpNew;
  256. if (ConvertDIBSECTIONToThumbnail((BITMAPINFO *)&ds.dsBmih, ds.dsBm.bmBits, &hBmpNew, &_rgSize,
  257. SHGetCurColorRes(), hPal, 0, FALSE))
  258. {
  259. DeleteObject(*phBmp);
  260. *phBmp = hBmpNew;
  261. }
  262. if (hPal)
  263. DeletePalette(hPal);
  264. }
  265. return hr;
  266. }
  267. HRESULT CGetThumbnailTask::_BitmapReady(HBITMAP hImage)
  268. {
  269. if (!PostMessage(_hwnd, _uMsg, _dwItem, (LPARAM)hImage))
  270. {
  271. DeleteObject(hImage);
  272. }
  273. return S_OK;
  274. }
  275. STDMETHODIMP CGetThumbnailTask::RunInitRT()
  276. {
  277. HRESULT hr = E_FAIL;
  278. // now get the date stamp and check the disk cache....
  279. FILETIME ftImageTimeStamp = {0,0};
  280. // do they support date stamps....
  281. IExtractImage2 *pei2;
  282. if (SUCCEEDED(_pei->QueryInterface(IID_PPV_ARG(IExtractImage2, &pei2))))
  283. {
  284. pei2->GetDateStamp(&ftImageTimeStamp);
  285. pei2->Release();
  286. }
  287. IShellFolder2 *psf2;
  288. if (IsNullTime(&ftImageTimeStamp) && _pidlLast && SUCCEEDED(_psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2))))
  289. {
  290. // fall back to this (most common case)
  291. GetDateProperty(psf2, _pidlLast, &SCID_WRITETIME, &ftImageTimeStamp);
  292. psf2->Release();
  293. }
  294. IShellImageStore *pStore;
  295. if (_pidlFolder &&
  296. SUCCEEDED(LoadFromIDList(CLSID_ShellThumbnailDiskCache, _pidlFolder, IID_PPV_ARG(IShellImageStore, &pStore))))
  297. {
  298. DWORD dwStoreLock;
  299. if (SUCCEEDED(pStore->Open(STGM_READ, &dwStoreLock)))
  300. {
  301. FILETIME ftCacheDateStamp;
  302. if ((S_OK == pStore->IsEntryInStore(_szPath, &ftCacheDateStamp)) &&
  303. ((0 == CompareFileTime(&ftCacheDateStamp, &ftImageTimeStamp)) || IsNullTime(&ftImageTimeStamp)))
  304. {
  305. HBITMAP hBmp;
  306. if (SUCCEEDED(pStore->GetEntry(_szPath, STGM_READ, &hBmp)))
  307. {
  308. _PrepImage(&hBmp);
  309. hr = _BitmapReady(hBmp);
  310. }
  311. }
  312. pStore->Close(&dwStoreLock);
  313. }
  314. pStore->Release();
  315. }
  316. if (FAILED(hr))
  317. {
  318. HBITMAP hbm;
  319. if (SUCCEEDED(_pei->Extract(&hbm)))
  320. {
  321. hr = _BitmapReady(hbm);
  322. }
  323. }
  324. return hr;
  325. }