idlist.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 21k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*----------------------------------------------------------------------------
  2. / Title;
  3. /   idlist.cpp
  4. /
  5. / Authors;
  6. /   David De Vorchik (daviddv)
  7. /
  8. / Notes;
  9. /   - All the smarts to handle IDLISTs for the DS.
  10. /   - DS IDLISTs contain UNICODE only strings
  11. /----------------------------------------------------------------------------*/
  12. #include "pch.h"
  13. #include "stddef.h"
  14. #pragma hdrstop
  15. /*-----------------------------------------------------------------------------
  16. / IDLISTs are opaque structures, they can be stored at any aligment, ours
  17. / contain the following data.  However this should not be treated as the
  18. / public version.  The pack and unpack functions below are responsible for
  19. / generating this structure, use those.
  20. /----------------------------------------------------------------------------*/
  21. #pragma pack(1)
  22. typedef struct
  23. {
  24. #if DELEGATE
  25.     WORD    cbSize;                     // size of entire item ID
  26.     WORD    wOuter;                     // private data owned by the outer folder
  27.     WORD    cbInner;                    // size of delegate's data
  28. #else
  29.     WORD    cbSize;                     // size of the IDLIST
  30. #endif
  31.     WORD    cbToStrings;                // offset to start of string data
  32.     DWORD   dwMagic;                    // magic guard word
  33.     DWORD   dwFlags;                    // flags word (defines what is present)
  34.     DWORD   dwProviderFlags;            // provider flags (sucked from the registry)
  35.     DWORD   dwReserved;        
  36.     WCHAR   szStringData[1];            // all strings stored UNICODE
  37. } OURIDLIST;
  38. typedef UNALIGNED OURIDLIST*  LPOURIDLIST;
  39. #pragma pack()
  40. // 
  41. // A class which implements a linear probing hash, this is used specificly
  42. // to cache ADSI paths and Object Class pairs for simple IDLISTs to avoid
  43. // us having to bind into the DS to obtain that information.
  44. //
  45. // The code is based on an algorithm in "Algorithms in C/Sedgewick pp 237".
  46. //
  47. // Basiclly compute the hash, check the index, if we don't have a match
  48. // then advance until we do or we hit an empty slot.  Then write the data
  49. // there.
  50. //
  51. #define CACHE_SIZE 101                  // nb: 101 is a prime 
  52. typedef struct
  53. {
  54.     LPWSTR pPath;                       // real key we are using
  55.     LPWSTR pObjectClass;                // value we are assocating.
  56. } CACHEENTRY, * LPCACHEENTRY;
  57. class CObjectCache
  58. {
  59.     private:
  60.         CACHEENTRY m_cache[CACHE_SIZE];
  61.         INT _ComputeKey(LPCWSTR pPath);
  62.    
  63.     public:
  64.         CObjectCache();
  65.         ~CObjectCache();
  66.         LPCWSTR GetObjectClass(LPCWSTR pPath);
  67. };
  68. CObjectCache g_ObjectCache;
  69. /*-----------------------------------------------------------------------------
  70. / CObjectCache implementation
  71. /----------------------------------------------------------------------------*/
  72. CObjectCache::CObjectCache()
  73. {
  74.     TraceEnter(TRACE_IDLIST, "CObjectCache::CObjectCache");
  75.     
  76.     ZeroMemory(m_cache, SIZEOF(m_cache));         // nuke out the cache
  77.     TraceLeave();
  78. }
  79. CObjectCache::~CObjectCache()
  80. {
  81.     INT i;
  82.     TraceEnter(TRACE_IDLIST, "CObjectCache::~CObjectCache");
  83.     for ( i = 0 ; i < CACHE_SIZE ; i++ )
  84.     {
  85.         LocalFreeStringW(&m_cache[i].pPath);
  86.         LocalFreeStringW(&m_cache[i].pObjectClass);
  87.     }
  88.     TraceLeave();
  89. }
  90. /*-----------------------------------------------------------------------------
  91. / CObjectCache::_ComputeKey
  92. / -------------------------
  93. /   Compute the key for a given ADSI path.
  94. /
  95. / In:
  96. /   pPath -> ADsPath for the object
  97. /
  98. / Out:
  99. /   INT - index into the cache
  100. /----------------------------------------------------------------------------*/
  101. INT CObjectCache::_ComputeKey(LPCWSTR pPath)
  102. {
  103.     INT result, i;
  104.     USES_CONVERSION;
  105.     TraceEnter(TRACE_IDLIST, "CObjectCache::_ComputeKey");
  106.     Trace(TEXT("pPath %s"), W2CT(pPath));
  107.     for ( result = 0, i = 0 ; i < lstrlenW(pPath) ; i++ )
  108.         result = (64 * result + pPath[i]) % CACHE_SIZE;
  109.     
  110.     Trace(TEXT("result %d"), result);
  111.     TraceLeaveValue(result);
  112. }
  113. /*-----------------------------------------------------------------------------
  114. / CObjectCache::GetObjectClass
  115. / ----------------------------
  116. /   Given the path of an object then lets get the ObjectClass for it,
  117. /   this involves searching the cache for an entry and then
  118. /   binding if we don't find one.  
  119. /
  120. / In:
  121. /   pPath -> ADsPath for the object
  122. /
  123. / Out:
  124. /   pObjectClass -> object class record in the cache
  125. /----------------------------------------------------------------------------*/
  126. LPCWSTR CObjectCache::GetObjectClass(LPCWSTR pPath)
  127. {
  128.     HRESULT hr;
  129.     LPCWSTR pObjectClass = NULL;
  130.     IADs* pDsObject = NULL;
  131.     BSTR bstrObjectClass = NULL;
  132.     INT i;
  133.     USES_CONVERSION;
  134.     TraceEnter(TRACE_IDLIST, "CObjectCache::GetObjectClass");
  135.     Trace(TEXT("pPath %s"), W2CT(pPath));
  136.     // compute the key and lets look into the cache and see if we
  137.     // can find a match.  
  138.     for ( i = _ComputeKey(pPath) ; (i < CACHE_SIZE) && m_cache[i].pPath ; i++ )
  139.     {
  140.         if ( !StrCmpW(pPath, m_cache[i].pPath) )
  141.         {
  142.             Trace(TEXT("Found entry at index %d"), i);
  143.             pObjectClass = m_cache[i].pObjectClass;
  144.             goto exit_gracefully;
  145.         }
  146.     }
  147.     // we didn't find an entry in the cache (and either hit an emty slot,
  148.     // or hit the end of the table).  So now we must bind to the object
  149.     // and get the information, before filling the record.
  150. // BUGBUG: this we must revisit
  151.     hr = ADsOpenObject((LPWSTR)pPath, NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IADs, (LPVOID*)&pDsObject);
  152.     FailGracefully(hr, "Failed to bind to the object");
  153.     hr = pDsObject->get_Class(&bstrObjectClass);
  154.     FailGracefully(hr, "Failed to get the ObjectClass");
  155.     // discard the previous entry (if it was filled), and now lets write new information into it.
  156.     
  157.     if ( i >= CACHE_SIZE )
  158.     {
  159.         TraceMsg("Table is already filled, so lets recompute the index");
  160.         i = _ComputeKey(pPath);
  161.     }
  162.     LocalFreeStringW(&m_cache[i].pPath);
  163.     LocalFreeStringW(&m_cache[i].pObjectClass);
  164.     if ( FAILED(LocalAllocStringW(&m_cache[i].pPath, pPath)) ||
  165.             FAILED(LocalAllocStringW(&m_cache[i].pObjectClass, bstrObjectClass)) )
  166.     {
  167.         LocalFreeStringW(&m_cache[i].pPath);
  168.         LocalFreeStringW(&m_cache[i].pObjectClass);
  169.         ExitGracefully(hr, E_OUTOFMEMORY, "Failed to fill the record");
  170.     }
  171.     pObjectClass = m_cache[i].pObjectClass;
  172.     TraceAssert(pObjectClass);
  173. exit_gracefully:
  174.     Trace(TEXT("pObjectClass: %s"), pObjectClass ? W2CT(pObjectClass):TEXT("<not found>"));
  175.     DoRelease(pDsObject);
  176.     SysFreeString(bstrObjectClass);
  177.     TraceLeaveValue(pObjectClass);
  178. }
  179. /*-----------------------------------------------------------------------------
  180. / Helper functions
  181. /----------------------------------------------------------------------------*/
  182. /*-----------------------------------------------------------------------------
  183. / _GetString
  184. / -----------
  185. /   Helper function to extract a string and increase the pointers
  186. /   as required.
  187. /
  188. / In:
  189. /   ppString -> string data we are walking
  190. /   ppResult -> receives either the pointer or NULL
  191. /   fExtract = if the string should be read
  192. /
  193. / Out:
  194. /   ppString -> updated to point past string extracted
  195. /   ppResult -> receives either the string pointer or NULL
  196. /----------------------------------------------------------------------------*/
  197. void _GetString(LPWSTR* ppString, LPWSTR* ppResult, BOOL fExtract)
  198. {
  199.     TraceEnter(TRACE_IDLIST, "_GetString");
  200.     *ppResult = NULL;
  201.     if ( fExtract )
  202.     {
  203.         *ppResult  = *ppString;
  204.         *ppString += lstrlenW(*ppString)+1;
  205.     }
  206.     TraceLeave();
  207. }
  208. /*-----------------------------------------------------------------------------
  209. / _PutString
  210. / ----------
  211. /   Write a string at the given pointer, updating to reflect the change
  212. /   perform.
  213. /
  214. / In:
  215. /   ppBuffer -> buffer to write the string to
  216. /   pString -> string to be written
  217. /   fAppend = if the string should be appended
  218. /
  219. / Out:
  220. /   ppBuffer updated to reflect new string added
  221. /----------------------------------------------------------------------------*/
  222. void _PutString(LPWSTR* ppBuffer, LPWSTR pString, BOOL fAppend)
  223. {
  224.     TraceEnter(TRACE_IDLIST, "_PutString");
  225.     if ( fAppend )
  226.     {
  227.         StrCpyW(*ppBuffer, pString);
  228.         *ppBuffer += lstrlenW(pString)+1;
  229.     }
  230.     TraceLeave();
  231. }
  232. /*-----------------------------------------------------------------------------
  233. / IDLIST pack/unpack functions
  234. /----------------------------------------------------------------------------*/
  235. /*-----------------------------------------------------------------------------
  236. / CreateIdList
  237. / ------------
  238. /   Convert a IDLISTDATA into a ITEMIDLIST that the shell can cope with,
  239. /   including packing all the data and hiding any Unicode / ANSI nastyness.
  240. /
  241. / In:
  242. /   ppidl -> receives the newly allocated IDLIST.
  243. /   pData -> IDLISTDATA structure to create the IDL from.
  244. /
  245. / Out:
  246. /   hresult.
  247. /----------------------------------------------------------------------------*/
  248. HRESULT CreateIdList(LPITEMIDLIST* ppidl, LPIDLISTDATA pData, IMalloc* pm)
  249. {
  250.     HRESULT hr = E_INVALIDARG;
  251.     LPOURIDLIST pOurIdList = NULL;
  252.     LPWSTR pStringData;
  253.     int cbSize = SIZEOF(OURIDLIST);
  254.     USES_CONVERSION;
  255.     TraceEnter(TRACE_IDLIST, "CreateIdList");
  256.     TraceAssert(ppidl);
  257.     TraceAssert(pData);
  258.     // Compute the size of the string using the elements we have
  259.     cbSize += StringByteSizeW(pData->pName);
  260.     cbSize += StringByteSizeW(pData->pObjectClass);
  261.     cbSize += StringByteSizeW(pData->pPathElement);
  262.     cbSize += StringByteSizeW(pData->pUNC);
  263.     Trace(TEXT("cbSize %d (%04x)"), cbSize, cbSize);
  264.     // if we have a IMalloc then we are a delegate object, so we must call the malloc
  265.     // implementation and then we can indirect into the structure we get allocated.  Otherwise
  266.     // we use the old implementation which does a SHAlloc.
  267. #if DELEGATE
  268.     if ( !pm )
  269.         ExitGracefully(hr, E_INVALIDARG, "No IMalloc interface to alloc IDLIST with");
  270.     pOurIdList = (LPOURIDLIST)pm->Alloc(cbSize+SIZEOF(WORD));
  271.     TraceAssert(pOurIdList);
  272. #else
  273.     pOurIdList = (LPOURIDLIST)SHAlloc(cbSize+SIZEOF(WORD));
  274.     TraceAssert(pOurIdList);
  275. #endif
  276.     // - zero the structure and then fill the fields
  277.     // - write the pointer to the structure if it succeeded
  278.     if ( !pOurIdList )
  279.         ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate IDLIST");
  280. #if !DELEGATE
  281.     pOurIdList->cbSize = (WORD)cbSize;
  282. #endif
  283.     *(LPWORD)ByteOffset(pOurIdList, pOurIdList->cbSize) = 0;       // terminate
  284.     pOurIdList->cbToStrings = offsetof(OURIDLIST, szStringData);
  285.     pOurIdList->dwMagic = DSIDL_MAGIC;
  286.     pOurIdList->dwFlags = pData->dwFlags;
  287.     pOurIdList->dwProviderFlags = pData->dwProviderFlags;
  288.     // write the string data...
  289.     pStringData = pOurIdList->szStringData;
  290.     if ( pData->pName )
  291.     {
  292.         pOurIdList->dwFlags |= DSIDL_HASNAME;
  293.         _PutString(&pStringData, pData->pName, TRUE);
  294.     }
  295.     if ( pData->pObjectClass )
  296.     {
  297.         pOurIdList->dwFlags |= DSIDL_HASCLASS;
  298.         _PutString(&pStringData, pData->pObjectClass, TRUE);
  299.     }
  300.     _PutString(&pStringData, pData->pPathElement, TRUE);
  301.     if ( pData->pUNC )
  302.     {
  303.         pOurIdList->dwFlags |= DSIDL_HASUNC;
  304.         _PutString(&pStringData, pData->pUNC, TRUE);
  305.     }
  306.     *ppidl = (LPITEMIDLIST)pOurIdList;
  307.     TraceAssert(*ppidl);
  308.     hr = S_OK;                              // success
  309. exit_gracefully:
  310.     TraceLeaveResult(hr);
  311. }
  312. /*-----------------------------------------------------------------------------
  313. / CreateIdListFromPath
  314. / --------------------
  315. /   Given a ADsPath and its ObjectClass convert this to a IDLIST.
  316. /
  317. / In:
  318. /   ppidl = receives a pointer to new IDLIST
  319. /   pName, pPath, pObjectClass => string information about object
  320. /   pm -> IMalloc to allocate the IDLIST using
  321. /   pdds -> IDsDisplaySpecifier object
  322. /
  323. / Out:
  324. /   HRESULT
  325. /----------------------------------------------------------------------------*/
  326. HRESULT CreateIdListFromPath(LPITEMIDLIST* ppidl, 
  327.                              LPWSTR pName, LPWSTR pPath, LPWSTR pObjectClass, LPWSTR pUNC, 
  328.                              IMalloc* pm, IDsDisplaySpecifier *pdds)
  329. {
  330.     HRESULT hr;
  331.     IDLISTDATA data = { 0 };
  332.     INT i;
  333.     USES_CONVERSION;
  334.     TraceEnter(TRACE_IDLIST, "CreateIdListFromPath");
  335.     Trace(TEXT("pName %s"), pName ? W2CT(pName):TEXT("<none specified>"));
  336.     Trace(TEXT("pPath %s"), W2CT(pPath));
  337.     Trace(TEXT("pObjectClass %s"), pObjectClass ? W2CT(pObjectClass):TEXT("<none specified>"));
  338.     // Having plucked the useful information from the objects descriptor
  339.     // now attempt to build an IDLIST structure that represents it,
  340.     // to do this we build an IDLISTDATA structure and get it packed.
  341.     if ( pObjectClass && !pUNC )
  342.     {
  343.         if ( pdds->IsClassContainer(pObjectClass, pPath, 0x0) )
  344.             data.dwFlags |= DSIDL_ISCONTAINER;
  345.     }
  346.     else
  347.     {
  348.         data.dwFlags |= DSIDL_ISCONTAINER;
  349.     }
  350.     // if we have a parent path then lets ensure that we strim it from the path we are going
  351.     // to put into the IDLIST.  
  352.  
  353.     data.dwProviderFlags = 0;
  354.     data.pName = pName;
  355.     data.pObjectClass = pObjectClass;
  356.     data.pPathElement = pPath;
  357.     data.pUNC = pUNC;
  358.     // construct the IDLIST
  359.     hr = CreateIdList(ppidl, &data, pm);
  360.     FailGracefully(hr, "Failed to create IDLIST from data structure");
  361.     hr = S_OK;              // success
  362. exit_gracefully:
  363.     TraceLeaveResult(hr);
  364. }
  365. /*-----------------------------------------------------------------------------
  366. / UnpackIdList
  367. / ------------
  368. /   Extract all the interesting information from the ITEMIDLIST into an
  369. /   one of our descriptive structures.
  370. /
  371. / In:
  372. /   pidl -> ITEMIDLIST to expand.
  373. /   dwFlags = flags indicating important fields
  374. /   pData -> where to expand it into.
  375. /
  376. / Out:
  377. /   hresult.
  378. /----------------------------------------------------------------------------*/
  379. HRESULT UnpackIdList(LPCITEMIDLIST pidl, DWORD dwFlags, LPIDLISTDATA pData)
  380. {
  381.     LPOURIDLIST pOurIdList = (LPOURIDLIST)pidl;
  382.     LPWSTR pStringData;
  383.     IADs* pDsObject = NULL;
  384.     BSTR bstrObjectClass = NULL;
  385.     HRESULT hr;
  386.     TraceEnter(TRACE_IDLIST, "UnpackIdList");
  387.     TraceAssert(pOurIdList);
  388.     TraceAssert(pData);
  389.     // is the IDLIST valid?  If so unpack it, otherwise bail 
  390.     if ( !pOurIdList || ILIsEmpty(pidl) )
  391.         ExitGracefully(hr, E_INVALIDARG, "No IDLIST given");
  392.     if ( pOurIdList->dwMagic != DSIDL_MAGIC )
  393.     {
  394.         Trace(TEXT("dwMagic contains %08x, rather than %08x"), pOurIdList->dwMagic, DSIDL_MAGIC);
  395.         ExitGracefully(hr, E_INVALIDARG, "Bad guard word, cannot unpack");
  396.     }
  397.     pData->dwFlags = pOurIdList->dwFlags;
  398.     pData->dwProviderFlags = pOurIdList->dwProviderFlags;
  399.     pStringData = (LPWSTR)ByteOffset(pOurIdList, pOurIdList->cbToStrings);
  400.     _GetString(&pStringData, &pData->pName, (pData->dwFlags & DSIDL_HASNAME));
  401.     _GetString(&pStringData, &pData->pObjectClass, (pData->dwFlags & DSIDL_HASCLASS));
  402.     _GetString(&pStringData, &pData->pPathElement, TRUE);
  403.     _GetString(&pStringData, &pData->pUNC, (pData->dwFlags & DSIDL_HASUNC));
  404.     // check the cache for the object class if we haven't unpacked it.
  405.     if ( !(pData->dwFlags & DSIDL_HASCLASS) && (dwFlags & DSIDL_HASCLASS) )
  406.     {
  407.         LPCWSTR pObjectClass;
  408.         TraceMsg("IDLIST is simple and has no ObjectClass");
  409. // BUGBUG: crit section
  410.         pObjectClass = g_ObjectCache.GetObjectClass(pData->pPathElement);
  411.         TraceAssert(pObjectClass);
  412.         if ( !pObjectClass )
  413.             ExitGracefully(hr, E_UNEXPECTED, "Failed to get cached ObjectClass");
  414.         StrCpyW(pData->szObjectClass, pObjectClass);
  415.         pData->pObjectClass = pData->szObjectClass;
  416.     }
  417.     hr = S_OK;          // success
  418. exit_gracefully:
  419.     DoRelease(pDsObject);
  420.     SysFreeString(bstrObjectClass);
  421.     TraceLeaveResult(hr);
  422. }
  423. /*-----------------------------------------------------------------------------
  424. / AttributesFromIDL
  425. / -----------------
  426. /   Build the attributes for the given IDLIST data.  This information is
  427. /   derived from both the IDLISTDATA structure and also the information
  428. /   stored in the registry.
  429. /
  430. / In:
  431. /   pData -> IDLISTDATA structure
  432. /
  433. / Out:
  434. /   fAttrib = attributes matching the object
  435. /----------------------------------------------------------------------------*/
  436. ULONG AttributesFromIdList(LPIDLISTDATA pData)
  437. {
  438.     HRESULT hr;
  439.     HKEY aKeys[UIKEY_MAX];
  440.     ULONG fResult = SFGAO_CANLINK;
  441.     ULONG fAttributes;
  442.     DWORD dwType, cb;
  443.     LONG err;
  444.     int i;
  445.     TraceEnter(TRACE_IDLIST, "AttributesFromIdList");
  446.     ZeroMemory(aKeys, SIZEOF(aKeys));
  447.     // Some bits come from the IDLIST we are looking at.
  448.     if ( pData->dwFlags & (DSIDL_ISCONTAINER|DSIDL_HASUNC) )
  449.         fResult |= SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR;
  450.     // Other bits come from the registry under the "ui" keys
  451.     hr = GetKeysForIdList(NULL, pData, ARRAYSIZE(aKeys), aKeys);
  452.     FailGracefully(hr, "Failed when getting keys");
  453.     for ( i = 0 ; i < ARRAYSIZE(aKeys); i++ )
  454.     {
  455.         if ( aKeys[i] )
  456.         {
  457.             cb = SIZEOF(fAttributes);
  458.             if ( ERROR_SUCCESS == RegQueryValueEx(aKeys[i], c_szAttributes, NULL, &dwType, (LPBYTE)&fAttributes, &cb) )
  459.             {
  460.                fResult |= fAttributes;
  461.             }
  462.         }
  463.     }
  464.     hr = S_OK;                      // success
  465. exit_gracefully:
  466.     
  467.     TidyKeys(ARRAYSIZE(aKeys), aKeys);
  468.     TraceLeaveValue(fResult);
  469. }
  470. /*-----------------------------------------------------------------------------
  471. / NameFromIDL
  472. / -----------
  473. /   Crack the RDN from a IDLIST.   Using the path cracker API we are given.
  474. /
  475. / In:
  476. /   pidl -> idlist to be converted
  477. /   pidlParent -> parent of the idlist ( == pidlParent ++ pidl )
  478. /   ppName -> receives a pointer to the name string
  479. /   papn -> pathname interface
  480. /
  481. / Out:
  482. /   HRESULT
  483. /----------------------------------------------------------------------------*/
  484. HRESULT NameFromIdList(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlParent, LPWSTR pName, INT cchName, IADsPathname* papn)
  485. {
  486.     HRESULT hr;
  487.     LPWSTR pPath = NULL;
  488.     BSTR bstrName = NULL;
  489.     LPITEMIDLIST pidlT = NULL;
  490.     IDLISTDATA data = { 0 };
  491.     TraceEnter(TRACE_IDLIST, "NameFromIDL");
  492.    
  493.     // do we have the papn interface we need, if not then lets grab one, 
  494.     // otherwise AddRef the one we have so we can just release on exit.
  495.     if ( !papn )
  496.     {
  497.         hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&papn);
  498.         FailGracefully(hr, "Failed to get the IADsPathname interface");
  499.     }
  500.     else
  501.     {
  502.         papn->AddRef();
  503.     }
  504.     // check to see if the idlist has a name encoded into it?
  505.     hr = UnpackIdList(pidl, 0x0, &data);
  506.     FailGracefully(hr, "Failed to unpack the IDLIST");
  507.     if ( data.dwFlags & DSIDL_HASNAME )
  508.     {
  509.         TraceMsg("Copying name from the IDLISTDATA");
  510.         StrCpyNW(pName, data.pName, cchName);
  511.     }
  512.     else
  513.     {
  514.         TraceMsg("Extracting the name fromt the full path");
  515.         // get the name, feed it into the name cracker and then lets put the
  516.         // result into a buffer that the caller can use...
  517.         if ( pidlParent )
  518.         {
  519.             pidlT = ILCombine(pidlParent, pidl);
  520.             TraceAssert(pidlT);
  521.             if ( !pidlT )
  522.                 ExitGracefully(hr, E_OUTOFMEMORY, "Failed to combine the PIDL");
  523.         }
  524.         hr = PathFromIdList(pidlT ? pidlT:pidl, &pPath, papn);
  525.         FailGracefully(hr, "Failed to get the path from the IDLIST");
  526.         hr = papn->Set(pPath, ADS_SETTYPE_FULL);
  527.         FailGracefully(hr, "Failed to set the path of the name");
  528.         papn->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  529.     
  530.         hr = papn->Retrieve(ADS_FORMAT_LEAF, &bstrName);
  531.         FailGracefully(hr, "Failed to get leaf name");
  532.         StrCpyNW(pName, bstrName, cchName);
  533.     }
  534.     hr = S_OK;
  535. exit_gracefully:
  536.     LocalFreeStringW(&pPath);
  537.     SysFreeString(bstrName);
  538.     DoRelease(papn);
  539.     DoILFree(pidlT);
  540.     TraceLeaveResult(hr);
  541. }
  542. /*-----------------------------------------------------------------------------
  543. / PathFromIdList
  544. / -------------
  545. /   Convert the given IDLIST to a path, we do this by finding
  546. /   the last element and the unpacking that.
  547. /
  548. / In:
  549. /   pidl -> idlist to be converted
  550. /   ppPath -> receives a pointer to the newly allocated string
  551. /   papn -> IADsPathname interface we can use for converting the path to X500 format
  552. /
  553. / Out:
  554. /   HRESULT
  555. /----------------------------------------------------------------------------*/
  556. HRESULT PathFromIdList(LPCITEMIDLIST pidl, LPWSTR* ppPath, IADsPathname* papn)
  557. {
  558.     HRESULT hr = E_FAIL;
  559.     IDLISTDATA data = { 0 };
  560.     
  561.     TraceEnter(TRACE_IDLIST, "PathFromIdList");
  562.     hr = UnpackIdList(ILFindLastID(pidl), 0x0, &data);
  563.     FailGracefully(hr, "Failed to unpack the IDLIST");
  564.     
  565.     hr = LocalAllocStringW(ppPath, data.pPathElement);
  566.     FailGracefully(hr, "Failed to allocate the path element");
  567.     hr = S_OK;          // success
  568. exit_gracefully:
  569.     TraceLeaveResult(hr);
  570. }