|
|
#include "shellprv.h"
#include "runtask.h"
#include "prop.h"
#include "thumbutil.h"
#include <cowsite.h>
static const GUID TOID_Thumbnail = { 0xadec3450, 0xe907, 0x11d0, {0xa5, 0x7b, 0x00, 0xc0, 0x4f, 0xc2, 0xf7, 0x6a} };
class CThumbnail : public IThumbnail2, public IParentAndItem, public CObjectWithSite { public: CThumbnail(void);
// IUnknown
STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
// IThumbnail
STDMETHODIMP Init(HWND hwnd, UINT uMsg); STDMETHODIMP GetBitmap(LPCWSTR pszFile, DWORD dwItem, LONG lWidth, LONG lHeight);
// IThumbnail2
STDMETHODIMP GetBitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight);
// IParentAndItem
STDMETHODIMP SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild); STDMETHODIMP GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidlChild);
private: ~CThumbnail(void); HRESULT _CreateTask(IShellFolder *psf, LPCITEMIDLIST pidlLast, DWORD dwItem, SIZE rgSize, IExtractImage *pei, IRunnableTask **pprt); HRESULT _BitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight); HRESULT _InitTaskCancelItems();
LONG _cRef; HWND _hwnd; UINT _uMsg; IShellTaskScheduler *_pScheduler; IShellFolder *_psf; LPITEMIDLIST _pidl; };
class CGetThumbnailTask : public CRunnableTask { public: CGetThumbnailTask(IShellFolder *psf, LPCITEMIDLIST pidl, IExtractImage *pei, HWND hwnd, UINT uMsg, DWORD dwItem, SIZE rgSize); STDMETHODIMP RunInitRT(void);
private: ~CGetThumbnailTask(); HRESULT _PrepImage(HBITMAP *phBmp); HRESULT _BitmapReady(HBITMAP hImage); IShellFolder *_psf; IExtractImage *_pei; HWND _hwnd; UINT _uMsg; DWORD _dwItem; SIZE _rgSize; LPITEMIDLIST _pidlFolder; // folder where we test the cache
LPITEMIDLIST _pidlLast; WCHAR _szPath[MAX_PATH]; // the item in that in folder parsing name for cache test
};
CThumbnail::CThumbnail(void) : _cRef(1) { DllAddRef(); }
CThumbnail::~CThumbnail(void) { if (_pScheduler) { _pScheduler->RemoveTasks(TOID_Thumbnail, ITSAT_DEFAULT_LPARAM, FALSE); _pScheduler->Release(); _pScheduler = NULL; }
if (_psf) _psf->Release();
ILFree(_pidl);
DllRelease(); }
STDAPI CThumbnail_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv) { HRESULT hr; CThumbnail *pThumb = new CThumbnail(); if (pThumb) { hr = pThumb->QueryInterface(riid, ppv); pThumb->Release(); } else hr = E_OUTOFMEMORY; return hr; }
HRESULT CThumbnail::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CThumbnail, IThumbnail2), QITABENTMULTI(CThumbnail, IThumbnail, IThumbnail2), QITABENT(CThumbnail, IParentAndItem), QITABENT(CThumbnail, IObjectWithSite), { 0 }, }; return QISearch(this, qit, riid, ppv); }
ULONG CThumbnail::AddRef(void) { return InterlockedIncrement(&_cRef); }
ULONG CThumbnail::Release(void) { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
// IThumbnail
HRESULT CThumbnail::Init(HWND hwnd, UINT uMsg) { _hwnd = hwnd; _uMsg = uMsg; ASSERT(NULL == _pScheduler);
return S_OK; }
HRESULT CThumbnail::_InitTaskCancelItems() { if (!_pScheduler) { if (!_punkSite || FAILED(IUnknown_QueryService(_punkSite, SID_ShellTaskScheduler, IID_PPV_ARG(IShellTaskScheduler, &_pScheduler)))) { CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellTaskScheduler, &_pScheduler)); } if (_pScheduler) { // make sure RemoveTasks() actually kills old tasks even if they're not done yet
_pScheduler->Status(ITSSFLAG_KILL_ON_DESTROY, ITSS_THREAD_TIMEOUT_NO_CHANGE); } }
if (_pScheduler) { // Kill any old tasks in the scheduler.
_pScheduler->RemoveTasks(TOID_Thumbnail, ITSAT_DEFAULT_LPARAM, FALSE); } return _pScheduler ? S_OK : E_FAIL; }
HRESULT CThumbnail::_CreateTask(IShellFolder *psf, LPCITEMIDLIST pidl, DWORD dwItem, SIZE rgSize, IExtractImage *pei, IRunnableTask **pprt) { *pprt = new CGetThumbnailTask(psf, pidl, pei, _hwnd, _uMsg, dwItem, rgSize); return *pprt ? S_OK : E_OUTOFMEMORY; }
HRESULT CThumbnail::_BitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight) { LPCITEMIDLIST pidlLast; IShellFolder *psf; HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast); if (SUCCEEDED(hr)) { IExtractImage *pei; hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, IID_PPV_ARG_NULL(IExtractImage, &pei)); if (SUCCEEDED(hr)) { DWORD dwPriority = 0; DWORD dwFlags = IEIFLAG_ASYNC | IEIFLAG_SCREEN | IEIFLAG_OFFLINE; SIZEL rgSize = {lWidth, lHeight};
WCHAR szLocation[MAX_PATH]; hr = pei->GetLocation(szLocation, ARRAYSIZE(szLocation), &dwPriority, &rgSize, SHGetCurColorRes(), &dwFlags); if (SUCCEEDED(hr)) { if (S_OK == hr) { HBITMAP hbm; hr = pei->Extract(&hbm); if (SUCCEEDED(hr)) { if (!PostMessage(_hwnd, _uMsg, dwItem, (LPARAM)hbm)) { DeleteObject(hbm); } } } else hr = E_FAIL; } else if (E_PENDING == hr) { IRunnableTask *prt; hr = _CreateTask(psf, pidlLast, dwItem, rgSize, pei, &prt); if (SUCCEEDED(hr)) { // Add the task to the scheduler.
hr = _pScheduler->AddTask(prt, TOID_Thumbnail, ITSAT_DEFAULT_LPARAM, dwPriority); prt->Release(); } } pei->Release(); } psf->Release(); } return hr; }
STDMETHODIMP CThumbnail::GetBitmap(LPCWSTR pszFile, DWORD dwItem, LONG lWidth, LONG lHeight) { HRESULT hr = _InitTaskCancelItems(); if (pszFile) { LPITEMIDLIST pidl = ILCreateFromPathW(pszFile); if (pidl) { hr = _BitmapFromIDList(pidl, dwItem, lWidth, lHeight); ILFree(pidl); } else hr = E_FAIL; } return hr; }
// IThumbnail2
STDMETHODIMP CThumbnail::GetBitmapFromIDList(LPCITEMIDLIST pidl, DWORD dwItem, LONG lWidth, LONG lHeight) { HRESULT hr = _InitTaskCancelItems(); if (pidl) { hr = _BitmapFromIDList(pidl, dwItem, lWidth, lHeight); } return hr; }
// IParentAndItem
STDMETHODIMP CThumbnail::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild) { return E_NOTIMPL; }
STDMETHODIMP CThumbnail::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl) { return E_NOTIMPL; }
CGetThumbnailTask::CGetThumbnailTask(IShellFolder *psf, LPCITEMIDLIST pidl, IExtractImage *pei, HWND hwnd, UINT uMsg, DWORD dwItem, SIZE rgSize) : CRunnableTask(RTF_DEFAULT), _pei(pei), _hwnd(hwnd), _uMsg(uMsg), _dwItem(dwItem), _psf(psf), _rgSize(rgSize) { SHGetIDListFromUnk(psf, &_pidlFolder); // failure handled later
_pidlLast = ILClone(pidl); // failure handled later
DisplayNameOf(psf, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, _szPath, ARRAYSIZE(_szPath)); _pei->AddRef(); _psf->AddRef(); }
CGetThumbnailTask::~CGetThumbnailTask() { ILFree(_pidlLast); ILFree(_pidlFolder); _pei->Release(); _psf->Release(); }
HRESULT CGetThumbnailTask::_PrepImage(HBITMAP *phBmp) { HRESULT hr = E_FAIL; DIBSECTION ds; if (GetObject(*phBmp, sizeof(ds), &ds)) { // the disk cache only supports 32 Bpp DIBS now, so we can ignore the palette issue...
ASSERT(ds.dsBm.bmBitsPixel == 32); HPALETTE hPal = (SHGetCurColorRes() == 8) ? SHCreateShellPalette(NULL) : NULL;
HBITMAP hBmpNew; if (ConvertDIBSECTIONToThumbnail((BITMAPINFO *)&ds.dsBmih, ds.dsBm.bmBits, &hBmpNew, &_rgSize, SHGetCurColorRes(), hPal, 0, FALSE)) { DeleteObject(*phBmp); *phBmp = hBmpNew; }
if (hPal) DeletePalette(hPal); } return hr; }
HRESULT CGetThumbnailTask::_BitmapReady(HBITMAP hImage) { if (!PostMessage(_hwnd, _uMsg, _dwItem, (LPARAM)hImage)) { DeleteObject(hImage); } return S_OK; }
STDMETHODIMP CGetThumbnailTask::RunInitRT() { HRESULT hr = E_FAIL; // now get the date stamp and check the disk cache....
FILETIME ftImageTimeStamp = {0,0};
// do they support date stamps....
IExtractImage2 *pei2; if (SUCCEEDED(_pei->QueryInterface(IID_PPV_ARG(IExtractImage2, &pei2)))) { pei2->GetDateStamp(&ftImageTimeStamp); pei2->Release(); }
IShellFolder2 *psf2; if (IsNullTime(&ftImageTimeStamp) && _pidlLast && SUCCEEDED(_psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)))) { // fall back to this (most common case)
GetDateProperty(psf2, _pidlLast, &SCID_WRITETIME, &ftImageTimeStamp); psf2->Release(); }
IShellImageStore *pStore; if (_pidlFolder && SUCCEEDED(LoadFromIDList(CLSID_ShellThumbnailDiskCache, _pidlFolder, IID_PPV_ARG(IShellImageStore, &pStore)))) { DWORD dwStoreLock; if (SUCCEEDED(pStore->Open(STGM_READ, &dwStoreLock))) { FILETIME ftCacheDateStamp; if ((S_OK == pStore->IsEntryInStore(_szPath, &ftCacheDateStamp)) && ((0 == CompareFileTime(&ftCacheDateStamp, &ftImageTimeStamp)) || IsNullTime(&ftImageTimeStamp))) { HBITMAP hBmp; if (SUCCEEDED(pStore->GetEntry(_szPath, STGM_READ, &hBmp))) { _PrepImage(&hBmp); hr = _BitmapReady(hBmp); } } pStore->Close(&dwStoreLock); } pStore->Release(); }
if (FAILED(hr)) { HBITMAP hbm; if (SUCCEEDED(_pei->Extract(&hbm))) { hr = _BitmapReady(hbm); } }
return hr; }
|