📄 pidl.cpp
字号:
////////////////////////////////////////////////////////////////////
// PIDL.cpp: implementation of the CPIDL class.
//
// By Oz Solomonovich (osolo@bigfoot.com)
#include "stdafx.h"
#include "PIDL.h"
LPSHELLFOLDER CPIDL::m_sfDesktop = NULL; // cached destkop folder
LPMALLOC CPIDL::m_pAllocator = NULL; // cahced system allocator
CPIDL::pidl_initializer CPIDL::m_initializer; // automatic init. obj
////////////////////////////////////////////////////////////////////
// Initialization object
////////////////////////////////////////////////////////////////////
// pidl_initializer is used to initialized our static data. The
// constructor and destructor are automatically called for us when
// the program starts/ends.
CPIDL::pidl_initializer::pidl_initializer()
{
SHGetDesktopFolder(&m_sfDesktop); // cache d'top folder obj ptr
SHGetMalloc(&m_pAllocator); // cache sys allocator obj ptr
}
CPIDL::pidl_initializer::~pidl_initializer()
{
// decrement COM reference counters:
m_sfDesktop->Release();
m_pAllocator->Release();
}
////////////////////////////////////////////////////////////////////
// CPIDL Implementation
////////////////////////////////////////////////////////////////////
CPIDL::~CPIDL()
{
Free(); // just free used memory
}
////////////////////////////////////////////////////////////////////
// Assignment Functions
HRESULT CPIDL::Set(const CPIDL& cpidl)
{
return MakeCopyOf(cpidl.m_pidl);
}
HRESULT CPIDL::Set(LPITEMIDLIST pidl)
{
Free();
m_pidl = pidl;
return ERROR_SUCCESS;
}
HRESULT CPIDL::Set(LPCSTR szPath, LPSHELLFOLDER psf)
{
OLECHAR olePath[MAX_PATH];
ULONG chEaten;
ULONG dwAttributes;
Free();
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1,
olePath, MAX_PATH);
return psf->ParseDisplayName(NULL, NULL, olePath, &chEaten,
&m_pidl, &dwAttributes);
}
HRESULT CPIDL::MakeCopyOf(LPITEMIDLIST pidl)
{
Free();
if (pidl) {
UINT sz = m_pAllocator->GetSize((LPVOID)pidl);
AllocMem(sz);
CopyMemory((LPVOID)m_pidl, (LPVOID)pidl, sz);
}
return ERROR_SUCCESS;
}
HRESULT CPIDL::MakeAbsPIDLOf(LPSHELLFOLDER psf, LPITEMIDLIST pidl)
{
OLECHAR szOleChar[MAX_PATH];
ULONG ulEaten, ulAttribs;
HRESULT hr;
STRRET str;
Free();
hr = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
if (SUCCEEDED(hr)) {
ExtractCStr(str);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.cStr, -1,
(USHORT *)szOleChar, sizeof(szOleChar));
hr = m_sfDesktop->ParseDisplayName(NULL,
NULL, szOleChar, &ulEaten, &m_pidl, &ulAttribs);
}
return hr;
}
////////////////////////////////////////////////////////////////////
// CPIDL Operations
// Frees memory used by the PIDL.
void CPIDL::Free()
{
if (m_pidl) {
m_pAllocator->Free(m_pidl);
m_pidl = NULL;
}
}
UINT CPIDL::GetSize() const
{
UINT cbTotal = 0;
LPSHITEMID pid = GetFirstItemID();
if (pid) {
do {
cbTotal += pid->cb;
GetNextItemID(pid);
} while (pid->cb);
cbTotal += sizeof(pid->cb); // count the terminator
}
return cbTotal;
}
#define CB_SIZE (sizeof(piid->cb)) // size of terminator
void CPIDL::Split(CPIDL& root, CPIDL& obj) const
{
int size;
SHITEMID *piid, *piidLast;
// find last item-id and calculate total size of pidl
size = 0;
piid = piidLast = &m_pidl->mkid;
while (piid->cb)
{
piidLast = piid;
size += (piid->cb);
piid = (SHITEMID *)((LPBYTE)piid + (piid->cb));
}
// copy "root" portion
size -= piidLast->cb; // don't count "object" item-id
root.AllocMem(size + CB_SIZE);
CopyMemory(root.m_pidl, m_pidl, size);
ZeroMemory((LPBYTE)root.m_pidl + size, CB_SIZE); // terminator
// copy "object" portion
size = piidLast->cb + CB_SIZE;
obj.AllocMem(size);
CopyMemory(obj.m_pidl, piidLast, size);
}
CPIDL CPIDL::operator + (CPIDL& pidl) const
{
CPIDL ret;
Concat(*this, pidl, ret);
return ret;
}
void CPIDL::Concat(const CPIDL &a, const CPIDL& b, CPIDL& result)
{
result.Free();
// both empty?
if (a.m_pidl == NULL && b.m_pidl == NULL) return;
// a empty? return b
if (a.m_pidl == NULL) { result.Set(b); return; }
// b empty? return a
if (a.m_pidl == NULL) { result.Set(a); return; }
UINT cb1, cb2;
cb1 = a.GetSize() - sizeof(a.m_pidl->mkid.cb);
cb2 = b.GetSize();
result.AllocMem(cb1 + cb2); // allocate enough memory
CopyMemory(result.m_pidl, a.m_pidl, cb1); // 1st
CopyMemory(((LPBYTE)result.m_pidl) + cb1, b.m_pidl, cb2); // 2nd
}
HRESULT CPIDL::GetUIObjectOf(REFIID riid, LPVOID *ppvOut,
HWND hWnd /*= NULL*/, LPSHELLFOLDER psf /*= m_sfDesktop*/)
{
CPIDL root, obj;
LPSHELLFOLDER psfRoot;
HRESULT hr;
Split(root, obj);
// get the IShellFolder of the root
hr = psf->BindToObject(root, NULL, IID_IShellFolder,
(LPVOID *)&psfRoot);
if (SUCCEEDED(hr)) {
hr = psfRoot->GetUIObjectOf(hWnd, 1, obj, riid, 0, ppvOut);
psfRoot->Release();
}
return hr;
}
void CPIDL::ExtractCStr(STRRET& strRet) const
{
switch (strRet.uType)
{
case STRRET_WSTR:
{
// pOleStr points to a WCHAR string - convert it to ANSI
LPWSTR pOleStr = strRet.pOleStr;
WideCharToMultiByte(CP_ACP, 0, pOleStr, -1,
strRet.cStr, MAX_PATH, NULL, NULL);
m_pAllocator->Free(pOleStr);
break;
}
case STRRET_OFFSET:
// The string lives inside the pidl, so copy it out.
lstrcpyn(strRet.cStr, (LPSTR)
((LPBYTE)m_pidl + strRet.uOffset), MAX_PATH);
break;
case STRRET_CSTR:
// The string already is in the right place.
break;
}
}
////////////////////////////////////////////////////////////////////
// CPIDL Private Operations
void CPIDL::AllocMem(int iAllocSize)
{
Free();
m_pidl = (LPITEMIDLIST)m_pAllocator->Alloc(iAllocSize);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -