PIDL.cpp
上传用户:yatsl7111
上传日期:2007-01-08
资源大小:1433k
文件大小:6k
源码类别:

图形图象

开发平台:

Visual C++

  1. ////////////////////////////////////////////////////////////////////
  2. // PIDL.cpp: implementation of the CPIDL class.
  3. //
  4. // By Oz Solomonovich (osolo@bigfoot.com)
  5. #include "stdafx.h"
  6. #include <atlbase.h>
  7. #include "PIDL.h"
  8. LPSHELLFOLDER CPIDL::m_sfDesktop  = NULL; // cached destkop folder
  9. LPMALLOC      CPIDL::m_pAllocator = NULL; // cached system allocator
  10. CPIDL::pidl_initializer CPIDL::m_initializer; // automatic init. obj
  11. ////////////////////////////////////////////////////////////////////
  12. // Initialization object
  13. ////////////////////////////////////////////////////////////////////
  14. // pidl_initializer is used to initialize the static data.  The 
  15. // constructor and destructor are automatically called for us when
  16. // the program starts/ends.
  17. CPIDL::pidl_initializer::pidl_initializer()
  18. {
  19.     SHGetDesktopFolder(&m_sfDesktop); // cache d'top folder obj ptr 
  20.     SHGetMalloc(&m_pAllocator);       // cache sys allocator obj ptr
  21. }
  22. CPIDL::pidl_initializer::~pidl_initializer()
  23. {
  24.     m_sfDesktop->Release();
  25.     m_pAllocator->Release();
  26. }
  27. ////////////////////////////////////////////////////////////////////
  28. // CPIDL Implementation
  29. ////////////////////////////////////////////////////////////////////
  30. CPIDL::CPIDL(LPCTSTR szPath, LPSHELLFOLDER psf) : 
  31.      m_pidl(NULL) 
  32. Set(szPath, psf); 
  33. }
  34. CPIDL::~CPIDL()
  35. {
  36.     Free();  // just free used memory
  37. }
  38. ////////////////////////////////////////////////////////////////////
  39. // Assignment Functions
  40. HRESULT CPIDL::Set(const CPIDL& cpidl)
  41. {
  42.     return MakeCopyOf(cpidl.m_pidl);
  43. }
  44. HRESULT CPIDL::Set(LPITEMIDLIST pidl)
  45. {
  46.     Free();
  47.     m_pidl = pidl;
  48.     return ERROR_SUCCESS;
  49. }
  50. HRESULT CPIDL::Set(LPCTSTR szPath, LPSHELLFOLDER psf)
  51. {
  52.     OLECHAR olePath[MAX_PATH];
  53.     ULONG   chEaten;
  54.     ULONG   dwAttributes;
  55.     
  56.     Free();
  57. #ifndef _UNICODE
  58.     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, 
  59.         olePath, MAX_PATH);
  60. #else
  61. lstrcpy(olePath,szPath);
  62. #endif
  63.     return psf->ParseDisplayName(NULL, NULL, olePath, &chEaten, 
  64.         &m_pidl, &dwAttributes);
  65. }
  66. HRESULT CPIDL::MakeCopyOf(LPITEMIDLIST pidl)
  67. {
  68.     Free();
  69.     if (pidl) {
  70.         UINT sz = m_pAllocator->GetSize((LPVOID)pidl);
  71.         AllocMem(sz);
  72.         CopyMemory((LPVOID)m_pidl, (LPVOID)pidl, sz);
  73.     }
  74.     return ERROR_SUCCESS;
  75. }
  76. HRESULT CPIDL::MakeAbsPIDLOf(LPSHELLFOLDER psf, LPITEMIDLIST pidl)
  77. {
  78. USES_CONVERSION;
  79.     STRRET  str;
  80.     HRESULT hr = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
  81.     if (SUCCEEDED(hr)) {
  82.         ExtractCStr(str);
  83.         hr = Set(A2T(str.cStr));
  84.     }
  85.     return hr;
  86. }
  87. ////////////////////////////////////////////////////////////////////
  88. // CPIDL Operations
  89. void CPIDL::Free()
  90. {
  91.     if (m_pidl) {
  92.         m_pAllocator->Free(m_pidl);
  93.         m_pidl = NULL;
  94.     }
  95. }
  96. #define CB_SIZE  (sizeof(piid->cb))  // size of termination item
  97. UINT CPIDL::GetSize() const
  98. {
  99.     UINT        cbTotal = 0;
  100.     LPSHITEMID  piid    = GetFirstItemID();
  101.     
  102.     if (piid) {
  103.         do {
  104.             cbTotal += piid->cb;
  105.             GetNextItemID(piid);
  106.         } while (piid->cb);
  107.         cbTotal += CB_SIZE; // count the terminator
  108.     }
  109.     
  110.     return cbTotal;
  111. }
  112. void CPIDL::Split(CPIDL& parent, CPIDL& obj) const
  113. {
  114.     int         size = 0;
  115.     SHITEMID    *piid, *piidLast;
  116.     
  117.     // find last item-id and calculate total size of pidl
  118.     piid = piidLast = &m_pidl->mkid;
  119.     while (piid->cb)
  120.     {
  121.         piidLast = piid;
  122.         size += (piid->cb);
  123.         piid =  (SHITEMID *)((LPBYTE)piid + (piid->cb));
  124.     }
  125.     
  126.     // copy parent folder portion
  127.     size -= piidLast->cb;  // don't count "object" item-id
  128. if (size > 0)
  129. {
  130.     parent.AllocMem(size + CB_SIZE);
  131. CopyMemory(parent.m_pidl, m_pidl, size);
  132. ZeroMemory((LPBYTE)parent.m_pidl + size, CB_SIZE); // terminator
  133.     }
  134.     // copy "object" portion
  135.     size = piidLast->cb + CB_SIZE;
  136. if (size > 0)
  137. {
  138.     obj.AllocMem(size);
  139. CopyMemory(obj.m_pidl, piidLast, size);
  140. }
  141. }
  142. CPIDL CPIDL::operator + (CPIDL& pidl) const
  143. {
  144.     CPIDL ret;
  145.     Concat(*this, pidl, ret);
  146.     return ret;
  147. }
  148. void CPIDL::Concat(const CPIDL &a, const CPIDL& b, CPIDL& result)
  149. {
  150.     result.Free();
  151.     
  152.     // both empty->empty | a empty->return b | b empty->return a
  153.     if (a.m_pidl == NULL  &&  b.m_pidl == NULL) return;
  154.     if (a.m_pidl == NULL) { result.Set(b); return; }
  155.     if (a.m_pidl == NULL) { result.Set(a); return; }
  156.     
  157.     UINT cb1 = a.GetSize() - sizeof(a.m_pidl->mkid.cb);
  158.     UINT cb2 = b.GetSize(); 
  159.     result.AllocMem(cb1 + cb2); // allocate enough memory 
  160.     CopyMemory(result.m_pidl, a.m_pidl, cb1);                 // 1st
  161.     CopyMemory(((LPBYTE)result.m_pidl) + cb1, b.m_pidl, cb2); // 2nd
  162. }
  163. HRESULT CPIDL::GetUIObjectOf(REFIID riid, LPVOID *ppvOut, 
  164.     HWND hWnd /*= NULL*/, LPSHELLFOLDER psf /*= m_sfDesktop*/)
  165. {
  166.     CPIDL           parent, obj;
  167.     LPSHELLFOLDER   psfParent;
  168. HRESULT hr=S_OK;
  169.     
  170.     Split(parent, obj);
  171. // if no idl the use desktop folder
  172. if (parent.m_pidl == NULL || parent.m_pidl->mkid.cb == 0)
  173. {
  174. psfParent = psf;
  175. psfParent->AddRef();
  176. }
  177. else
  178. {
  179. // otherwise get the parent
  180.      hr = psf->BindToObject(parent, NULL, IID_IShellFolder, 
  181.     (LPVOID *)&psfParent); // get the IShellFolder of the parent
  182. }
  183.     if (SUCCEEDED(hr)) 
  184. {
  185.         hr = psfParent->GetUIObjectOf(hWnd, 1, obj, riid, 0, ppvOut);
  186. psfParent->Release();
  187.     }
  188.     return hr;
  189. }
  190. void CPIDL::ExtractCStr(STRRET& strRet) const
  191. {
  192.     switch (strRet.uType) 
  193.     {
  194.         case STRRET_WSTR:
  195.         {
  196.             // pOleStr points to a WCHAR string - convert it to ANSI
  197.             LPWSTR pOleStr = strRet.pOleStr;
  198.             WideCharToMultiByte(CP_ACP, 0, pOleStr, -1,
  199.                 strRet.cStr, MAX_PATH, NULL, NULL);
  200.             m_pAllocator->Free(pOleStr);
  201.             break;
  202.         }
  203.         
  204.         case STRRET_OFFSET:
  205.             // The string lives inside the pidl, so copy it out.
  206.             strncpy(strRet.cStr, (LPSTR)
  207.                 ((LPBYTE)m_pidl + strRet.uOffset), MAX_PATH);
  208.             break;
  209.     }
  210. }
  211. ////////////////////////////////////////////////////////////////////
  212. // CPIDL Private Operations
  213. void CPIDL::AllocMem(int iAllocSize)
  214. {
  215.     Free();
  216.     m_pidl = (LPITEMIDLIST)m_pAllocator->Alloc(iAllocSize);
  217. }