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.

1639 lines
44 KiB

  1. #include "shellprv.h"
  2. #include "category.h"
  3. #include "prop.h"
  4. #include "ids.h"
  5. #include "clsobj.h"
  6. #include "comcat.h" // for IEnumGUID
  7. #include "ole2dup.h"
  8. #define GROUPID_UNSPECIFIED (-10)
  9. #define GROUPID_FOLDER (-11)
  10. #define GROUPID_OTHER (-12)
  11. #define STRINGID_FROM_GROUPID(id) ((id) == GROUPID_UNSPECIFIED)? IDS_UNSPECIFIED : (((id) == GROUPID_FOLDER)?IDS_GROUPFOLDERS: IDS_GROUPOTHERCHAR)
  12. typedef struct tagCATCACHE
  13. {
  14. GUID guid;
  15. SHCOLUMNID scid;
  16. IUnknown* punk;
  17. } CATCACHE;
  18. // {3E373E22-DA99-4cb7-A886-754EAE984CB4}
  19. static const GUID CLSID_DetailCategorizer =
  20. { 0x3e373e22, 0xda99, 0x4cb7, { 0xa8, 0x86, 0x75, 0x4e, 0xae, 0x98, 0x4c, 0xb4 } };
  21. class CTimeCategorizer : public ICategorizer,
  22. public IShellExtInit
  23. {
  24. public:
  25. // IUnknown
  26. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  27. STDMETHODIMP_(ULONG) AddRef(void);
  28. STDMETHODIMP_(ULONG) Release(void);
  29. // ICategorizer
  30. STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
  31. STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
  32. STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
  33. STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
  34. // IShellExtInit
  35. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
  36. CTimeCategorizer(const SHCOLUMNID* pscid, IShellFolder2* psf);
  37. CTimeCategorizer();
  38. private:
  39. ~CTimeCategorizer();
  40. long _cRef;
  41. IShellFolder2* _psf;
  42. SHCOLUMNID _scid;
  43. };
  44. class CSizeCategorizer : public ICategorizer,
  45. public IShellExtInit
  46. {
  47. public:
  48. // IUnknown
  49. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  50. STDMETHODIMP_(ULONG) AddRef(void);
  51. STDMETHODIMP_(ULONG) Release(void);
  52. // ICategorizer
  53. STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
  54. STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
  55. STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
  56. STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
  57. // IShellExtInit
  58. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
  59. CSizeCategorizer(IShellFolder2* psf);
  60. CSizeCategorizer(BOOL fLarge);
  61. private:
  62. ~CSizeCategorizer();
  63. long _cRef;
  64. IShellFolder2* _psf;
  65. BOOL _fLarge;
  66. };
  67. class CDriveTypeCategorizer : public ICategorizer,
  68. public IShellExtInit
  69. {
  70. public:
  71. // IUnknown
  72. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  73. STDMETHODIMP_(ULONG) AddRef(void);
  74. STDMETHODIMP_(ULONG) Release(void);
  75. // ICategorizer
  76. STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
  77. STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
  78. STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
  79. STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
  80. // IShellExtInit
  81. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
  82. CDriveTypeCategorizer(IShellFolder2* psf);
  83. CDriveTypeCategorizer();
  84. private:
  85. ~CDriveTypeCategorizer();
  86. long _cRef;
  87. IShellFolder2* _psf;
  88. };
  89. class CAlphaCategorizer : public ICategorizer
  90. {
  91. public:
  92. // IUnknown
  93. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  94. STDMETHODIMP_(ULONG) AddRef(void);
  95. STDMETHODIMP_(ULONG) Release(void);
  96. // ICategorizer
  97. STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
  98. STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
  99. STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
  100. STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
  101. CAlphaCategorizer(IShellFolder2* psf);
  102. private:
  103. ~CAlphaCategorizer();
  104. long _cRef;
  105. IShellFolder2* _psf;
  106. };
  107. class CFreeSpaceCategorizer : public ICategorizer,
  108. public IShellExtInit
  109. {
  110. public:
  111. // IUnknown
  112. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  113. STDMETHODIMP_(ULONG) AddRef(void);
  114. STDMETHODIMP_(ULONG) Release(void);
  115. // ICategorizer
  116. STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
  117. STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
  118. STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
  119. STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
  120. // IShellExtInit
  121. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
  122. CFreeSpaceCategorizer();
  123. private:
  124. ~CFreeSpaceCategorizer();
  125. long _cRef;
  126. IShellFolder2* _psf;
  127. };
  128. class CDetailCategorizer : public ICategorizer
  129. {
  130. public:
  131. // IUnknown
  132. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  133. STDMETHODIMP_(ULONG) AddRef(void);
  134. STDMETHODIMP_(ULONG) Release(void);
  135. // ICategorizer
  136. STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
  137. STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
  138. STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
  139. STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
  140. CDetailCategorizer(IShellFolder2* psf, const SHCOLUMNID& scid);
  141. private:
  142. ~CDetailCategorizer();
  143. long _cRef;
  144. IShellFolder2* _psf;
  145. SHCOLUMNID _scid;
  146. HHASHTABLE _hash;
  147. HDPA _hdpaKeys;
  148. };
  149. class CEnumCategoryGUID : public IEnumGUID
  150. {
  151. public:
  152. // IUnknown
  153. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  154. STDMETHODIMP_(ULONG) AddRef(void);
  155. STDMETHODIMP_(ULONG) Release(void);
  156. // IEnumIDList
  157. STDMETHODIMP Next(ULONG celt, GUID *rgelt, ULONG *pceltFetched);
  158. STDMETHODIMP Skip(ULONG celt) { return E_NOTIMPL; }
  159. STDMETHODIMP Reset() { _iIndex = 0; return S_OK;}
  160. STDMETHODIMP Clone(IEnumGUID **ppenum) { return E_NOTIMPL; };
  161. CEnumCategoryGUID(HDSA hdsa);
  162. private:
  163. long _cRef;
  164. HDSA _hda;
  165. int _iIndex;
  166. };
  167. CEnumCategoryGUID::CEnumCategoryGUID(HDSA hda): _cRef(1)
  168. {
  169. _hda = hda;
  170. }
  171. HRESULT CEnumCategoryGUID::QueryInterface(REFIID riid, void **ppv)
  172. {
  173. static const QITAB qit[] =
  174. {
  175. QITABENT(CEnumCategoryGUID, IEnumGUID),
  176. { 0 },
  177. };
  178. return QISearch(this, qit, riid, ppv);
  179. }
  180. ULONG CEnumCategoryGUID::AddRef()
  181. {
  182. return InterlockedIncrement(&_cRef);
  183. }
  184. ULONG CEnumCategoryGUID::Release()
  185. {
  186. ASSERT( 0 != _cRef );
  187. ULONG cRef = InterlockedDecrement(&_cRef);
  188. if ( 0 == cRef )
  189. {
  190. delete this;
  191. }
  192. return cRef;
  193. }
  194. STDMETHODIMP CEnumCategoryGUID::Next(ULONG celt, GUID *rgelt, ULONG *pceltFetched)
  195. {
  196. HRESULT hr = S_FALSE;
  197. if (celt > 1)
  198. return E_INVALIDARG;
  199. if (_hda == NULL)
  200. return hr;
  201. while (hr != S_OK &&
  202. _iIndex < DSA_GetItemCount(_hda))
  203. {
  204. CATCACHE* pcat = (CATCACHE*)DSA_GetItemPtr(_hda, _iIndex);
  205. // Is this a scid map entry instead of an external categorizer?
  206. if (pcat->scid.fmtid == GUID_NULL)
  207. {
  208. // Nope. then we can enum it.
  209. if (pceltFetched)
  210. *pceltFetched = 1;
  211. *rgelt = pcat->guid;
  212. hr = S_OK;
  213. }
  214. _iIndex++;
  215. }
  216. return hr;
  217. }
  218. class CCategoryProvider : public ICategoryProvider, public IDefCategoryProvider
  219. {
  220. public:
  221. // IUnknown
  222. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  223. STDMETHODIMP_(ULONG) AddRef(void);
  224. STDMETHODIMP_(ULONG) Release(void);
  225. // ICategoryProvider
  226. STDMETHODIMP CanCategorizeOnSCID(SHCOLUMNID* pscid);
  227. STDMETHODIMP GetDefaultCategory(GUID* pguid, SHCOLUMNID* pscid);
  228. STDMETHODIMP GetCategoryForSCID(SHCOLUMNID* pscid, GUID* pguid);
  229. STDMETHODIMP EnumCategories(IEnumGUID** penum);
  230. STDMETHODIMP GetCategoryName(GUID* pguid, LPWSTR pszName, UINT cch);
  231. STDMETHODIMP CreateCategory(GUID* pguid, REFIID riid, void** ppv);
  232. // IDefCategoryProvider
  233. STDMETHODIMP Initialize(const GUID* pguid, const SHCOLUMNID* pscid, const SHCOLUMNID* pscidExlude, HKEY hkey, const CATLIST* pcl, IShellFolder* psf);
  234. CCategoryProvider();
  235. private:
  236. ~CCategoryProvider();
  237. BOOL _BuildCategoryList(HKEY hkey, const CATLIST* pcl);
  238. friend int DestroyCache(void *pv, void *unused);
  239. HRESULT CreateInstance(GUID* pguid, REFIID riid, void** ppv);
  240. long _cRef;
  241. LPITEMIDLIST _pidlFolder;
  242. IShellFolder2* _psf;
  243. HDSA _hdaCat;
  244. GUID _guidDefault;
  245. SHCOLUMNID _scidDefault;
  246. HDSA _hdaExcludeSCIDs;
  247. };
  248. STDAPI CCategoryProvider_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
  249. {
  250. HRESULT hr = E_OUTOFMEMORY;
  251. CCategoryProvider* p = new CCategoryProvider();
  252. if (p)
  253. {
  254. hr = p->QueryInterface(riid, ppv);
  255. p->Release();
  256. }
  257. return hr;
  258. }
  259. BOOL CCategoryProvider::_BuildCategoryList(HKEY hkey, const CATLIST* pcl)
  260. {
  261. int i = 0;
  262. _hdaCat = DSA_Create(sizeof(CATCACHE), 3);
  263. if (!_hdaCat)
  264. return FALSE;
  265. // Enumerate static
  266. while(!IsEqualGUID(*pcl[i].pguid, GUID_NULL))
  267. {
  268. CATCACHE cc = {0};
  269. cc.guid = *pcl[i].pguid;
  270. if (pcl[i].pscid)
  271. {
  272. cc.scid = *pcl[i].pscid;
  273. }
  274. DSA_AppendItem(_hdaCat, (void*)&cc);
  275. i++;
  276. }
  277. // Enumerate hkey
  278. TCHAR szHandlerCLSID[GUIDSTR_MAX];
  279. int iHandler = 0;
  280. while (ERROR_SUCCESS == RegEnumKey(hkey, iHandler++, szHandlerCLSID, ARRAYSIZE(szHandlerCLSID)))
  281. {
  282. CLSID clsid;
  283. if (SUCCEEDED(SHCLSIDFromString(szHandlerCLSID, &clsid)))
  284. {
  285. CATCACHE cc = {0};
  286. cc.guid = clsid;
  287. DSA_AppendItem(_hdaCat, (void*)&cc);
  288. i++;
  289. }
  290. }
  291. return TRUE;
  292. }
  293. CCategoryProvider::CCategoryProvider() : _cRef(1)
  294. {
  295. DllAddRef();
  296. }
  297. int DestroyCache(void *pv, void *unused)
  298. {
  299. CATCACHE* pcat = (CATCACHE*)pv;
  300. ATOMICRELEASE(pcat->punk);
  301. return 1;
  302. }
  303. CCategoryProvider::~CCategoryProvider()
  304. {
  305. ATOMICRELEASE(_psf);
  306. ILFree(_pidlFolder);
  307. if (_hdaExcludeSCIDs)
  308. {
  309. DSA_Destroy(_hdaExcludeSCIDs);
  310. }
  311. if (_hdaCat)
  312. {
  313. DSA_DestroyCallback(_hdaCat, DestroyCache, NULL);
  314. }
  315. DllRelease();
  316. }
  317. HRESULT CCategoryProvider::QueryInterface(REFIID riid, void **ppv)
  318. {
  319. static const QITAB qit[] =
  320. {
  321. QITABENT(CCategoryProvider, IDefCategoryProvider),
  322. QITABENT(CCategoryProvider, ICategoryProvider),
  323. { 0 },
  324. };
  325. return QISearch(this, qit, riid, ppv);
  326. }
  327. ULONG CCategoryProvider::AddRef()
  328. {
  329. return InterlockedIncrement(&_cRef);
  330. }
  331. ULONG CCategoryProvider::Release()
  332. {
  333. ASSERT( 0 != _cRef );
  334. ULONG cRef = InterlockedDecrement(&_cRef);
  335. if ( 0 == cRef )
  336. {
  337. delete this;
  338. }
  339. return cRef;
  340. }
  341. HRESULT CCategoryProvider::Initialize(const GUID* pguid, const SHCOLUMNID* pscid, const SHCOLUMNID* pscidExclude, HKEY hkey, const CATLIST* pcl, IShellFolder* psf)
  342. {
  343. if (!psf)
  344. return E_INVALIDARG;
  345. HRESULT hr = SHGetIDListFromUnk(psf, &_pidlFolder);
  346. if (SUCCEEDED(hr))
  347. {
  348. if (pcl && !_BuildCategoryList(hkey, pcl))
  349. return E_OUTOFMEMORY;
  350. if (pguid)
  351. _guidDefault = *pguid;
  352. if (pscid)
  353. _scidDefault = *pscid;
  354. if (pscidExclude)
  355. {
  356. _hdaExcludeSCIDs = DSA_Create(sizeof(SHCOLUMNID), 3);
  357. if (_hdaExcludeSCIDs)
  358. {
  359. int i = 0;
  360. while(pscidExclude[i].fmtid != GUID_NULL)
  361. {
  362. DSA_AppendItem(_hdaExcludeSCIDs, (void*)&pscidExclude[i]);
  363. i++;
  364. }
  365. }
  366. }
  367. hr = psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf));
  368. }
  369. return hr;
  370. }
  371. STDMETHODIMP CCategoryProvider::CanCategorizeOnSCID(SHCOLUMNID* pscid)
  372. {
  373. if (_hdaExcludeSCIDs)
  374. {
  375. for (int i=0; i < DSA_GetItemCount(_hdaExcludeSCIDs); i++)
  376. {
  377. SHCOLUMNID* pscidExclude = (SHCOLUMNID*)DSA_GetItemPtr(_hdaExcludeSCIDs, i);
  378. if (IsEqualSCID(*pscidExclude, *pscid))
  379. return S_FALSE;
  380. }
  381. }
  382. return S_OK;
  383. }
  384. STDMETHODIMP CCategoryProvider::GetDefaultCategory(GUID* pguid, SHCOLUMNID* pscid)
  385. {
  386. *pguid = _guidDefault;
  387. *pscid = _scidDefault;
  388. if (_guidDefault == GUID_NULL && _scidDefault.fmtid == GUID_NULL)
  389. return S_FALSE;
  390. return S_OK;
  391. }
  392. STDMETHODIMP CCategoryProvider::GetCategoryForSCID(SHCOLUMNID* pscid, GUID* pguid)
  393. {
  394. HRESULT hr = S_FALSE;
  395. if (_hdaCat == NULL || pscid == NULL)
  396. return hr;
  397. int c = DSA_GetItemCount(_hdaCat);
  398. for (int i = 0; i < c; i++)
  399. {
  400. CATCACHE* pcc = (CATCACHE*)DSA_GetItemPtr(_hdaCat, i);
  401. ASSERT(pcc != NULL);
  402. if (IsEqualSCID(pcc->scid, *pscid))
  403. {
  404. *pguid = pcc->guid;
  405. hr = S_OK;
  406. break;
  407. }
  408. }
  409. return hr;
  410. }
  411. STDMETHODIMP CCategoryProvider::EnumCategories(IEnumGUID** penum)
  412. {
  413. HRESULT hr = E_NOINTERFACE;
  414. if (_hdaCat)
  415. {
  416. *penum = (IEnumGUID*)new CEnumCategoryGUID(_hdaCat);
  417. if (!*penum)
  418. hr = E_OUTOFMEMORY;
  419. hr = S_OK;
  420. }
  421. return hr;
  422. }
  423. STDMETHODIMP CCategoryProvider::GetCategoryName(GUID* pguid, LPWSTR pszName, UINT cch)
  424. {
  425. ICategorizer* pcat;
  426. HRESULT hr = CreateCategory(pguid, IID_PPV_ARG(ICategorizer, &pcat));
  427. if (SUCCEEDED(hr))
  428. {
  429. hr = pcat->GetDescription(pszName, cch);
  430. pcat->Release();
  431. }
  432. return hr;
  433. }
  434. HRESULT CCategoryProvider::CreateInstance(GUID* pguid, REFIID riid, void** ppv)
  435. {
  436. IShellExtInit* psei;
  437. // These come from HKCR hence must go through approval
  438. HRESULT hr = SHExtCoCreateInstance(NULL, pguid, NULL, IID_PPV_ARG(IShellExtInit, &psei));
  439. if (SUCCEEDED(hr))
  440. {
  441. psei->Initialize(_pidlFolder, NULL, NULL);
  442. hr = psei->QueryInterface(riid, ppv);
  443. psei->Release();
  444. }
  445. return hr;
  446. }
  447. STDMETHODIMP CCategoryProvider::CreateCategory(GUID* pguid, REFIID riid, void** ppv)
  448. {
  449. HRESULT hr = E_NOINTERFACE;
  450. if (_hdaCat != NULL)
  451. {
  452. int c = DSA_GetItemCount(_hdaCat);
  453. for (int i = 0; i < c; i++)
  454. {
  455. CATCACHE* pcc = (CATCACHE*)DSA_GetItemPtr(_hdaCat, i);
  456. ASSERT(pcc != NULL);
  457. if (IsEqualGUID(pcc->guid, *pguid))
  458. {
  459. if (!pcc->punk)
  460. {
  461. hr = CreateInstance(pguid, IID_PPV_ARG(IUnknown, &pcc->punk));
  462. }
  463. if (pcc->punk)
  464. {
  465. hr = pcc->punk->QueryInterface(riid, ppv);
  466. }
  467. break;
  468. }
  469. }
  470. }
  471. if (FAILED(hr))
  472. {
  473. // Not in the cache? Just try a create
  474. hr = CreateInstance(pguid, riid, ppv);
  475. }
  476. return hr;
  477. }
  478. STDAPI CCategoryProvider_Create(const GUID* pguid, const SHCOLUMNID* pscid, HKEY hkey, const CATLIST* pcl, IShellFolder* psf, REFIID riid, void **ppv)
  479. {
  480. HRESULT hr;
  481. CCategoryProvider *pdext = new CCategoryProvider();
  482. if (pdext)
  483. {
  484. hr = pdext->Initialize(pguid, pscid, NULL, hkey, pcl, psf);
  485. if (SUCCEEDED(hr))
  486. hr = pdext->QueryInterface(riid, ppv);
  487. pdext->Release();
  488. }
  489. else
  490. {
  491. *ppv = NULL;
  492. hr = E_OUTOFMEMORY;
  493. }
  494. return hr;
  495. }
  496. /////////////////////////////////////////////////////////
  497. // Time Categorizer
  498. STDAPI CTimeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  499. {
  500. HRESULT hr = E_OUTOFMEMORY;
  501. CTimeCategorizer* p = new CTimeCategorizer();
  502. if (p)
  503. {
  504. hr = p->QueryInterface(riid, ppv);
  505. p->Release();
  506. }
  507. return hr;
  508. }
  509. STDAPI CTimeCategorizer_Create(IShellFolder2* psf2, const SHCOLUMNID* pscid, REFIID riid, void **ppv)
  510. {
  511. HRESULT hr = E_OUTOFMEMORY;
  512. CTimeCategorizer* p = new CTimeCategorizer(pscid, psf2);
  513. if (p)
  514. {
  515. hr = p->QueryInterface(riid, ppv);
  516. p->Release();
  517. }
  518. return hr;
  519. }
  520. CTimeCategorizer::CTimeCategorizer(const SHCOLUMNID* pscid, IShellFolder2* psf) : _cRef(1)
  521. {
  522. _psf = psf;
  523. ASSERT(psf);
  524. psf->AddRef();
  525. _scid = *pscid;
  526. }
  527. CTimeCategorizer::CTimeCategorizer() : _cRef(1)
  528. {
  529. _scid = SCID_WRITETIME;
  530. }
  531. CTimeCategorizer::~CTimeCategorizer()
  532. {
  533. ATOMICRELEASE(_psf);
  534. }
  535. HRESULT CTimeCategorizer::QueryInterface(REFIID riid, void **ppv)
  536. {
  537. static const QITAB qit[] =
  538. {
  539. QITABENT(CTimeCategorizer, ICategorizer),
  540. QITABENT(CTimeCategorizer, IShellExtInit),
  541. { 0 },
  542. };
  543. return QISearch(this, qit, riid, ppv);
  544. }
  545. ULONG CTimeCategorizer::AddRef()
  546. {
  547. return InterlockedIncrement(&_cRef);
  548. }
  549. ULONG CTimeCategorizer::Release()
  550. {
  551. ASSERT( 0 != _cRef );
  552. ULONG cRef = InterlockedDecrement(&_cRef);
  553. if ( 0 == cRef )
  554. {
  555. delete this;
  556. }
  557. return cRef;
  558. }
  559. HRESULT CTimeCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
  560. {
  561. ATOMICRELEASE(_psf);
  562. return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
  563. }
  564. HRESULT CTimeCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
  565. {
  566. LoadString(HINST_THISDLL, IDS_GROUPBYTIME, pszDesc, cch);
  567. return S_OK;
  568. }
  569. static const int mpcdymoAccum[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
  570. int GetDaysForMonth(int yr, int mo)
  571. {
  572. int cdy;
  573. if (yr == 1752 && mo == 9)
  574. return 19;
  575. cdy = mpcdymoAccum[mo] - mpcdymoAccum[mo - 1];
  576. if (mo == 2 && (yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  577. cdy++;
  578. return cdy;
  579. }
  580. int GetDaysForLastMonth(int year, int month)
  581. {
  582. if (month == 1)
  583. {
  584. year--;
  585. month = 12;
  586. }
  587. else
  588. month--;
  589. return GetDaysForMonth(year, month);
  590. }
  591. HRESULT CTimeCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
  592. {
  593. SYSTEMTIME stCur;
  594. GetLocalTime(&stCur);
  595. for (UINT i = 0; i < cidl; i++)
  596. {
  597. FILETIME ft;
  598. // Get the time data
  599. if (SUCCEEDED(GetDateProperty(_psf, apidl[i], &_scid, &ft)))
  600. {
  601. // Convert it to a usable format
  602. SYSTEMTIME stFile;
  603. FileTimeToLocalFileTime(&ft, &ft);
  604. FileTimeToSystemTime(&ft, &stFile);
  605. if (stFile.wYear == stCur.wYear)
  606. {
  607. if (stFile.wMonth > stCur.wMonth)
  608. {
  609. if (stFile.wMonth == stCur.wMonth + 1)
  610. {
  611. rgCategoryIds[i] = IDS_NEXTMONTH;
  612. }
  613. else
  614. {
  615. rgCategoryIds[i] = IDS_LATERTHISYEAR;
  616. }
  617. }
  618. else if (stFile.wMonth == stCur.wMonth)
  619. {
  620. if (stFile.wDay == stCur.wDay + 1)
  621. {
  622. rgCategoryIds[i] = IDS_TOMORROW;
  623. }
  624. else if (stFile.wDay == stCur.wDay + 2)
  625. {
  626. rgCategoryIds[i] = IDS_TWODAYSFROMNOW;
  627. }
  628. else if (stFile.wDay == stCur.wDay)
  629. {
  630. rgCategoryIds[i] = IDS_TODAY;
  631. }
  632. else if (stFile.wDay == stCur.wDay - 1)
  633. {
  634. rgCategoryIds[i] = IDS_YESTERDAY;
  635. }
  636. else if (stFile.wDayOfWeek < stCur.wDayOfWeek &&
  637. stFile.wDay < stCur.wDay &&
  638. stCur.wDay - stCur.wDayOfWeek > 0 &&
  639. stFile.wDay >= stCur.wDay - stCur.wDayOfWeek)
  640. {
  641. rgCategoryIds[i] = IDS_EARLIERTHISWEEK;
  642. }
  643. else if (stFile.wDayOfWeek > stCur.wDayOfWeek &&
  644. stFile.wDay > stCur.wDay &&
  645. stFile.wDay <= stCur.wDay + (7 - stCur.wDayOfWeek))
  646. {
  647. rgCategoryIds[i] = IDS_LATERTHISWEEK;
  648. }
  649. else if (stFile.wDay > stCur.wDay)
  650. {
  651. rgCategoryIds[i] = IDS_LATERTHISMONTH;
  652. }
  653. else
  654. {
  655. int fileDays = GetDaysForLastMonth(stFile.wYear, stFile.wMonth - 1) + stFile.wDay;
  656. int curDays = GetDaysForLastMonth(stCur.wYear, stCur.wMonth - 1) + stCur.wDay;
  657. if (fileDays < (curDays - stCur.wDayOfWeek) &&
  658. fileDays > (curDays - stCur.wDayOfWeek - 7))
  659. {
  660. rgCategoryIds[i] = IDS_LASTWEEK;
  661. }
  662. else if (fileDays < (curDays - stCur.wDayOfWeek - 7) &&
  663. fileDays > (curDays - stCur.wDayOfWeek - 14))
  664. {
  665. rgCategoryIds[i] = IDS_TWOWEEKSAGO;
  666. }
  667. else
  668. {
  669. rgCategoryIds[i] = IDS_EARLIERTHISMONTH;
  670. }
  671. }
  672. }
  673. else if (stFile.wMonth == stCur.wMonth - 1 ||
  674. (stFile.wMonth == 12 &&
  675. stCur.wMonth == 1))
  676. {
  677. rgCategoryIds[i] = IDS_LASTMONTH;
  678. }
  679. else if (stFile.wMonth == stCur.wMonth - 2 ||
  680. (stFile.wMonth == 12 && stCur.wMonth == 2) ||
  681. (stFile.wMonth == 11 && stCur.wMonth == 1))
  682. {
  683. rgCategoryIds[i] = IDS_TWOMONTHSAGO;
  684. }
  685. else
  686. {
  687. rgCategoryIds[i] = IDS_EARLIERTHISYEAR;
  688. }
  689. }
  690. else if (stFile.wYear == stCur.wYear - 1)
  691. {
  692. rgCategoryIds[i] = IDS_LASTYEAR;
  693. }
  694. else if (stFile.wYear == stCur.wYear - 2)
  695. {
  696. rgCategoryIds[i] = IDS_TWOYEARSAGO;
  697. }
  698. else if (stFile.wYear < stCur.wYear - 2)
  699. {
  700. rgCategoryIds[i] = IDS_LONGTIMEAGO;
  701. }
  702. else if (stFile.wYear == stCur.wYear + 1)
  703. {
  704. rgCategoryIds[i] = IDS_NEXTYEAR;
  705. }
  706. else if (stFile.wYear > stCur.wYear + 2)
  707. {
  708. rgCategoryIds[i] = IDS_SOMETIMETHISMILLENNIA;
  709. }
  710. else if (stFile.wYear > (stCur.wYear / 1000) * 1000 + 1000) // 2050 / 1000 = 2. 2 * 1000 = 2000. 2000 + 1000 = 3000 i.e. next millennium
  711. {
  712. rgCategoryIds[i] = IDS_SOMEFUTUREDATE;
  713. }
  714. }
  715. else
  716. {
  717. rgCategoryIds[i] = IDS_UNSPECIFIED;
  718. }
  719. }
  720. return S_OK;
  721. }
  722. HRESULT CTimeCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
  723. {
  724. LoadString(HINST_THISDLL, dwCategoryId, pci->wszName, ARRAYSIZE(pci->wszName));
  725. return S_OK;
  726. }
  727. HRESULT CTimeCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
  728. {
  729. if (dwCategoryId1 == dwCategoryId2)
  730. return ResultFromShort(0);
  731. else if (dwCategoryId1 == IDS_GROUPFOLDERS)
  732. return ResultFromShort(-1);
  733. else if (dwCategoryId2 == IDS_GROUPFOLDERS)
  734. return ResultFromShort(1);
  735. else if (dwCategoryId1 < dwCategoryId2)
  736. return ResultFromShort(-1);
  737. else
  738. return ResultFromShort(1);
  739. }
  740. /////////////////////////////////////////////////////////
  741. // Size Categorizer
  742. STDAPI CDriveSizeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  743. {
  744. HRESULT hr = E_OUTOFMEMORY;
  745. CSizeCategorizer* p = new CSizeCategorizer(TRUE);
  746. if (p)
  747. {
  748. hr = p->QueryInterface(riid, ppv);
  749. p->Release();
  750. }
  751. return hr;
  752. }
  753. STDAPI CSizeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  754. {
  755. HRESULT hr = E_OUTOFMEMORY;
  756. CSizeCategorizer* p = new CSizeCategorizer(FALSE);
  757. if (p)
  758. {
  759. hr = p->QueryInterface(riid, ppv);
  760. p->Release();
  761. }
  762. return hr;
  763. }
  764. STDAPI CSizeCategorizer_Create(IShellFolder2* psf2, REFIID riid, void **ppv)
  765. {
  766. HRESULT hr = E_OUTOFMEMORY;
  767. CSizeCategorizer* p = new CSizeCategorizer(psf2);
  768. if (p)
  769. {
  770. hr = p->QueryInterface(riid, ppv);
  771. p->Release();
  772. }
  773. return hr;
  774. }
  775. CSizeCategorizer::CSizeCategorizer(IShellFolder2* psf) : _cRef(1)
  776. {
  777. _psf = psf;
  778. ASSERT(psf);
  779. psf->AddRef();
  780. }
  781. CSizeCategorizer::CSizeCategorizer(BOOL fLarge) : _cRef(1), _fLarge(fLarge)
  782. {
  783. }
  784. CSizeCategorizer::~CSizeCategorizer()
  785. {
  786. ATOMICRELEASE(_psf);
  787. }
  788. HRESULT CSizeCategorizer::QueryInterface(REFIID riid, void **ppv)
  789. {
  790. static const QITAB qit[] =
  791. {
  792. QITABENT(CSizeCategorizer, ICategorizer),
  793. QITABENT(CSizeCategorizer, IShellExtInit),
  794. { 0 },
  795. };
  796. return QISearch(this, qit, riid, ppv);
  797. }
  798. ULONG CSizeCategorizer::AddRef()
  799. {
  800. return InterlockedIncrement(&_cRef);
  801. }
  802. ULONG CSizeCategorizer::Release()
  803. {
  804. ASSERT( 0 != _cRef );
  805. ULONG cRef = InterlockedDecrement(&_cRef);
  806. if ( 0 == cRef )
  807. {
  808. delete this;
  809. }
  810. return cRef;
  811. }
  812. HRESULT CSizeCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
  813. {
  814. ATOMICRELEASE(_psf);
  815. return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
  816. }
  817. HRESULT CSizeCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
  818. {
  819. LoadString(HINST_THISDLL, IDS_GROUPBYSIZE, pszDesc, cch);
  820. return S_OK;
  821. }
  822. const static ULONGLONG s_rgSizesSmall[] =
  823. {
  824. // 130mb 16mb 1mb 100k 10l
  825. 134217728, 16777216, 1048576, 131072, 32768, 0
  826. };
  827. const static ULONGLONG s_rgSizesLarge[] =
  828. {
  829. // 80gig 25gig 10gig 2gig 500mb
  830. 80000000000, 25000000000, 10000000000, 2000000000, 500000000, 0
  831. };
  832. HRESULT CSizeCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
  833. {
  834. if (_psf == NULL)
  835. return E_ACCESSDENIED; // Not initialized yet.
  836. for (UINT i = 0; i < cidl; i++)
  837. {
  838. const ULONGLONG* pll = _fLarge? s_rgSizesLarge : s_rgSizesSmall;
  839. // Get the size data
  840. ULONGLONG ullSize;
  841. if (SUCCEEDED(GetLongProperty(_psf, apidl[i], _fLarge?&SCID_CAPACITY:&SCID_SIZE, &ullSize)))
  842. {
  843. if (ullSize >= pll[0])
  844. rgCategoryIds[i] = IDS_GIGANTIC;
  845. if (ullSize < pll[0])
  846. rgCategoryIds[i] = IDS_HUGE;
  847. if (ullSize < pll[1]) // Under 16mb
  848. rgCategoryIds[i] = IDS_LARGE;
  849. if (ullSize < pll[2]) // Under 1mb
  850. rgCategoryIds[i] = IDS_MEDIUM;
  851. if (ullSize < pll[3]) // Under 100k
  852. rgCategoryIds[i] = IDS_SMALL;
  853. if (ullSize < pll[4]) // Under 10k
  854. rgCategoryIds[i] = IDS_TINY;
  855. if (ullSize == pll[5]) // Zero sized files
  856. {
  857. if (SHGetAttributes(_psf, apidl[i], SFGAO_FOLDER))
  858. {
  859. rgCategoryIds[i] = IDS_FOLDERS;
  860. }
  861. else
  862. {
  863. rgCategoryIds[i] = IDS_ZERO;
  864. }
  865. }
  866. }
  867. else
  868. {
  869. rgCategoryIds[i] = IDS_UNSPECIFIED;
  870. }
  871. }
  872. return S_OK;
  873. }
  874. HRESULT CSizeCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
  875. {
  876. LoadString(HINST_THISDLL, dwCategoryId, pci->wszName, ARRAYSIZE(pci->wszName));
  877. return S_OK;
  878. }
  879. HRESULT CSizeCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
  880. {
  881. if (dwCategoryId1 == dwCategoryId2)
  882. return ResultFromShort(0);
  883. else if (dwCategoryId1 == IDS_GROUPFOLDERS)
  884. return ResultFromShort(-1);
  885. else if (dwCategoryId2 == IDS_GROUPFOLDERS)
  886. return ResultFromShort(1);
  887. else if (dwCategoryId1 < dwCategoryId2)
  888. return ResultFromShort(-1);
  889. else
  890. return ResultFromShort(1);
  891. }
  892. /////////////////////////////////////////////////////////
  893. // Type Categorizer
  894. STDAPI CDriveTypeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  895. {
  896. CDriveTypeCategorizer *p = new CDriveTypeCategorizer();
  897. if (!p)
  898. return E_OUTOFMEMORY;
  899. HRESULT hr = p->QueryInterface(riid, ppv);
  900. p->Release();
  901. return hr;
  902. }
  903. CDriveTypeCategorizer::CDriveTypeCategorizer(IShellFolder2* psf) :
  904. _cRef(1)
  905. {
  906. _psf = psf;
  907. ASSERT(psf);
  908. psf->AddRef();
  909. }
  910. CDriveTypeCategorizer::CDriveTypeCategorizer() :
  911. _cRef(1)
  912. {
  913. }
  914. CDriveTypeCategorizer::~CDriveTypeCategorizer()
  915. {
  916. ATOMICRELEASE(_psf);
  917. }
  918. HRESULT CDriveTypeCategorizer::QueryInterface(REFIID riid, void **ppv)
  919. {
  920. static const QITAB qit[] =
  921. {
  922. QITABENT(CDriveTypeCategorizer, ICategorizer),
  923. QITABENT(CDriveTypeCategorizer, IShellExtInit),
  924. { 0 },
  925. };
  926. return QISearch(this, qit, riid, ppv);
  927. }
  928. ULONG CDriveTypeCategorizer::AddRef()
  929. {
  930. return InterlockedIncrement(&_cRef);
  931. }
  932. ULONG CDriveTypeCategorizer::Release()
  933. {
  934. ASSERT( 0 != _cRef );
  935. ULONG cRef = InterlockedDecrement(&_cRef);
  936. if ( 0 == cRef )
  937. {
  938. delete this;
  939. }
  940. return cRef;
  941. }
  942. HRESULT CDriveTypeCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
  943. {
  944. ATOMICRELEASE(_psf);
  945. return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
  946. }
  947. HRESULT CDriveTypeCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
  948. {
  949. LoadString(HINST_THISDLL, IDS_GROUPBYDRIVETYPE, pszDesc, cch);
  950. return S_OK;
  951. }
  952. const struct { DWORD dwDescriptionId; UINT uIDGroup; } c_drives_mapping[] =
  953. {
  954. { SHDID_COMPUTER_FIXED , IDS_DRIVES_FIXED_GROUP },
  955. { SHDID_COMPUTER_DRIVE35 , IDS_DRIVES_REMOVABLE_GROUP },
  956. { SHDID_COMPUTER_REMOVABLE , IDS_DRIVES_REMOVABLE_GROUP },
  957. { SHDID_COMPUTER_CDROM , IDS_DRIVES_REMOVABLE_GROUP },
  958. { SHDID_COMPUTER_NETDRIVE , IDS_DRIVES_NETDRIVE_GROUP },
  959. { SHDID_COMPUTER_OTHER , IDS_DRIVES_OTHER_GROUP },
  960. { SHDID_COMPUTER_DRIVE525 , IDS_DRIVES_REMOVABLE_GROUP },
  961. { SHDID_COMPUTER_RAMDISK , IDS_DRIVES_OTHER_GROUP },
  962. { SHDID_COMPUTER_IMAGING , IDS_DRIVES_IMAGING_GROUP },
  963. { SHDID_COMPUTER_AUDIO , IDS_DRIVES_AUDIO_GROUP },
  964. { SHDID_COMPUTER_SHAREDDOCS, IDS_DRIVES_SHAREDDOCS_GROUP},
  965. };
  966. HRESULT CDriveTypeCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
  967. {
  968. HRESULT hr;
  969. if (_psf == NULL)
  970. {
  971. hr = E_ACCESSDENIED; // Not initialized yet.
  972. }
  973. else
  974. {
  975. for (UINT i = 0; i < cidl; i++)
  976. {
  977. rgCategoryIds[i] = IDS_DRIVES_OTHER_GROUP;
  978. VARIANT v;
  979. // Get the type data
  980. hr = _psf->GetDetailsEx(apidl[i], &SCID_DESCRIPTIONID, &v);
  981. if (SUCCEEDED(hr))
  982. {
  983. SHDESCRIPTIONID did;
  984. if (VariantToBuffer(&v, &did, sizeof(did)))
  985. {
  986. for (int j = 0; j < ARRAYSIZE(c_drives_mapping); j++)
  987. {
  988. if (did.dwDescriptionId == c_drives_mapping[j].dwDescriptionId)
  989. {
  990. rgCategoryIds[i] = c_drives_mapping[j].uIDGroup;
  991. break;
  992. }
  993. }
  994. }
  995. VariantClear(&v);
  996. }
  997. }
  998. hr = S_OK;
  999. }
  1000. return hr;
  1001. }
  1002. HRESULT CDriveTypeCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
  1003. {
  1004. LoadString(HINST_THISDLL, dwCategoryId, pci->wszName, ARRAYSIZE(pci->wszName));
  1005. return S_OK;
  1006. }
  1007. HRESULT CDriveTypeCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
  1008. {
  1009. if (dwCategoryId1 == dwCategoryId2)
  1010. return ResultFromShort(0);
  1011. else if (dwCategoryId1 < dwCategoryId2)
  1012. return ResultFromShort(-1);
  1013. else
  1014. return ResultFromShort(1);
  1015. }
  1016. /////////////////////////////////////////////////////////
  1017. // FreeSpace Categorizer
  1018. CFreeSpaceCategorizer::CFreeSpaceCategorizer() : _cRef(1)
  1019. {
  1020. }
  1021. CFreeSpaceCategorizer::~CFreeSpaceCategorizer()
  1022. {
  1023. ATOMICRELEASE(_psf);
  1024. }
  1025. HRESULT CFreeSpaceCategorizer::QueryInterface(REFIID riid, void **ppv)
  1026. {
  1027. static const QITAB qit[] =
  1028. {
  1029. QITABENT(CFreeSpaceCategorizer, ICategorizer),
  1030. QITABENT(CFreeSpaceCategorizer, IShellExtInit),
  1031. { 0 },
  1032. };
  1033. return QISearch(this, qit, riid, ppv);
  1034. }
  1035. ULONG CFreeSpaceCategorizer::AddRef()
  1036. {
  1037. return InterlockedIncrement(&_cRef);
  1038. }
  1039. ULONG CFreeSpaceCategorizer::Release()
  1040. {
  1041. ASSERT( 0 != _cRef );
  1042. ULONG cRef = InterlockedDecrement(&_cRef);
  1043. if ( 0 == cRef )
  1044. {
  1045. delete this;
  1046. }
  1047. return cRef;
  1048. }
  1049. HRESULT CFreeSpaceCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
  1050. {
  1051. ATOMICRELEASE(_psf);
  1052. return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
  1053. }
  1054. HRESULT CFreeSpaceCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
  1055. {
  1056. LoadString(HINST_THISDLL, IDS_GROUPBYFREESPACE, pszDesc, cch);
  1057. return S_OK;
  1058. }
  1059. HRESULT CFreeSpaceCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST* apidl, DWORD* rgCategoryIds)
  1060. {
  1061. if (_psf == NULL)
  1062. return E_ACCESSDENIED; // Not initialized yet.
  1063. for (UINT i = 0; i < cidl; i++)
  1064. {
  1065. rgCategoryIds[i] = IDS_UNSPECIFIED;
  1066. // Get the total size and free space
  1067. ULONGLONG ullSize;
  1068. if (SUCCEEDED(GetLongProperty(_psf, apidl[i], &SCID_CAPACITY, &ullSize)))
  1069. {
  1070. ULONGLONG ullFree;
  1071. if (SUCCEEDED(GetLongProperty(_psf, apidl[i], &SCID_FREESPACE, &ullFree)))
  1072. {
  1073. // Prevent divide by zero
  1074. if (ullSize == 0)
  1075. {
  1076. rgCategoryIds[i] = IDS_UNSPECIFIED;
  1077. }
  1078. else
  1079. {
  1080. // Turning this into a percent. DWORD cast is ok.
  1081. rgCategoryIds[i] = (static_cast<DWORD>((ullFree * 100) / ullSize) / 10) * 10;
  1082. }
  1083. }
  1084. }
  1085. }
  1086. return S_OK;
  1087. }
  1088. HRESULT CFreeSpaceCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
  1089. {
  1090. if (dwCategoryId == IDS_UNSPECIFIED)
  1091. {
  1092. LoadString(HINST_THISDLL, IDS_UNSPECIFIED, pci->wszName, ARRAYSIZE(pci->wszName));
  1093. return S_OK;
  1094. }
  1095. else
  1096. {
  1097. TCHAR szName[MAX_PATH];
  1098. LoadString(HINST_THISDLL, IDS_FREESPACEPERCENT, szName, ARRAYSIZE(szName));
  1099. wnsprintf(pci->wszName, ARRAYSIZE(pci->wszName), szName, dwCategoryId);
  1100. return S_OK;
  1101. }
  1102. return E_FAIL;
  1103. }
  1104. HRESULT CFreeSpaceCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
  1105. {
  1106. if (dwCategoryId1 == IDS_UNSPECIFIED)
  1107. return ResultFromShort(1);
  1108. else if (dwCategoryId2 == IDS_UNSPECIFIED)
  1109. return ResultFromShort(-1);
  1110. else if (dwCategoryId1 == dwCategoryId2)
  1111. return ResultFromShort(0);
  1112. else if (dwCategoryId1 < dwCategoryId2)
  1113. return ResultFromShort(-1);
  1114. else
  1115. return ResultFromShort(1);
  1116. }
  1117. STDAPI CFreeSpaceCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  1118. {
  1119. HRESULT hr = E_OUTOFMEMORY;
  1120. CFreeSpaceCategorizer* p = new CFreeSpaceCategorizer();
  1121. if (p)
  1122. {
  1123. hr = p->QueryInterface(riid, ppv);
  1124. p->Release();
  1125. }
  1126. return hr;
  1127. }
  1128. /////////////////////////////////////////////////////////
  1129. // Detail Categorizer
  1130. STDAPI CDetailCategorizer_Create(const SHCOLUMNID& pscid, IShellFolder2* psf2, REFIID riid, void **ppv)
  1131. {
  1132. HRESULT hr = E_OUTOFMEMORY;
  1133. CDetailCategorizer* p = new CDetailCategorizer(psf2, pscid);
  1134. if (p)
  1135. {
  1136. hr = p->QueryInterface(riid, ppv);
  1137. p->Release();
  1138. }
  1139. return hr;
  1140. }
  1141. CDetailCategorizer::CDetailCategorizer(IShellFolder2* psf, const SHCOLUMNID& scid) : _cRef(1)
  1142. {
  1143. _psf = psf;
  1144. psf->AddRef();
  1145. _scid = scid;
  1146. _hash = CreateHashItemTable(10, sizeof(DWORD));
  1147. _hdpaKeys = DPA_Create(10);
  1148. }
  1149. CDetailCategorizer::~CDetailCategorizer()
  1150. {
  1151. _psf->Release();
  1152. DestroyHashItemTable(_hash);
  1153. DPA_Destroy(_hdpaKeys);
  1154. }
  1155. HRESULT CDetailCategorizer::QueryInterface(REFIID riid, void **ppv)
  1156. {
  1157. static const QITAB qit[] =
  1158. {
  1159. QITABENT(CDetailCategorizer, ICategorizer),
  1160. { 0 },
  1161. };
  1162. return QISearch(this, qit, riid, ppv);
  1163. }
  1164. ULONG CDetailCategorizer::AddRef()
  1165. {
  1166. return InterlockedIncrement(&_cRef);
  1167. }
  1168. ULONG CDetailCategorizer::Release()
  1169. {
  1170. ASSERT( 0 != _cRef );
  1171. ULONG cRef = InterlockedDecrement(&_cRef);
  1172. if ( 0 == cRef )
  1173. {
  1174. delete this;
  1175. }
  1176. return cRef;
  1177. }
  1178. HRESULT CDetailCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
  1179. {
  1180. return E_FAIL;
  1181. }
  1182. HRESULT CDetailCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
  1183. {
  1184. if (!_hash || !_hdpaKeys)
  1185. return E_OUTOFMEMORY;
  1186. for (UINT i = 0; i < cidl; i++)
  1187. {
  1188. VARIANT v;
  1189. rgCategoryIds[i] = GROUPID_UNSPECIFIED;
  1190. HRESULT hr = _psf->GetDetailsEx(apidl[i], &_scid, &v);
  1191. if (hr == S_OK) // GetDetails returns S_FALSE for failure.
  1192. {
  1193. WCHAR szValue[MAX_PATH];
  1194. if (SUCCEEDED(SHFormatForDisplay(_scid.fmtid, _scid.pid, (PROPVARIANT*)&v, PUIFFDF_DEFAULT, szValue, ARRAYSIZE(szValue))))
  1195. {
  1196. LPCTSTR pszKey = FindHashItem(_hash, szValue);
  1197. if (pszKey)
  1198. {
  1199. rgCategoryIds[i] = (DWORD)GetHashItemData(_hash, pszKey, 0);
  1200. }
  1201. else
  1202. {
  1203. pszKey = AddHashItem(_hash, szValue);
  1204. if (pszKey)
  1205. {
  1206. rgCategoryIds[i] = DPA_AppendPtr(_hdpaKeys, (void*)pszKey);
  1207. SetHashItemData(_hash, pszKey, 0, rgCategoryIds[i]);
  1208. }
  1209. }
  1210. }
  1211. VariantClear(&v);
  1212. }
  1213. }
  1214. return S_OK;
  1215. }
  1216. HRESULT CDetailCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
  1217. {
  1218. HRESULT hr = E_OUTOFMEMORY;
  1219. if (_hash|| _hdpaKeys)
  1220. {
  1221. if (dwCategoryId == GROUPID_UNSPECIFIED || dwCategoryId == GROUPID_FOLDER)
  1222. {
  1223. LoadString(HINST_THISDLL, STRINGID_FROM_GROUPID(dwCategoryId), pci->wszName, ARRAYSIZE(pci->wszName));
  1224. hr = S_OK;
  1225. }
  1226. else
  1227. {
  1228. LPCTSTR pszKey = (LPCTSTR)DPA_FastGetPtr(_hdpaKeys, dwCategoryId);
  1229. if (pszKey)
  1230. {
  1231. LPCTSTR psz = FindHashItem(_hash, pszKey);
  1232. if (psz)
  1233. {
  1234. StrCpyN(pci->wszName, psz, ARRAYSIZE(pci->wszName));
  1235. hr = S_OK;
  1236. }
  1237. }
  1238. else
  1239. {
  1240. hr = E_INVALIDARG;
  1241. }
  1242. }
  1243. }
  1244. return hr;
  1245. }
  1246. HRESULT CDetailCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
  1247. {
  1248. if (dwCategoryId1 == dwCategoryId2)
  1249. {
  1250. return ResultFromShort(0);
  1251. }
  1252. else if (dwCategoryId1 == GROUPID_UNSPECIFIED ||
  1253. dwCategoryId2 == GROUPID_UNSPECIFIED)
  1254. {
  1255. return ResultFromShort((dwCategoryId1 == GROUPID_UNSPECIFIED)? 1 : -1);
  1256. }
  1257. else if (dwCategoryId1 == GROUPID_FOLDER)
  1258. {
  1259. return ResultFromShort(-1);
  1260. }
  1261. else if (dwCategoryId2 == GROUPID_FOLDER)
  1262. {
  1263. return ResultFromShort(1);
  1264. }
  1265. else
  1266. {
  1267. LPCTSTR pszKey1 = (LPCTSTR)DPA_FastGetPtr(_hdpaKeys, dwCategoryId1);
  1268. LPCTSTR pszKey2 = (LPCTSTR)DPA_FastGetPtr(_hdpaKeys, dwCategoryId2);
  1269. LPCTSTR psz1 = FindHashItem(_hash, pszKey1);
  1270. LPCTSTR psz2 = FindHashItem(_hash, pszKey2);
  1271. return ResultFromShort(lstrcmpi(psz1, psz2));
  1272. }
  1273. }
  1274. /////////////////////////////////////////////////////////
  1275. // Alphanumeric Categorizer
  1276. STDAPI CAlphaCategorizer_Create(IShellFolder2* psf2, REFIID riid, void **ppv)
  1277. {
  1278. HRESULT hr = E_OUTOFMEMORY;
  1279. CAlphaCategorizer* p = new CAlphaCategorizer(psf2);
  1280. if (p)
  1281. {
  1282. hr = p->QueryInterface(riid, ppv);
  1283. p->Release();
  1284. }
  1285. return hr;
  1286. }
  1287. CAlphaCategorizer::CAlphaCategorizer(IShellFolder2* psf) : _cRef(1)
  1288. {
  1289. _psf = psf;
  1290. ASSERT(psf);
  1291. psf->AddRef();
  1292. }
  1293. CAlphaCategorizer::~CAlphaCategorizer()
  1294. {
  1295. _psf->Release();
  1296. }
  1297. HRESULT CAlphaCategorizer::QueryInterface(REFIID riid, void **ppv)
  1298. {
  1299. static const QITAB qit[] =
  1300. {
  1301. QITABENT(CAlphaCategorizer, ICategorizer),
  1302. { 0 },
  1303. };
  1304. return QISearch(this, qit, riid, ppv);
  1305. }
  1306. ULONG CAlphaCategorizer::AddRef()
  1307. {
  1308. return InterlockedIncrement(&_cRef);
  1309. }
  1310. ULONG CAlphaCategorizer::Release()
  1311. {
  1312. ASSERT( 0 != _cRef );
  1313. ULONG cRef = InterlockedDecrement(&_cRef);
  1314. if ( 0 == cRef )
  1315. {
  1316. delete this;
  1317. }
  1318. return cRef;
  1319. }
  1320. HRESULT CAlphaCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
  1321. {
  1322. LoadString(HINST_THISDLL, IDS_GROUPALPHABETICALLY, pszDesc, cch);
  1323. return S_OK;
  1324. }
  1325. HRESULT CAlphaCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
  1326. {
  1327. if (_psf == NULL)
  1328. return E_ACCESSDENIED; // Not initialized yet.
  1329. for (UINT i = 0; i < cidl; i++)
  1330. {
  1331. TCHAR szName[MAX_PATH];
  1332. HRESULT hr = DisplayNameOf(_psf, apidl[i], SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  1333. if (SUCCEEDED(hr))
  1334. {
  1335. if (StrChr(TEXT("~`!@#$%^&*()_-+=1234567890<,>.;:'[]{}|"), szName[0]) != NULL)
  1336. {
  1337. rgCategoryIds[i] = GROUPID_OTHER;
  1338. }
  1339. else
  1340. {
  1341. CharUpperBuff(szName, 1);
  1342. rgCategoryIds[i] = (DWORD)szName[0];
  1343. }
  1344. }
  1345. if (FAILED(hr))
  1346. rgCategoryIds[i] = GROUPID_UNSPECIFIED;
  1347. }
  1348. return S_OK;
  1349. }
  1350. HRESULT CAlphaCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
  1351. {
  1352. if (GROUPID_UNSPECIFIED == dwCategoryId ||
  1353. GROUPID_OTHER == dwCategoryId ||
  1354. GROUPID_FOLDER == dwCategoryId)
  1355. {
  1356. LoadString(HINST_THISDLL, STRINGID_FROM_GROUPID(dwCategoryId), pci->wszName, ARRAYSIZE(pci->wszName));
  1357. return S_OK;
  1358. }
  1359. else
  1360. {
  1361. pci->wszName[0] = (WCHAR)dwCategoryId;
  1362. pci->wszName[1] = 0;
  1363. return S_OK;
  1364. }
  1365. }
  1366. HRESULT CAlphaCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
  1367. {
  1368. if (dwCategoryId1 == dwCategoryId2)
  1369. {
  1370. return ResultFromShort(0);
  1371. }
  1372. else if (IDS_UNSPECIFIED == dwCategoryId1 || IDS_GROUPOTHERCHAR == dwCategoryId1)
  1373. {
  1374. return ResultFromShort(1);
  1375. }
  1376. else if (IDS_UNSPECIFIED == dwCategoryId2 || IDS_GROUPOTHERCHAR == dwCategoryId2)
  1377. {
  1378. return ResultFromShort(-1);
  1379. }
  1380. else if (dwCategoryId1 == IDS_GROUPFOLDERS)
  1381. return ResultFromShort(-1);
  1382. else if (dwCategoryId2 == IDS_GROUPFOLDERS)
  1383. return ResultFromShort(1);
  1384. else
  1385. {
  1386. TCHAR szName1[2] = {(WCHAR)dwCategoryId1, 0};
  1387. TCHAR szName2[2] = {(WCHAR)dwCategoryId2, 0};
  1388. return ResultFromShort(lstrcmpi(szName1, szName2));
  1389. }
  1390. }