📄 itemidlist.h
字号:
#pragma once
// too easy implementation
// no ref count, no other goodness, forgive me.
class CItemIDList;
// for debug
#ifdef _DEBUG
const bool _Mtl_ItemIDList_traceOn = false;
#define idlTRACE if (_Mtl_ItemIDList_traceOn) ATLTRACE
#else
#define idlTRACE
#endif
class CItemIDList
{
public:
#ifdef _DEBUG
// for checking leaks
static int d_m_nCount;
#define _INCREMENT_COUNT() ++CItemIDList::d_m_nCount; if (_Mtl_ItemIDList_traceOn) ATLTRACE(_T("CItemIDList(%d)\n"), CItemIDList::d_m_nCount)
#define _DECREMENT_COUNT() --CItemIDList::d_m_nCount; if (_Mtl_ItemIDList_traceOn) ATLTRACE(_T("CItemIDList(%d)\n"), CItemIDList::d_m_nCount)
#else
#define _INCREMENT_COUNT()
#define _DECREMENT_COUNT()
#endif
// Data members
LPITEMIDLIST m_pidl;
// Constructors
CItemIDList() : m_pidl(NULL)
{
}
CItemIDList(const CItemIDList& idl)
{
m_pidl = _CopyItemIDList(idl);
}
CItemIDList(LPCITEMIDLIST pidl)
{
m_pidl = _CopyItemIDList(pidl);
}
CItemIDList(LPCTSTR lpszPath)// Note. this is late
{
m_pidl = NULL;
ULONG chEaten;
USES_CONVERSION;
CComPtr<IShellFolder> spDesktopFolder;
HRESULT hr = ::SHGetDesktopFolder(&spDesktopFolder);
if (FAILED(hr))
return;
spDesktopFolder->ParseDisplayName(NULL, NULL, T2OLE((LPTSTR)lpszPath),
&chEaten, &m_pidl, NULL);
_INCREMENT_COUNT();
}
// Destructor
~CItemIDList()
{
_Release(m_pidl);
}
void Release()
{
_Release(m_pidl);
m_pidl = NULL;
}
static void FreeIDList(LPITEMIDLIST pidl)
{
_Release(pidl);
}
// Attributes
bool IsNull()
{
return (m_pidl == NULL);
}
CString GetPath()
{
TCHAR szPath[MAX_PATH];
if (::SHGetPathFromIDList(m_pidl, szPath))
return szPath;
else
return CString();
}
void Attach(LPITEMIDLIST pidl)
{
ATLASSERT(m_pidl == NULL);
m_pidl = pidl;
}
LPITEMIDLIST Detach()
{
LPITEMIDLIST idl = m_pidl;
m_pidl = NULL;
return idl;
}
operator LPITEMIDLIST() const
{
return m_pidl;
}
// operator LPCITEMIDLIST() const
// {
// return m_pidl;
// }
LPITEMIDLIST* operator&()
{
ATLASSERT(m_pidl == NULL);
_INCREMENT_COUNT();
return &m_pidl;
}
UINT GetSize()
{
return _GetSize(m_pidl);
}
// Operations
/* bool operator==(const CItemIDList& idl) const
{
return _CmpItemID(m_pidl, idl);
}
bool operator!=(const CItemIDList& idl) const
{
return !_CmpItemID(m_pidl, idl);
}
*/
void operator+=(const CItemIDList& idl)
{
LPITEMIDLIST pidlNew = _ConcatPidls(m_pidl, idl);
Release();
m_pidl = pidlNew;
}
void operator-=(const CItemIDList& idl)
{
LPITEMIDLIST pidlNew = _RelativePidls(m_pidl, idl);
Release();
m_pidl = pidlNew;
}
bool Find(LPCTSTR lpszText)
{
int nLen = ::lstrlen(lpszText);
if (nLen == 0)
return false;
int nSrc = _GetSize(m_pidl);
if (nSrc < nLen)
return false;
const BYTE* p = (BYTE*)m_pidl;
for (int i = 0; i < nSrc - nLen; ++i) {
if(::memcmp(p + i, lpszText, nLen * sizeof(TCHAR)) == 0) {
return true;
}
}
return false;
}
// Operators
CItemIDList& operator=(const CItemIDList& idlSrc)
{
Release();
m_pidl = _CopyItemIDList(idlSrc);
return *this;
}
CItemIDList& operator=(LPCTSTR lpszPath)
{
Release();
CComPtr<IShellFolder> spDesktopFolder;
HRESULT hr = ::SHGetDesktopFolder(&spDesktopFolder);
if (FAILED(hr))
return *this;
ULONG chEaten;
USES_CONVERSION;
hr = spDesktopFolder->ParseDisplayName(NULL, NULL, T2OLE((LPTSTR)lpszPath),
&chEaten, &m_pidl, NULL);
_INCREMENT_COUNT();
return *this;
}
CItemIDList operator+(const CItemIDList& idlSrc) const
{
CItemIDList idl;
idl.m_pidl = _ConcatPidls(m_pidl, idlSrc);
return idl;
}
CItemIDList operator-(const CItemIDList& idlSrc) const
{
CItemIDList idl;
idl.m_pidl = _RelativePidls(m_pidl, idlSrc);
return idl;
}
// Helpers
static LPITEMIDLIST _Create(UINT cbSize)
{
LPITEMIDLIST pidl = (LPITEMIDLIST)::CoTaskMemAlloc(cbSize);
if (pidl == NULL)
return NULL;
_INCREMENT_COUNT();
if (pidl)
::memset(pidl, 0, cbSize); // zero-init for external task alloc
return pidl;
}
static void _Release(LPITEMIDLIST pidl)
{
#ifdef _DEBUG
if (pidl != NULL) {
_DECREMENT_COUNT();
}
#endif
::CoTaskMemFree(pidl);
}
static UINT _GetSize(LPCITEMIDLIST pidl)
{// include null terminator
UINT cbTotal = 0;
if (pidl) {
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb) {
cbTotal += pidl->mkid.cb;
pidl = _Next(pidl);
}
}
return cbTotal;
}
static LPITEMIDLIST _Next(LPCITEMIDLIST pidl)
{
ATLASSERT(pidl != NULL);
LPSTR lpMem=(LPSTR)pidl;
lpMem += pidl->mkid.cb;
return (LPITEMIDLIST)lpMem;
}
static LPITEMIDLIST _ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
UINT cb1;
if (pidl1) //May be NULL
cb1 = _GetSize(pidl1) - sizeof(pidl1->mkid.cb);
else
cb1 = 0;
UINT cb2 = _GetSize(pidl2);
LPITEMIDLIST pidlNew = _Create(cb1 + cb2);
if (pidlNew) {
if (pidl1)
::memcpy(pidlNew, pidl1, cb1);
::memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
ATLASSERT(_GetSize(pidlNew) == cb1 + cb2);
}
return pidlNew;
}
static LPITEMIDLIST _RelativePidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
ATLASSERT(pidl1 != NULL);
UINT cb1 = _GetSize(pidl1);
UINT cb2;
if (pidl2) //May be NULL
cb2 = _GetSize(pidl2) - sizeof(pidl2->mkid.cb);
else
cb2 = 0;
if (cb1 <= cb2)
return NULL;
LPITEMIDLIST pidlNew = _Create(cb1 - cb2);
if (pidlNew) {
if (pidl1)
::memcpy(pidlNew, ((LPSTR)pidl1) + cb2, cb1 - cb2);
ATLASSERT(_GetSize(pidlNew) == cb1 - cb2);
}
return pidlNew;
}
static LPITEMIDLIST _CopyItemIDList(LPCITEMIDLIST lpi)
{
if (lpi == NULL)
return NULL;
UINT cb = _GetSize(lpi);
LPITEMIDLIST lpiTemp = (LPITEMIDLIST)::CoTaskMemAlloc(cb);
if (lpiTemp == NULL)
return NULL;
_INCREMENT_COUNT();
::memcpy(lpiTemp, lpi, cb);
return lpiTemp;
}
/* static LPITEMIDLIST _CopyItemID(LPCITEMIDLIST lpi)
{
if (lpi == NULL)
return NULL;
LPITEMIDLIST lpiTemp = (LPITEMIDLIST)::CoTaskMemAlloc( lpi->mkid.cb + sizeof(lpi->mkid.cb) );
if (lpiTemp == NULL)
return NULL;
_INCREMENT_COUNT();
::memcpy(lpiTemp, lpi, lpi->mkid.cb + sizeof(lpi->mkid.cb));
return lpiTemp;
}
*/
static bool _CmpItemID(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
if (pidl1 == NULL && pidl2 != NULL)
return false;
if (pidl1 != NULL && pidl2 == NULL)
return false;
UINT cb1 = _GetSize(pidl2);
UINT cb2 = _GetSize(pidl1);
if (cb1 != cb2)
return false;
return ::memcmp(pidl1, pidl2, cb1) == 0;
}
static void _Dump(LPCITEMIDLIST pidlSrc)
{
if (pidlSrc == NULL)
return;
LPITEMIDLIST pidl = (LPITEMIDLIST)pidlSrc;
while (pidl->mkid.cb) {
idlTRACE(_T(" "));
for (int i = sizeof(pidl->mkid.cb); i < pidl->mkid.cb; ++i)
idlTRACE(_T("%c"), *((LPBYTE)pidl + i));
pidl = _Next(pidl);
}
idlTRACE(_T("\n"));
}
};
#ifdef _DEBUG
__declspec(selectany) int CItemIDList::d_m_nCount = 0;
#endif
// Compare helpers
inline bool operator==(const CItemIDList& s1, const CItemIDList& s2)
{
return CItemIDList::_CmpItemID(s1, s2);
}
inline bool operator==(const CItemIDList& s1, LPCITEMIDLIST s2)
{
return CItemIDList::_CmpItemID(s1, s2);
}
inline bool operator==(LPCITEMIDLIST s1, const CItemIDList& s2)
{
return CItemIDList::_CmpItemID(s1, s2);
}
inline bool operator!=(const CItemIDList& s1, const CItemIDList& s2)
{
return !CItemIDList::_CmpItemID(s1, s2);
}
inline bool operator!=(const CItemIDList& s1, LPCITEMIDLIST s2)
{
return !CItemIDList::_CmpItemID(s1, s2);
}
inline bool operator!=(LPCITEMIDLIST s1, const CItemIDList& s2)
{
return !CItemIDList::_CmpItemID(s1, s2);
}
/*
template <class _Function>
_Function MtlForEachFile(IShellFolder* pFolder, _Function __f, bool bIncludeHidden = false)
{
DWORD grfFlags = bIncludeHidden ? SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN : SHCONTF_NONFOLDERS;
CComPtr<IEnumIDList> spEnum;
HRESULT hr = pFolder->EnumObjects(NULL, grfFlags, &spEnum);
if (FAILED(hr))
return __f;
LPITEMIDLIST pidl;
ULONG celtFetched;
while (spEnum->Next(1, &pidl, &celtFetched) == S_OK) {
ATLASSERT(pidl != NULL);
CItemIDList idl; idl.Attach(pidl);
__f(pFolder, idl);
}
return __f;
}
template <typename _Function>
_Function MtlForEachFolder(IShellFolder* pFolder, _Function __f, bool bIncludeHidden = false)
{
DWORD grfFlags = bIncludeHidden ? SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN : SHCONTF_FOLDERS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -