Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1623 lines
42 KiB

#include "shellprv.h"
#include "category.h"
#include "prop.h"
#include "ids.h"
#include "clsobj.h"
#include "comcat.h" // for IEnumGUID
#include "ole2dup.h"
#define GROUPID_UNSPECIFIED (-10)
#define GROUPID_FOLDER (-11)
#define GROUPID_OTHER (-12)
#define STRINGID_FROM_GROUPID(id) ((id) == GROUPID_UNSPECIFIED)? IDS_UNSPECIFIED : (((id) == GROUPID_FOLDER)?IDS_GROUPFOLDERS: IDS_GROUPOTHERCHAR)
typedef struct tagCATCACHE
{
GUID guid;
SHCOLUMNID scid;
IUnknown* punk;
} CATCACHE;
// {3E373E22-DA99-4cb7-A886-754EAE984CB4}
static const GUID CLSID_DetailCategorizer =
{ 0x3e373e22, 0xda99, 0x4cb7, { 0xa8, 0x86, 0x75, 0x4e, 0xae, 0x98, 0x4c, 0xb4 } };
class CTimeCategorizer : public ICategorizer,
public IShellExtInit
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategorizer
STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
// IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
CTimeCategorizer(const SHCOLUMNID* pscid, IShellFolder2* psf);
CTimeCategorizer();
private:
~CTimeCategorizer();
long _cRef;
IShellFolder2* _psf;
SHCOLUMNID _scid;
};
class CSizeCategorizer : public ICategorizer,
public IShellExtInit
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategorizer
STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
// IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
CSizeCategorizer(IShellFolder2* psf);
CSizeCategorizer(BOOL fLarge);
private:
~CSizeCategorizer();
long _cRef;
IShellFolder2* _psf;
BOOL _fLarge;
};
class CDriveTypeCategorizer : public ICategorizer,
public IShellExtInit
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategorizer
STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
// IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
CDriveTypeCategorizer(IShellFolder2* psf);
CDriveTypeCategorizer();
private:
~CDriveTypeCategorizer();
long _cRef;
IShellFolder2* _psf;
};
class CAlphaCategorizer : public ICategorizer
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategorizer
STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
CAlphaCategorizer(IShellFolder2* psf);
private:
~CAlphaCategorizer();
long _cRef;
IShellFolder2* _psf;
};
class CFreeSpaceCategorizer : public ICategorizer,
public IShellExtInit
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategorizer
STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
// IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID);
CFreeSpaceCategorizer();
private:
~CFreeSpaceCategorizer();
long _cRef;
IShellFolder2* _psf;
};
class CDetailCategorizer : public ICategorizer
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategorizer
STDMETHODIMP GetDescription(LPWSTR pszDesc, UINT cch);
STDMETHODIMP GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds);
STDMETHODIMP GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci);
STDMETHODIMP CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2);
CDetailCategorizer(IShellFolder2* psf, const SHCOLUMNID& scid);
private:
~CDetailCategorizer();
long _cRef;
IShellFolder2* _psf;
SHCOLUMNID _scid;
HHASHTABLE _hash;
HDPA _hdpaKeys;
};
class CEnumCategoryGUID : public IEnumGUID
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IEnumIDList
STDMETHODIMP Next(ULONG celt, GUID *rgelt, ULONG *pceltFetched);
STDMETHODIMP Skip(ULONG celt) { return E_NOTIMPL; }
STDMETHODIMP Reset() { _iIndex = 0; return S_OK;}
STDMETHODIMP Clone(IEnumGUID **ppenum) { return E_NOTIMPL; };
CEnumCategoryGUID(HDSA hdsa);
private:
long _cRef;
HDSA _hda;
int _iIndex;
};
CEnumCategoryGUID::CEnumCategoryGUID(HDSA hda): _cRef(1)
{
_hda = hda;
}
HRESULT CEnumCategoryGUID::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CEnumCategoryGUID, IEnumGUID),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CEnumCategoryGUID::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CEnumCategoryGUID::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
STDMETHODIMP CEnumCategoryGUID::Next(ULONG celt, GUID *rgelt, ULONG *pceltFetched)
{
HRESULT hr = S_FALSE;
if (celt > 1)
return E_INVALIDARG;
if (_hda == NULL)
return hr;
while (hr != S_OK &&
_iIndex < DSA_GetItemCount(_hda))
{
CATCACHE* pcat = (CATCACHE*)DSA_GetItemPtr(_hda, _iIndex);
// Is this a scid map entry instead of an external categorizer?
if (pcat->scid.fmtid == GUID_NULL)
{
// Nope. then we can enum it.
if (pceltFetched)
*pceltFetched = 1;
*rgelt = pcat->guid;
hr = S_OK;
}
_iIndex++;
}
return hr;
}
class CCategoryProvider : public ICategoryProvider, public IDefCategoryProvider
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// ICategoryProvider
STDMETHODIMP CanCategorizeOnSCID(SHCOLUMNID* pscid);
STDMETHODIMP GetDefaultCategory(GUID* pguid, SHCOLUMNID* pscid);
STDMETHODIMP GetCategoryForSCID(SHCOLUMNID* pscid, GUID* pguid);
STDMETHODIMP EnumCategories(IEnumGUID** penum);
STDMETHODIMP GetCategoryName(GUID* pguid, LPWSTR pszName, UINT cch);
STDMETHODIMP CreateCategory(GUID* pguid, REFIID riid, void** ppv);
// IDefCategoryProvider
STDMETHODIMP Initialize(const GUID* pguid, const SHCOLUMNID* pscid, const SHCOLUMNID* pscidExlude, HKEY hkey, const CATLIST* pcl, IShellFolder* psf);
CCategoryProvider();
private:
~CCategoryProvider();
BOOL _BuildCategoryList(HKEY hkey, const CATLIST* pcl);
friend int DestroyCache(void *pv, void *unused);
HRESULT CreateInstance(GUID* pguid, REFIID riid, void** ppv);
long _cRef;
LPITEMIDLIST _pidlFolder;
IShellFolder2* _psf;
HDSA _hdaCat;
GUID _guidDefault;
SHCOLUMNID _scidDefault;
HDSA _hdaExcludeSCIDs;
};
STDAPI CCategoryProvider_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CCategoryProvider* p = new CCategoryProvider();
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
BOOL CCategoryProvider::_BuildCategoryList(HKEY hkey, const CATLIST* pcl)
{
int i = 0;
_hdaCat = DSA_Create(sizeof(CATCACHE), 3);
if (!_hdaCat)
return FALSE;
// Enumerate static
while(!IsEqualGUID(*pcl[i].pguid, GUID_NULL))
{
CATCACHE cc = {0};
cc.guid = *pcl[i].pguid;
if (pcl[i].pscid)
{
cc.scid = *pcl[i].pscid;
}
DSA_AppendItem(_hdaCat, (void*)&cc);
i++;
}
// Enumerate hkey
TCHAR szHandlerCLSID[GUIDSTR_MAX];
int iHandler = 0;
while (ERROR_SUCCESS == RegEnumKey(hkey, iHandler++, szHandlerCLSID, ARRAYSIZE(szHandlerCLSID)))
{
CLSID clsid;
if (SUCCEEDED(SHCLSIDFromString(szHandlerCLSID, &clsid)))
{
CATCACHE cc = {0};
cc.guid = clsid;
DSA_AppendItem(_hdaCat, (void*)&cc);
i++;
}
}
return TRUE;
}
CCategoryProvider::CCategoryProvider() : _cRef(1)
{
DllAddRef();
}
int DestroyCache(void *pv, void *unused)
{
CATCACHE* pcat = (CATCACHE*)pv;
ATOMICRELEASE(pcat->punk);
return 1;
}
CCategoryProvider::~CCategoryProvider()
{
ATOMICRELEASE(_psf);
ILFree(_pidlFolder);
if (_hdaExcludeSCIDs)
{
DSA_Destroy(_hdaExcludeSCIDs);
}
if (_hdaCat)
{
DSA_DestroyCallback(_hdaCat, DestroyCache, NULL);
}
DllRelease();
}
HRESULT CCategoryProvider::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CCategoryProvider, IDefCategoryProvider),
QITABENT(CCategoryProvider, ICategoryProvider),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CCategoryProvider::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CCategoryProvider::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CCategoryProvider::Initialize(const GUID* pguid, const SHCOLUMNID* pscid, const SHCOLUMNID* pscidExclude, HKEY hkey, const CATLIST* pcl, IShellFolder* psf)
{
if (!psf)
return E_INVALIDARG;
HRESULT hr = SHGetIDListFromUnk(psf, &_pidlFolder);
if (SUCCEEDED(hr))
{
if (pcl && !_BuildCategoryList(hkey, pcl))
return E_OUTOFMEMORY;
if (pguid)
_guidDefault = *pguid;
if (pscid)
_scidDefault = *pscid;
if (pscidExclude)
{
_hdaExcludeSCIDs = DSA_Create(sizeof(SHCOLUMNID), 3);
if (_hdaExcludeSCIDs)
{
int i = 0;
while(pscidExclude[i].fmtid != GUID_NULL)
{
DSA_AppendItem(_hdaExcludeSCIDs, (void*)&pscidExclude[i]);
i++;
}
}
}
hr = psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf));
}
return hr;
}
STDMETHODIMP CCategoryProvider::CanCategorizeOnSCID(SHCOLUMNID* pscid)
{
if (_hdaExcludeSCIDs)
{
for (int i=0; i < DSA_GetItemCount(_hdaExcludeSCIDs); i++)
{
SHCOLUMNID* pscidExclude = (SHCOLUMNID*)DSA_GetItemPtr(_hdaExcludeSCIDs, i);
if (IsEqualSCID(*pscidExclude, *pscid))
return S_FALSE;
}
}
return S_OK;
}
STDMETHODIMP CCategoryProvider::GetDefaultCategory(GUID* pguid, SHCOLUMNID* pscid)
{
*pguid = _guidDefault;
*pscid = _scidDefault;
if (_guidDefault == GUID_NULL && _scidDefault.fmtid == GUID_NULL)
return S_FALSE;
return S_OK;
}
STDMETHODIMP CCategoryProvider::GetCategoryForSCID(SHCOLUMNID* pscid, GUID* pguid)
{
HRESULT hr = S_FALSE;
if (_hdaCat == NULL || pscid == NULL)
return hr;
int c = DSA_GetItemCount(_hdaCat);
for (int i = 0; i < c; i++)
{
CATCACHE* pcc = (CATCACHE*)DSA_GetItemPtr(_hdaCat, i);
ASSERT(pcc != NULL);
if (IsEqualSCID(pcc->scid, *pscid))
{
*pguid = pcc->guid;
hr = S_OK;
break;
}
}
return hr;
}
STDMETHODIMP CCategoryProvider::EnumCategories(IEnumGUID** penum)
{
HRESULT hr = E_NOINTERFACE;
if (_hdaCat)
{
*penum = (IEnumGUID*)new CEnumCategoryGUID(_hdaCat);
if (!*penum)
hr = E_OUTOFMEMORY;
hr = S_OK;
}
return hr;
}
STDMETHODIMP CCategoryProvider::GetCategoryName(GUID* pguid, LPWSTR pszName, UINT cch)
{
ICategorizer* pcat;
HRESULT hr = CreateCategory(pguid, IID_PPV_ARG(ICategorizer, &pcat));
if (SUCCEEDED(hr))
{
hr = pcat->GetDescription(pszName, cch);
pcat->Release();
}
return hr;
}
HRESULT CCategoryProvider::CreateInstance(GUID* pguid, REFIID riid, void** ppv)
{
IShellExtInit* psei;
// These come from HKCR hence must go through approval
HRESULT hr = SHExtCoCreateInstance(NULL, pguid, NULL, IID_PPV_ARG(IShellExtInit, &psei));
if (SUCCEEDED(hr))
{
psei->Initialize(_pidlFolder, NULL, NULL);
hr = psei->QueryInterface(riid, ppv);
psei->Release();
}
return hr;
}
STDMETHODIMP CCategoryProvider::CreateCategory(GUID* pguid, REFIID riid, void** ppv)
{
HRESULT hr = E_NOINTERFACE;
if (_hdaCat != NULL)
{
int c = DSA_GetItemCount(_hdaCat);
for (int i = 0; i < c; i++)
{
CATCACHE* pcc = (CATCACHE*)DSA_GetItemPtr(_hdaCat, i);
ASSERT(pcc != NULL);
if (IsEqualGUID(pcc->guid, *pguid))
{
if (!pcc->punk)
{
hr = CreateInstance(pguid, IID_PPV_ARG(IUnknown, &pcc->punk));
}
if (pcc->punk)
{
hr = pcc->punk->QueryInterface(riid, ppv);
}
break;
}
}
}
if (FAILED(hr))
{
// Not in the cache? Just try a create
hr = CreateInstance(pguid, riid, ppv);
}
return hr;
}
STDAPI CCategoryProvider_Create(const GUID* pguid, const SHCOLUMNID* pscid, HKEY hkey, const CATLIST* pcl, IShellFolder* psf, REFIID riid, void **ppv)
{
HRESULT hr;
CCategoryProvider *pdext = new CCategoryProvider();
if (pdext)
{
hr = pdext->Initialize(pguid, pscid, NULL, hkey, pcl, psf);
if (SUCCEEDED(hr))
hr = pdext->QueryInterface(riid, ppv);
pdext->Release();
}
else
{
*ppv = NULL;
hr = E_OUTOFMEMORY;
}
return hr;
}
/////////////////////////////////////////////////////////
// Time Categorizer
STDAPI CTimeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CTimeCategorizer* p = new CTimeCategorizer();
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
STDAPI CTimeCategorizer_Create(IShellFolder2* psf2, const SHCOLUMNID* pscid, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CTimeCategorizer* p = new CTimeCategorizer(pscid, psf2);
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
CTimeCategorizer::CTimeCategorizer(const SHCOLUMNID* pscid, IShellFolder2* psf) : _cRef(1)
{
_psf = psf;
ASSERT(psf);
psf->AddRef();
_scid = *pscid;
}
CTimeCategorizer::CTimeCategorizer() : _cRef(1)
{
_scid = SCID_WRITETIME;
}
CTimeCategorizer::~CTimeCategorizer()
{
ATOMICRELEASE(_psf);
}
HRESULT CTimeCategorizer::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CTimeCategorizer, ICategorizer),
QITABENT(CTimeCategorizer, IShellExtInit),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CTimeCategorizer::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CTimeCategorizer::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CTimeCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
{
ATOMICRELEASE(_psf);
return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
}
HRESULT CTimeCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
{
LoadString(HINST_THISDLL, IDS_GROUPBYTIME, pszDesc, cch);
return S_OK;
}
static const int mpcdymoAccum[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
int GetDaysForMonth(int yr, int mo)
{
int cdy;
if (yr == 1752 && mo == 9)
return 19;
cdy = mpcdymoAccum[mo] - mpcdymoAccum[mo - 1];
if (mo == 2 && (yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
cdy++;
return cdy;
}
int GetDaysForLastMonth(int year, int month)
{
if (month == 1)
{
year--;
month = 12;
}
else
month--;
return GetDaysForMonth(year, month);
}
HRESULT CTimeCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
{
SYSTEMTIME stCur;
GetLocalTime(&stCur);
for (UINT i = 0; i < cidl; i++)
{
FILETIME ft;
// Get the time data
if (SUCCEEDED(GetDateProperty(_psf, apidl[i], &_scid, &ft)))
{
// Convert it to a usable format
SYSTEMTIME stFile;
FileTimeToLocalFileTime(&ft, &ft);
FileTimeToSystemTime(&ft, &stFile);
if (stFile.wYear == stCur.wYear)
{
if (stFile.wMonth > stCur.wMonth)
{
if (stFile.wMonth == stCur.wMonth + 1)
{
rgCategoryIds[i] = IDS_NEXTMONTH;
}
else
{
rgCategoryIds[i] = IDS_LATERTHISYEAR;
}
}
else if (stFile.wMonth == stCur.wMonth)
{
if (stFile.wDay == stCur.wDay + 1)
{
rgCategoryIds[i] = IDS_TOMORROW;
}
else if (stFile.wDay == stCur.wDay + 2)
{
rgCategoryIds[i] = IDS_TWODAYSFROMNOW;
}
else if (stFile.wDay == stCur.wDay)
{
rgCategoryIds[i] = IDS_TODAY;
}
else if (stFile.wDay == stCur.wDay - 1)
{
rgCategoryIds[i] = IDS_YESTERDAY;
}
else if (stFile.wDayOfWeek < stCur.wDayOfWeek &&
stFile.wDay < stCur.wDay &&
stCur.wDay - stCur.wDayOfWeek > 0 &&
stFile.wDay >= stCur.wDay - stCur.wDayOfWeek)
{
rgCategoryIds[i] = IDS_EARLIERTHISWEEK;
}
else if (stFile.wDayOfWeek > stCur.wDayOfWeek &&
stFile.wDay > stCur.wDay &&
stFile.wDay <= stCur.wDay + (7 - stCur.wDayOfWeek))
{
rgCategoryIds[i] = IDS_LATERTHISWEEK;
}
else if (stFile.wDay > stCur.wDay)
{
rgCategoryIds[i] = IDS_LATERTHISMONTH;
}
else
{
int fileDays = GetDaysForLastMonth(stFile.wYear, stFile.wMonth - 1) + stFile.wDay;
int curDays = GetDaysForLastMonth(stCur.wYear, stCur.wMonth - 1) + stCur.wDay;
if (fileDays < (curDays - stCur.wDayOfWeek) &&
fileDays > (curDays - stCur.wDayOfWeek - 7))
{
rgCategoryIds[i] = IDS_LASTWEEK;
}
else if (fileDays < (curDays - stCur.wDayOfWeek - 7) &&
fileDays > (curDays - stCur.wDayOfWeek - 14))
{
rgCategoryIds[i] = IDS_TWOWEEKSAGO;
}
else
{
rgCategoryIds[i] = IDS_EARLIERTHISMONTH;
}
}
}
else if (stFile.wMonth == stCur.wMonth - 1 ||
(stFile.wMonth == 12 &&
stCur.wMonth == 1))
{
rgCategoryIds[i] = IDS_LASTMONTH;
}
else if (stFile.wMonth == stCur.wMonth - 2 ||
(stFile.wMonth == 12 && stCur.wMonth == 2) ||
(stFile.wMonth == 11 && stCur.wMonth == 1))
{
rgCategoryIds[i] = IDS_TWOMONTHSAGO;
}
else
{
rgCategoryIds[i] = IDS_EARLIERTHISYEAR;
}
}
else if (stFile.wYear == stCur.wYear - 1)
{
rgCategoryIds[i] = IDS_LASTYEAR;
}
else if (stFile.wYear == stCur.wYear - 2)
{
rgCategoryIds[i] = IDS_TWOYEARSAGO;
}
else if (stFile.wYear < stCur.wYear - 2)
{
rgCategoryIds[i] = IDS_LONGTIMEAGO;
}
else if (stFile.wYear == stCur.wYear + 1)
{
rgCategoryIds[i] = IDS_NEXTYEAR;
}
else if (stFile.wYear > stCur.wYear + 2)
{
rgCategoryIds[i] = IDS_SOMETIMETHISMILLENNIA;
}
else if (stFile.wYear > (stCur.wYear / 1000) * 1000 + 1000) // 2050 / 1000 = 2. 2 * 1000 = 2000. 2000 + 1000 = 3000 i.e. next millennium
{
rgCategoryIds[i] = IDS_SOMEFUTUREDATE;
}
}
else
{
rgCategoryIds[i] = IDS_UNSPECIFIED;
}
}
return S_OK;
}
HRESULT CTimeCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
{
LoadString(HINST_THISDLL, dwCategoryId, pci->wszName, ARRAYSIZE(pci->wszName));
return S_OK;
}
HRESULT CTimeCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
{
if (dwCategoryId1 == dwCategoryId2)
return ResultFromShort(0);
else if (dwCategoryId1 == IDS_GROUPFOLDERS)
return ResultFromShort(-1);
else if (dwCategoryId2 == IDS_GROUPFOLDERS)
return ResultFromShort(1);
else if (dwCategoryId1 < dwCategoryId2)
return ResultFromShort(-1);
else
return ResultFromShort(1);
}
/////////////////////////////////////////////////////////
// Size Categorizer
STDAPI CDriveSizeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CSizeCategorizer* p = new CSizeCategorizer(TRUE);
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
STDAPI CSizeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CSizeCategorizer* p = new CSizeCategorizer(FALSE);
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
STDAPI CSizeCategorizer_Create(IShellFolder2* psf2, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CSizeCategorizer* p = new CSizeCategorizer(psf2);
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
CSizeCategorizer::CSizeCategorizer(IShellFolder2* psf) : _cRef(1)
{
_psf = psf;
ASSERT(psf);
psf->AddRef();
}
CSizeCategorizer::CSizeCategorizer(BOOL fLarge) : _cRef(1), _fLarge(fLarge)
{
}
CSizeCategorizer::~CSizeCategorizer()
{
ATOMICRELEASE(_psf);
}
HRESULT CSizeCategorizer::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CSizeCategorizer, ICategorizer),
QITABENT(CSizeCategorizer, IShellExtInit),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CSizeCategorizer::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CSizeCategorizer::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CSizeCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
{
ATOMICRELEASE(_psf);
return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
}
HRESULT CSizeCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
{
LoadString(HINST_THISDLL, IDS_GROUPBYSIZE, pszDesc, cch);
return S_OK;
}
const static ULONGLONG s_rgSizesSmall[] =
{
// 130mb 16mb 1mb 100k 10l
134217728, 16777216, 1048576, 131072, 32768, 0
};
const static ULONGLONG s_rgSizesLarge[] =
{
// 80gig 25gig 10gig 2gig 500mb
80000000000, 25000000000, 10000000000, 2000000000, 500000000, 0
};
HRESULT CSizeCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
{
if (_psf == NULL)
return E_ACCESSDENIED; // Not initialized yet.
for (UINT i = 0; i < cidl; i++)
{
const ULONGLONG* pll = _fLarge? s_rgSizesLarge : s_rgSizesSmall;
// Get the size data
ULONGLONG ullSize;
if (SUCCEEDED(GetLongProperty(_psf, apidl[i], _fLarge?&SCID_CAPACITY:&SCID_SIZE, &ullSize)))
{
if (ullSize >= pll[0])
rgCategoryIds[i] = IDS_GIGANTIC;
if (ullSize < pll[0])
rgCategoryIds[i] = IDS_HUGE;
if (ullSize < pll[1]) // Under 16mb
rgCategoryIds[i] = IDS_LARGE;
if (ullSize < pll[2]) // Under 1mb
rgCategoryIds[i] = IDS_MEDIUM;
if (ullSize < pll[3]) // Under 100k
rgCategoryIds[i] = IDS_SMALL;
if (ullSize < pll[4]) // Under 10k
rgCategoryIds[i] = IDS_TINY;
if (ullSize == pll[5]) // Zero sized files
{
if (SHGetAttributes(_psf, apidl[i], SFGAO_FOLDER))
{
rgCategoryIds[i] = IDS_FOLDERS;
}
else
{
rgCategoryIds[i] = IDS_ZERO;
}
}
}
else
{
rgCategoryIds[i] = IDS_UNSPECIFIED;
}
}
return S_OK;
}
HRESULT CSizeCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
{
LoadString(HINST_THISDLL, dwCategoryId, pci->wszName, ARRAYSIZE(pci->wszName));
return S_OK;
}
HRESULT CSizeCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
{
if (dwCategoryId1 == dwCategoryId2)
return ResultFromShort(0);
else if (dwCategoryId1 == IDS_GROUPFOLDERS)
return ResultFromShort(-1);
else if (dwCategoryId2 == IDS_GROUPFOLDERS)
return ResultFromShort(1);
else if (dwCategoryId1 < dwCategoryId2)
return ResultFromShort(-1);
else
return ResultFromShort(1);
}
/////////////////////////////////////////////////////////
// Type Categorizer
STDAPI CDriveTypeCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
CDriveTypeCategorizer *p = new CDriveTypeCategorizer();
if (!p)
return E_OUTOFMEMORY;
HRESULT hr = p->QueryInterface(riid, ppv);
p->Release();
return hr;
}
CDriveTypeCategorizer::CDriveTypeCategorizer(IShellFolder2* psf) :
_cRef(1)
{
_psf = psf;
ASSERT(psf);
psf->AddRef();
}
CDriveTypeCategorizer::CDriveTypeCategorizer() :
_cRef(1)
{
}
CDriveTypeCategorizer::~CDriveTypeCategorizer()
{
ATOMICRELEASE(_psf);
}
HRESULT CDriveTypeCategorizer::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CDriveTypeCategorizer, ICategorizer),
QITABENT(CDriveTypeCategorizer, IShellExtInit),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CDriveTypeCategorizer::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CDriveTypeCategorizer::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CDriveTypeCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
{
ATOMICRELEASE(_psf);
return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
}
HRESULT CDriveTypeCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
{
LoadString(HINST_THISDLL, IDS_GROUPBYDRIVETYPE, pszDesc, cch);
return S_OK;
}
const struct { DWORD dwDescriptionId; UINT uIDGroup; } c_drives_mapping[] =
{
{ SHDID_COMPUTER_FIXED , IDS_DRIVES_FIXED_GROUP },
{ SHDID_COMPUTER_DRIVE35 , IDS_DRIVES_REMOVABLE_GROUP },
{ SHDID_COMPUTER_REMOVABLE , IDS_DRIVES_REMOVABLE_GROUP },
{ SHDID_COMPUTER_CDROM , IDS_DRIVES_REMOVABLE_GROUP },
{ SHDID_COMPUTER_NETDRIVE , IDS_DRIVES_NETDRIVE_GROUP },
{ SHDID_COMPUTER_OTHER , IDS_DRIVES_OTHER_GROUP },
{ SHDID_COMPUTER_DRIVE525 , IDS_DRIVES_REMOVABLE_GROUP },
{ SHDID_COMPUTER_RAMDISK , IDS_DRIVES_OTHER_GROUP },
{ SHDID_COMPUTER_IMAGING , IDS_DRIVES_IMAGING_GROUP },
{ SHDID_COMPUTER_AUDIO , IDS_DRIVES_AUDIO_GROUP },
{ SHDID_COMPUTER_SHAREDDOCS, IDS_DRIVES_SHAREDDOCS_GROUP},
};
HRESULT CDriveTypeCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
{
HRESULT hr;
if (_psf == NULL)
{
hr = E_ACCESSDENIED; // Not initialized yet.
}
else
{
for (UINT i = 0; i < cidl; i++)
{
rgCategoryIds[i] = IDS_DRIVES_OTHER_GROUP;
VARIANT v;
// Get the type data
hr = _psf->GetDetailsEx(apidl[i], &SCID_DESCRIPTIONID, &v);
if (SUCCEEDED(hr))
{
SHDESCRIPTIONID did;
if (VariantToBuffer(&v, &did, sizeof(did)))
{
for (int j = 0; j < ARRAYSIZE(c_drives_mapping); j++)
{
if (did.dwDescriptionId == c_drives_mapping[j].dwDescriptionId)
{
rgCategoryIds[i] = c_drives_mapping[j].uIDGroup;
break;
}
}
}
VariantClear(&v);
}
}
hr = S_OK;
}
return hr;
}
HRESULT CDriveTypeCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
{
LoadString(HINST_THISDLL, dwCategoryId, pci->wszName, ARRAYSIZE(pci->wszName));
return S_OK;
}
HRESULT CDriveTypeCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
{
if (dwCategoryId1 == dwCategoryId2)
return ResultFromShort(0);
else if (dwCategoryId1 < dwCategoryId2)
return ResultFromShort(-1);
else
return ResultFromShort(1);
}
/////////////////////////////////////////////////////////
// FreeSpace Categorizer
CFreeSpaceCategorizer::CFreeSpaceCategorizer() : _cRef(1)
{
}
CFreeSpaceCategorizer::~CFreeSpaceCategorizer()
{
ATOMICRELEASE(_psf);
}
HRESULT CFreeSpaceCategorizer::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CFreeSpaceCategorizer, ICategorizer),
QITABENT(CFreeSpaceCategorizer, IShellExtInit),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CFreeSpaceCategorizer::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CFreeSpaceCategorizer::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CFreeSpaceCategorizer::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkeyProgID)
{
ATOMICRELEASE(_psf);
return SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidlFolder, &_psf));
}
HRESULT CFreeSpaceCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
{
LoadString(HINST_THISDLL, IDS_GROUPBYFREESPACE, pszDesc, cch);
return S_OK;
}
HRESULT CFreeSpaceCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST* apidl, DWORD* rgCategoryIds)
{
if (_psf == NULL)
return E_ACCESSDENIED; // Not initialized yet.
for (UINT i = 0; i < cidl; i++)
{
rgCategoryIds[i] = IDS_UNSPECIFIED;
// Get the total size and free space
ULONGLONG ullSize;
if (SUCCEEDED(GetLongProperty(_psf, apidl[i], &SCID_CAPACITY, &ullSize)))
{
ULONGLONG ullFree;
if (SUCCEEDED(GetLongProperty(_psf, apidl[i], &SCID_FREESPACE, &ullFree)))
{
// Prevent divide by zero
if (ullSize == 0)
{
rgCategoryIds[i] = IDS_UNSPECIFIED;
}
else
{
// Turning this into a percent. DWORD cast is ok.
rgCategoryIds[i] = (static_cast<DWORD>((ullFree * 100) / ullSize) / 10) * 10;
}
}
}
}
return S_OK;
}
HRESULT CFreeSpaceCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
{
if (dwCategoryId == IDS_UNSPECIFIED)
{
LoadString(HINST_THISDLL, IDS_UNSPECIFIED, pci->wszName, ARRAYSIZE(pci->wszName));
return S_OK;
}
else
{
TCHAR szName[MAX_PATH];
LoadString(HINST_THISDLL, IDS_FREESPACEPERCENT, szName, ARRAYSIZE(szName));
wnsprintf(pci->wszName, ARRAYSIZE(pci->wszName), szName, dwCategoryId);
return S_OK;
}
return E_FAIL;
}
HRESULT CFreeSpaceCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
{
if (dwCategoryId1 == IDS_UNSPECIFIED)
return ResultFromShort(1);
else if (dwCategoryId2 == IDS_UNSPECIFIED)
return ResultFromShort(-1);
else if (dwCategoryId1 == dwCategoryId2)
return ResultFromShort(0);
else if (dwCategoryId1 < dwCategoryId2)
return ResultFromShort(-1);
else
return ResultFromShort(1);
}
STDAPI CFreeSpaceCategorizer_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CFreeSpaceCategorizer* p = new CFreeSpaceCategorizer();
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
/////////////////////////////////////////////////////////
// Detail Categorizer
STDAPI CDetailCategorizer_Create(const SHCOLUMNID& pscid, IShellFolder2* psf2, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CDetailCategorizer* p = new CDetailCategorizer(psf2, pscid);
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
CDetailCategorizer::CDetailCategorizer(IShellFolder2* psf, const SHCOLUMNID& scid) : _cRef(1)
{
_psf = psf;
psf->AddRef();
_scid = scid;
_hash = CreateHashItemTable(10, sizeof(DWORD));
_hdpaKeys = DPA_Create(10);
}
CDetailCategorizer::~CDetailCategorizer()
{
_psf->Release();
DestroyHashItemTable(_hash);
DPA_Destroy(_hdpaKeys);
}
HRESULT CDetailCategorizer::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CDetailCategorizer, ICategorizer),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CDetailCategorizer::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CDetailCategorizer::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CDetailCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
{
return E_FAIL;
}
HRESULT CDetailCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
{
if (!_hash || !_hdpaKeys)
return E_OUTOFMEMORY;
for (UINT i = 0; i < cidl; i++)
{
VARIANT v;
rgCategoryIds[i] = GROUPID_UNSPECIFIED;
HRESULT hr = _psf->GetDetailsEx(apidl[i], &_scid, &v);
if (hr == S_OK) // GetDetails returns S_FALSE for failure.
{
WCHAR szValue[MAX_PATH];
if (SUCCEEDED(SHFormatForDisplay(_scid.fmtid, _scid.pid, (PROPVARIANT*)&v, PUIFFDF_DEFAULT, szValue, ARRAYSIZE(szValue))))
{
LPCTSTR pszKey = FindHashItem(_hash, szValue);
if (pszKey)
{
rgCategoryIds[i] = (DWORD)GetHashItemData(_hash, pszKey, 0);
}
else
{
pszKey = AddHashItem(_hash, szValue);
if (pszKey)
{
rgCategoryIds[i] = DPA_AppendPtr(_hdpaKeys, (void*)pszKey);
SetHashItemData(_hash, pszKey, 0, rgCategoryIds[i]);
}
}
}
VariantClear(&v);
}
}
return S_OK;
}
HRESULT CDetailCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
{
HRESULT hr = E_OUTOFMEMORY;
if (_hash|| _hdpaKeys)
{
if (dwCategoryId == GROUPID_UNSPECIFIED || dwCategoryId == GROUPID_FOLDER)
{
LoadString(HINST_THISDLL, STRINGID_FROM_GROUPID(dwCategoryId), pci->wszName, ARRAYSIZE(pci->wszName));
hr = S_OK;
}
else
{
LPCTSTR pszKey = (LPCTSTR)DPA_FastGetPtr(_hdpaKeys, dwCategoryId);
if (pszKey)
{
LPCTSTR psz = FindHashItem(_hash, pszKey);
if (psz)
{
StrCpyN(pci->wszName, psz, ARRAYSIZE(pci->wszName));
hr = S_OK;
}
}
else
{
hr = E_INVALIDARG;
}
}
}
return hr;
}
HRESULT CDetailCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
{
if (dwCategoryId1 == dwCategoryId2)
{
return ResultFromShort(0);
}
else if (dwCategoryId1 == GROUPID_UNSPECIFIED ||
dwCategoryId2 == GROUPID_UNSPECIFIED)
{
return ResultFromShort((dwCategoryId1 == GROUPID_UNSPECIFIED)? 1 : -1);
}
else if (dwCategoryId1 == GROUPID_FOLDER)
{
return ResultFromShort(-1);
}
else if (dwCategoryId2 == GROUPID_FOLDER)
{
return ResultFromShort(1);
}
else
{
LPCTSTR pszKey1 = (LPCTSTR)DPA_FastGetPtr(_hdpaKeys, dwCategoryId1);
LPCTSTR pszKey2 = (LPCTSTR)DPA_FastGetPtr(_hdpaKeys, dwCategoryId2);
LPCTSTR psz1 = FindHashItem(_hash, pszKey1);
LPCTSTR psz2 = FindHashItem(_hash, pszKey2);
return ResultFromShort(lstrcmpi(psz1, psz2));
}
}
/////////////////////////////////////////////////////////
// Alphanumeric Categorizer
STDAPI CAlphaCategorizer_Create(IShellFolder2* psf2, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CAlphaCategorizer* p = new CAlphaCategorizer(psf2);
if (p)
{
hr = p->QueryInterface(riid, ppv);
p->Release();
}
return hr;
}
CAlphaCategorizer::CAlphaCategorizer(IShellFolder2* psf) : _cRef(1)
{
_psf = psf;
ASSERT(psf);
psf->AddRef();
}
CAlphaCategorizer::~CAlphaCategorizer()
{
_psf->Release();
}
HRESULT CAlphaCategorizer::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CAlphaCategorizer, ICategorizer),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
ULONG CAlphaCategorizer::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CAlphaCategorizer::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CAlphaCategorizer::GetDescription(LPWSTR pszDesc, UINT cch)
{
LoadString(HINST_THISDLL, IDS_GROUPALPHABETICALLY, pszDesc, cch);
return S_OK;
}
HRESULT CAlphaCategorizer::GetCategory(UINT cidl, LPCITEMIDLIST * apidl, DWORD* rgCategoryIds)
{
if (_psf == NULL)
return E_ACCESSDENIED; // Not initialized yet.
for (UINT i = 0; i < cidl; i++)
{
TCHAR szName[MAX_PATH];
HRESULT hr = DisplayNameOf(_psf, apidl[i], SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
{
if (StrChr(TEXT("~`!@#$%^&*()_-+=1234567890<,>.;:'[]{}|"), szName[0]) != NULL)
{
rgCategoryIds[i] = GROUPID_OTHER;
}
else
{
CharUpperBuff(szName, 1);
rgCategoryIds[i] = (DWORD)szName[0];
}
}
if (FAILED(hr))
rgCategoryIds[i] = GROUPID_UNSPECIFIED;
}
return S_OK;
}
HRESULT CAlphaCategorizer::GetCategoryInfo(DWORD dwCategoryId, CATEGORY_INFO* pci)
{
if (GROUPID_UNSPECIFIED == dwCategoryId ||
GROUPID_OTHER == dwCategoryId ||
GROUPID_FOLDER == dwCategoryId)
{
LoadString(HINST_THISDLL, STRINGID_FROM_GROUPID(dwCategoryId), pci->wszName, ARRAYSIZE(pci->wszName));
return S_OK;
}
else
{
pci->wszName[0] = (WCHAR)dwCategoryId;
pci->wszName[1] = 0;
return S_OK;
}
}
HRESULT CAlphaCategorizer::CompareCategory(CATSORT_FLAGS csfFlags, DWORD dwCategoryId1, DWORD dwCategoryId2)
{
if (dwCategoryId1 == dwCategoryId2)
{
return ResultFromShort(0);
}
else if (IDS_UNSPECIFIED == dwCategoryId1 || IDS_GROUPOTHERCHAR == dwCategoryId1)
{
return ResultFromShort(1);
}
else if (IDS_UNSPECIFIED == dwCategoryId2 || IDS_GROUPOTHERCHAR == dwCategoryId2)
{
return ResultFromShort(-1);
}
else if (dwCategoryId1 == IDS_GROUPFOLDERS)
return ResultFromShort(-1);
else if (dwCategoryId2 == IDS_GROUPFOLDERS)
return ResultFromShort(1);
else
{
TCHAR szName1[2] = {(WCHAR)dwCategoryId1, 0};
TCHAR szName2[2] = {(WCHAR)dwCategoryId2, 0};
return ResultFromShort(lstrcmpi(szName1, szName2));
}
}