Leaked source code of windows server 2003
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.

831 lines
22 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "idlcomm.h"
  4. #include "datautil.h"
  5. #ifdef DEBUG
  6. // Dugging aids for making sure we dont use free pidls
  7. #define VALIDATE_PIDL(pidl) ASSERT(IS_VALID_PIDL(pidl))
  8. #else
  9. #define VALIDATE_PIDL(pidl)
  10. #endif
  11. STDAPI_(LPITEMIDLIST) ILGetNext(LPCITEMIDLIST pidl)
  12. {
  13. LPITEMIDLIST pidlRet = NULL;
  14. if (pidl && pidl->mkid.cb)
  15. {
  16. VALIDATE_PIDL(pidl);
  17. pidlRet = _ILNext(pidl);
  18. }
  19. return pidlRet;
  20. }
  21. STDAPI_(UINT) ILGetSizeAndDepth(LPCITEMIDLIST pidl, DWORD *pdwDepth)
  22. {
  23. DWORD dwDepth = 0;
  24. UINT cbTotal = 0;
  25. if (pidl)
  26. {
  27. VALIDATE_PIDL(pidl);
  28. cbTotal += sizeof(pidl->mkid.cb); // Null terminator
  29. while (pidl->mkid.cb)
  30. {
  31. cbTotal += pidl->mkid.cb;
  32. pidl = _ILNext(pidl);
  33. dwDepth++;
  34. }
  35. }
  36. if (pdwDepth)
  37. *pdwDepth = dwDepth;
  38. return cbTotal;
  39. }
  40. STDAPI_(UINT) ILGetSize(LPCITEMIDLIST pidl)
  41. {
  42. return ILGetSizeAndDepth(pidl, NULL);
  43. }
  44. #define CBIDL_MIN 256
  45. #define CBIDL_INCL 256
  46. STDAPI_(LPITEMIDLIST) ILCreate()
  47. {
  48. return _ILCreate(CBIDL_MIN);
  49. }
  50. // cbExtra is the amount to add to cbRequired if the block needs to grow,
  51. // or it is 0 if we want to resize to the exact size
  52. STDAPI_(LPITEMIDLIST) ILResize(LPITEMIDLIST pidl, UINT cbRequired, UINT cbExtra)
  53. {
  54. if (pidl == NULL)
  55. {
  56. pidl = _ILCreate(cbRequired + cbExtra);
  57. }
  58. else if (!cbExtra || SHGetSize(pidl) < cbRequired)
  59. {
  60. pidl = (LPITEMIDLIST)SHRealloc(pidl, cbRequired + cbExtra);
  61. }
  62. return pidl;
  63. }
  64. STDAPI_(LPITEMIDLIST) ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID pmkid, BOOL fAppend)
  65. {
  66. // Create the ID list, if it is not given.
  67. if (!pidl)
  68. {
  69. pidl = ILCreate();
  70. if (!pidl)
  71. return NULL; // memory overflow
  72. }
  73. UINT cbUsed = ILGetSize(pidl);
  74. UINT cbRequired = cbUsed + pmkid->cb;
  75. pidl = ILResize(pidl, cbRequired, CBIDL_INCL);
  76. if (!pidl)
  77. return NULL; // memory overflow
  78. if (fAppend)
  79. {
  80. // Append it.
  81. MoveMemory(_ILSkip(pidl, cbUsed - sizeof(pidl->mkid.cb)), pmkid, pmkid->cb);
  82. }
  83. else
  84. {
  85. // Put it at the top
  86. MoveMemory(_ILSkip(pidl, pmkid->cb), pidl, cbUsed);
  87. MoveMemory(pidl, pmkid, pmkid->cb);
  88. ASSERT((ILGetSize(_ILNext(pidl))==cbUsed) ||
  89. (pmkid->cb == 0)); // if we're prepending the empty pidl, nothing changed
  90. }
  91. // We must put zero-terminator because of LMEM_ZEROINIT.
  92. _ILSkip(pidl, cbRequired - sizeof(pidl->mkid.cb))->mkid.cb = 0;
  93. ASSERT(ILGetSize(pidl) == cbRequired);
  94. return pidl;
  95. }
  96. STDAPI_(LPITEMIDLIST) ILFindLastID(LPCITEMIDLIST pidl)
  97. {
  98. LPCITEMIDLIST pidlLast = pidl;
  99. LPCITEMIDLIST pidlNext = pidl;
  100. if (pidl == NULL)
  101. return NULL;
  102. VALIDATE_PIDL(pidl);
  103. // Find the last one
  104. while (pidlNext->mkid.cb)
  105. {
  106. pidlLast = pidlNext;
  107. pidlNext = _ILNext(pidlLast);
  108. }
  109. return (LPITEMIDLIST)pidlLast;
  110. }
  111. STDAPI_(BOOL) ILRemoveLastID(LPITEMIDLIST pidl)
  112. {
  113. BOOL fRemoved = FALSE;
  114. if (pidl == NULL)
  115. return FALSE;
  116. if (pidl->mkid.cb)
  117. {
  118. LPITEMIDLIST pidlLast = (LPITEMIDLIST)ILFindLastID(pidl);
  119. ASSERT(pidlLast->mkid.cb);
  120. ASSERT(_ILNext(pidlLast)->mkid.cb==0);
  121. // Remove the last one
  122. pidlLast->mkid.cb = 0; // null-terminator
  123. fRemoved = TRUE;
  124. }
  125. return fRemoved;
  126. }
  127. STDAPI_(LPITEMIDLIST) ILClone(LPCITEMIDLIST pidl)
  128. {
  129. if (pidl)
  130. {
  131. UINT cb = ILGetSize(pidl);
  132. LPITEMIDLIST pidlRet = (LPITEMIDLIST)SHAlloc(cb);
  133. if (pidlRet)
  134. memcpy(pidlRet, pidl, cb);
  135. return pidlRet;
  136. }
  137. return NULL;
  138. }
  139. STDAPI_(LPITEMIDLIST) ILCloneCB(LPCITEMIDLIST pidl, UINT cbPidl)
  140. {
  141. UINT cb = cbPidl + sizeof(pidl->mkid.cb);
  142. LPITEMIDLIST pidlRet = (LPITEMIDLIST)SHAlloc(cb);
  143. if (pidlRet)
  144. {
  145. memcpy(pidlRet, pidl, cbPidl);
  146. // cbPidl can be odd, must use UNALIGNED
  147. *((UNALIGNED WORD *)((BYTE *)pidlRet + cbPidl)) = 0; // NULL terminate
  148. }
  149. return pidlRet;
  150. }
  151. STDAPI_(LPITEMIDLIST) ILCloneUpTo(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlUpTo)
  152. {
  153. return ILCloneCB(pidl, (UINT)((BYTE *)pidlUpTo - (BYTE *)pidl));
  154. }
  155. STDAPI_(LPITEMIDLIST) ILCloneFirst(LPCITEMIDLIST pidl)
  156. {
  157. return ILCloneCB(pidl, pidl->mkid.cb);
  158. }
  159. STDAPI_(BOOL) ILIsEqualEx(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, BOOL fMatchDepth, LPARAM lParam)
  160. {
  161. BOOL fRet = FALSE;
  162. VALIDATE_PIDL(pidl1);
  163. VALIDATE_PIDL(pidl2);
  164. if (pidl1 == pidl2)
  165. fRet = TRUE;
  166. else
  167. {
  168. DWORD dw1;
  169. UINT cb1 = ILGetSizeAndDepth(pidl1, &dw1);
  170. DWORD dw2;
  171. UINT cb2 = ILGetSizeAndDepth(pidl2, &dw2);
  172. if (!fMatchDepth || dw1 == dw2)
  173. {
  174. if (cb1 == cb2 && memcmp(pidl1, pidl2, cb1) == 0)
  175. fRet = TRUE;
  176. else
  177. {
  178. IShellFolder *psfDesktop;
  179. if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
  180. {
  181. if (psfDesktop->CompareIDs(lParam, pidl1, pidl2) == 0)
  182. fRet = TRUE;
  183. psfDesktop->Release();
  184. }
  185. }
  186. }
  187. }
  188. return fRet;
  189. }
  190. // the only case where this wouldnt be effective is if we were using
  191. // an old Simple pidl of a UNC and trying to compare with the actual
  192. // pidl. because the depth wasnt maintained correctly before.
  193. // ILIsParent() has always had this problem.
  194. STDAPI_(BOOL) ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  195. {
  196. return ILIsEqualEx(pidl1, pidl2, TRUE, SHCIDS_CANONICALONLY);
  197. }
  198. // test if
  199. // pidlParent is a parent of pidlBelow
  200. // fImmediate requires that pidlBelow be a direct child of pidlParent.
  201. // Otherwise, self and grandchildren are okay too.
  202. //
  203. // example:
  204. // pidlParent: [my comp] [c:\] [windows]
  205. // pidlBelow: [my comp] [c:\] [windows] [system32] [vmm.vxd]
  206. // fImmediate == FALSE result: TRUE
  207. // fImmediate == TRUE result: FALSE
  208. STDAPI_(BOOL) ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlBelow, BOOL fImmediate)
  209. {
  210. LPCITEMIDLIST pidlParentT;
  211. LPCITEMIDLIST pidlBelowT;
  212. VALIDATE_PIDL(pidlParent);
  213. VALIDATE_PIDL(pidlBelow);
  214. if (!pidlParent || !pidlBelow)
  215. return FALSE;
  216. /* This code will not work correctly when comparing simple NET id lists
  217. / against, real net ID lists. Simple ID lists DO NOT contain network provider
  218. / information therefore cannot pass the initial check of is pidlBelow longer than pidlParent.
  219. / daviddv (2/19/1996) */
  220. for (pidlParentT = pidlParent, pidlBelowT = pidlBelow; !ILIsEmpty(pidlParentT);
  221. pidlParentT = _ILNext(pidlParentT), pidlBelowT = _ILNext(pidlBelowT))
  222. {
  223. // if pidlBelow is shorter than pidlParent, pidlParent can't be its parent.
  224. if (ILIsEmpty(pidlBelowT))
  225. return FALSE;
  226. }
  227. if (fImmediate)
  228. {
  229. // If fImmediate is TRUE, pidlBelowT should contain exactly one ID.
  230. if (ILIsEmpty(pidlBelowT) || !ILIsEmpty(_ILNext(pidlBelowT)))
  231. return FALSE;
  232. }
  233. //
  234. // Create a new IDList from a portion of pidlBelow, which contains the
  235. // same number of IDs as pidlParent.
  236. //
  237. BOOL fRet = FALSE;
  238. UINT cb = (UINT)((UINT_PTR)pidlBelowT - (UINT_PTR)pidlBelow);
  239. LPITEMIDLIST pidlBelowPrefix = _ILCreate(cb + sizeof(pidlBelow->mkid.cb));
  240. if (pidlBelowPrefix)
  241. {
  242. IShellFolder *psfDesktop;
  243. if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
  244. {
  245. CopyMemory(pidlBelowPrefix, pidlBelow, cb);
  246. ASSERT(ILGetSize(pidlBelowPrefix) == cb + sizeof(pidlBelow->mkid.cb));
  247. fRet = psfDesktop->CompareIDs(SHCIDS_CANONICALONLY, pidlParent, pidlBelowPrefix) == ResultFromShort(0);
  248. psfDesktop->Release();
  249. }
  250. ILFree(pidlBelowPrefix);
  251. }
  252. return fRet;
  253. }
  254. // this returns a pointer to the child id ie:
  255. // given
  256. // pidlParent = [my comp] [c] [windows] [desktop]
  257. // pidlChild = [my comp] [c] [windows] [desktop] [dir] [bar.txt]
  258. // return pointer to:
  259. // [dir] [bar.txt]
  260. // NULL is returned if pidlParent is not a parent of pidlChild
  261. STDAPI_(LPITEMIDLIST) ILFindChild(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild)
  262. {
  263. if (ILIsParent(pidlParent, pidlChild, FALSE))
  264. {
  265. while (!ILIsEmpty(pidlParent))
  266. {
  267. pidlChild = _ILNext(pidlChild);
  268. pidlParent = _ILNext(pidlParent);
  269. }
  270. return (LPITEMIDLIST)pidlChild;
  271. }
  272. return NULL;
  273. }
  274. STDAPI_(LPITEMIDLIST) ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  275. {
  276. // Let me pass in NULL pointers
  277. if (!pidl1)
  278. {
  279. if (!pidl2)
  280. {
  281. return NULL;
  282. }
  283. return ILClone(pidl2);
  284. }
  285. else if (!pidl2)
  286. {
  287. return ILClone(pidl1);
  288. }
  289. UINT cb1 = ILGetSize(pidl1) - sizeof(pidl1->mkid.cb);
  290. UINT cb2 = ILGetSize(pidl2);
  291. VALIDATE_PIDL(pidl1);
  292. VALIDATE_PIDL(pidl2);
  293. LPITEMIDLIST pidlNew = _ILCreate(cb1 + cb2);
  294. if (pidlNew)
  295. {
  296. CopyMemory(pidlNew, pidl1, cb1);
  297. CopyMemory((LPTSTR)(((LPBYTE)pidlNew) + cb1), pidl2, cb2);
  298. ASSERT(ILGetSize(pidlNew) == cb1+cb2);
  299. }
  300. return pidlNew;
  301. }
  302. STDAPI_(void) ILFree(LPITEMIDLIST pidl)
  303. {
  304. if (pidl)
  305. {
  306. ASSERT(IS_VALID_PIDL(pidl));
  307. SHFree(pidl);
  308. }
  309. }
  310. // back on Win9x this did global global data, no longer
  311. STDAPI_(LPITEMIDLIST) ILGlobalClone(LPCITEMIDLIST pidl)
  312. {
  313. return ILClone(pidl);
  314. }
  315. STDAPI_(void) ILGlobalFree(LPITEMIDLIST pidl)
  316. {
  317. ILFree(pidl);
  318. }
  319. SHSTDAPI SHParseDisplayName(PCWSTR pszName, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
  320. {
  321. *ppidl = 0;
  322. if (psfgaoOut)
  323. *psfgaoOut = 0;
  324. // since ISF::PDN() takes a non-const pointer
  325. PWSTR pszParse = StrDupW(pszName);
  326. HRESULT hr = pszParse ? S_OK : E_OUTOFMEMORY;
  327. if (SUCCEEDED(hr))
  328. {
  329. CComPtr<IShellFolder> spsfDesktop;
  330. hr = SHGetDesktopFolder(&spsfDesktop);
  331. if (SUCCEEDED(hr))
  332. {
  333. CComPtr<IBindCtx> spbcLocal;
  334. // if they pass their own pbc, then they are responsible for
  335. // adding in the translate param, else we default to using it
  336. if (!pbc)
  337. {
  338. hr = BindCtx_RegisterObjectParam(NULL, STR_PARSE_TRANSLATE_ALIASES, NULL, &spbcLocal);
  339. pbc = spbcLocal;
  340. }
  341. if (SUCCEEDED(hr))
  342. {
  343. ULONG cchEaten;
  344. SFGAOF sfgaoInOut = sfgaoIn;
  345. hr = spsfDesktop->ParseDisplayName(BindCtx_GetUIWindow(pbc), pbc, pszParse, &cchEaten, ppidl, psfgaoOut ? &sfgaoInOut : NULL);
  346. if (SUCCEEDED(hr) && psfgaoOut)
  347. {
  348. *psfgaoOut = (sfgaoInOut & sfgaoIn); // only return attributes passed in
  349. }
  350. }
  351. }
  352. LocalFree(pszParse);
  353. }
  354. return hr;
  355. }
  356. HRESULT _CFPBindCtx(IUnknown *punkToSkip, ILCFP_FLAGS dwFlags, IBindCtx **ppbc)
  357. {
  358. HRESULT hr = S_FALSE;
  359. if (punkToSkip || (dwFlags & ILCFP_FLAG_SKIPJUNCTIONS))
  360. hr = SHCreateSkipBindCtx(punkToSkip, ppbc);
  361. else if (dwFlags & ILCFP_FLAG_NO_MAP_ALIAS)
  362. {
  363. // we need to create a bindctx to block alias mapping.
  364. // this will keep SHParseDisplayName() from adding the STR_PARSE_TRANSLATE_ALIASES
  365. hr = CreateBindCtx(0, ppbc);
  366. }
  367. return hr;
  368. }
  369. STDAPI ILCreateFromPathEx(LPCTSTR pszPath, IUnknown *punkToSkip, ILCFP_FLAGS dwFlags, LPITEMIDLIST *ppidl, DWORD *rgfInOut)
  370. {
  371. CComPtr<IBindCtx> spbc;
  372. HRESULT hr = _CFPBindCtx(punkToSkip, dwFlags, &spbc);
  373. if (SUCCEEDED(hr))
  374. {
  375. hr = SHParseDisplayName(pszPath, spbc, ppidl, rgfInOut ? *rgfInOut : 0, rgfInOut);
  376. }
  377. return hr;
  378. }
  379. STDAPI ILCreateFromCLSID(REFCLSID clsid, LPITEMIDLIST *ppidl)
  380. {
  381. TCHAR szCLSID[GUIDSTR_MAX + 3];
  382. szCLSID[0] = TEXT(':');
  383. szCLSID[1] = TEXT(':');
  384. SHStringFromGUID(clsid, szCLSID + 2, ARRAYSIZE(szCLSID) - 2);
  385. return SHILCreateFromPath(szCLSID, ppidl, NULL);
  386. }
  387. STDAPI SHILCreateFromPath(LPCTSTR pszPath, LPITEMIDLIST *ppidl, DWORD *rgfInOut)
  388. {
  389. return ILCreateFromPathEx(pszPath, NULL, ILCFP_FLAG_NO_MAP_ALIAS, ppidl, rgfInOut);
  390. }
  391. STDAPI_(LPITEMIDLIST) ILCreateFromPath(LPCTSTR pszPath)
  392. {
  393. LPITEMIDLIST pidl = NULL;
  394. HRESULT hr = SHILCreateFromPath(pszPath, &pidl, NULL);
  395. ASSERT(SUCCEEDED(hr) ? pidl != NULL : pidl == NULL);
  396. return pidl;
  397. }
  398. LPITEMIDLIST ILCreateFromPathA(IN LPCSTR pszPath)
  399. {
  400. TCHAR szPath[MAX_PATH];
  401. SHAnsiToUnicode(pszPath, szPath, SIZECHARS(szPath));
  402. return ILCreateFromPath(szPath);
  403. }
  404. STDAPI_(BOOL) ILGetDisplayNameEx(IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR pszName, int fType)
  405. {
  406. TraceMsg(TF_WARNING, "WARNING: ILGetDisplayNameEx() has been deprecated, should use SHGetNameAndFlags() instead!!!");
  407. RIPMSG(pszName && IS_VALID_WRITE_BUFFER(pszName, TCHAR, MAX_PATH), "ILGetDisplayNameEx: caller passed bad pszName");
  408. if (!pszName)
  409. return FALSE;
  410. DEBUGWhackPathBuffer(pszName, MAX_PATH);
  411. *pszName = 0;
  412. if (!pidl)
  413. return FALSE;
  414. HRESULT hr;
  415. if (psf)
  416. {
  417. hr = S_OK;
  418. psf->AddRef();
  419. }
  420. else
  421. {
  422. hr = SHGetDesktopFolder(&psf);
  423. }
  424. if (SUCCEEDED(hr))
  425. {
  426. DWORD dwGDNFlags;
  427. switch (fType)
  428. {
  429. case ILGDN_FULLNAME:
  430. dwGDNFlags = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
  431. hr = DisplayNameOf(psf, pidl, dwGDNFlags, pszName, MAX_PATH);
  432. break;
  433. case ILGDN_INFOLDER:
  434. case ILGDN_ITEMONLY:
  435. dwGDNFlags = fType == ILGDN_INFOLDER ? SHGDN_INFOLDER : SHGDN_NORMAL;
  436. if (!ILIsEmpty(pidl))
  437. {
  438. hr = SHGetNameAndFlags(pidl, dwGDNFlags, pszName, MAX_PATH, NULL);
  439. }
  440. else
  441. {
  442. hr = DisplayNameOf(psf, pidl, dwGDNFlags, pszName, MAX_PATH);
  443. }
  444. break;
  445. }
  446. psf->Release();
  447. }
  448. return SUCCEEDED(hr) ? TRUE : FALSE;
  449. }
  450. STDAPI_(BOOL) ILGetDisplayName(LPCITEMIDLIST pidl, LPTSTR pszPath)
  451. {
  452. return ILGetDisplayNameEx(NULL, pidl, pszPath, ILGDN_FULLNAME);
  453. }
  454. //*** ILGetPseudoName -- encode pidl relative to base
  455. // Not used any more
  456. //
  457. STDAPI_(BOOL) ILGetPseudoNameW(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlSpec, WCHAR *pszBuf, int fType)
  458. {
  459. *pszBuf = TEXT('\0');
  460. return FALSE;
  461. }
  462. STDAPI ILLoadFromStream(IStream *pstm, LPITEMIDLIST * ppidl)
  463. {
  464. ASSERT(ppidl);
  465. // Delete the old one if any.
  466. if (*ppidl)
  467. {
  468. ILFree(*ppidl);
  469. *ppidl = NULL;
  470. }
  471. // Read the size of the IDLIST
  472. ULONG cb = 0; // WARNING: We need to fill its HIWORD!
  473. HRESULT hr = pstm->Read(&cb, sizeof(USHORT), NULL); // Yes, USHORT
  474. if (SUCCEEDED(hr) && cb)
  475. {
  476. // Create a IDLIST
  477. LPITEMIDLIST pidl = _ILCreate(cb);
  478. if (pidl)
  479. {
  480. // Read its contents
  481. hr = pstm->Read(pidl, cb, NULL);
  482. if (SUCCEEDED(hr))
  483. {
  484. // Some pidls may be invalid. We know they are invalid
  485. // if their size claims to be larger than the memory we
  486. // allocated.
  487. if (SHIsConsistentPidl(pidl, cb))
  488. {
  489. *ppidl = pidl;
  490. }
  491. else
  492. {
  493. hr = E_FAIL;
  494. }
  495. }
  496. if (FAILED(hr))
  497. {
  498. ILFree(pidl);
  499. }
  500. }
  501. else
  502. {
  503. hr = E_OUTOFMEMORY;
  504. }
  505. }
  506. return hr;
  507. }
  508. STDAPI ILSaveToStream(IStream *pstm, LPCITEMIDLIST pidl)
  509. {
  510. ULONG cb = ILGetSize(pidl);
  511. ASSERT(HIWORD(cb) == 0);
  512. HRESULT hr = pstm->Write(&cb, sizeof(USHORT), NULL); // Yes, USHORT
  513. if (SUCCEEDED(hr) && cb)
  514. {
  515. hr = pstm->Write(pidl, cb, NULL);
  516. }
  517. return hr;
  518. }
  519. //
  520. // This one reallocated pidl if necessary. NULL is valid to pass in as pidl.
  521. //
  522. STDAPI_(LPITEMIDLIST) HIDA_FillIDList(HIDA hida, UINT i, LPITEMIDLIST pidl)
  523. {
  524. UINT cbRequired = HIDA_GetIDList(hida, i, NULL, 0);
  525. pidl = ILResize(pidl, cbRequired, 32); // extra 32-byte if we realloc
  526. if (pidl)
  527. {
  528. HIDA_GetIDList(hida, i, pidl, cbRequired);
  529. }
  530. return pidl;
  531. }
  532. STDAPI_(LPITEMIDLIST) IDA_FullIDList(LPIDA pida, UINT i)
  533. {
  534. LPITEMIDLIST pidl = NULL;
  535. LPCITEMIDLIST pidlParent = IDA_GetIDListPtr(pida, (UINT)-1);
  536. if (pidlParent)
  537. {
  538. LPCITEMIDLIST pidlRel = IDA_GetIDListPtr(pida, i);
  539. if (pidlRel)
  540. {
  541. pidl = ILCombine(pidlParent, pidlRel);
  542. }
  543. }
  544. return pidl;
  545. }
  546. LPITEMIDLIST HIDA_ILClone(HIDA hida, UINT i)
  547. {
  548. LPIDA pida = (LPIDA)GlobalLock(hida);
  549. if (pida)
  550. {
  551. LPITEMIDLIST pidl = IDA_ILClone(pida, i);
  552. GlobalUnlock(hida);
  553. return pidl;
  554. }
  555. return NULL;
  556. }
  557. //
  558. // This is a helper function to be called from within IShellFolder::CompareIDs.
  559. // When the first IDs of pidl1 and pidl2 are the (logically) same.
  560. //
  561. // Required:
  562. // psf && pidl1 && pidl2 && !ILEmpty(pidl1) && !ILEmpty(pidl2)
  563. //
  564. HRESULT ILCompareRelIDs(IShellFolder *psfParent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, LPARAM lParam)
  565. {
  566. HRESULT hr;
  567. LPCITEMIDLIST pidlRel1 = _ILNext(pidl1);
  568. LPCITEMIDLIST pidlRel2 = _ILNext(pidl2);
  569. if (ILIsEmpty(pidlRel1))
  570. {
  571. if (ILIsEmpty(pidlRel2))
  572. hr = ResultFromShort(0);
  573. else
  574. hr = ResultFromShort(-1);
  575. }
  576. else
  577. {
  578. if (ILIsEmpty(pidlRel2))
  579. {
  580. hr = ResultFromShort(1);
  581. }
  582. else
  583. {
  584. //
  585. // pidlRel1 and pidlRel2 point to something
  586. // (1) Bind to the next level of the IShellFolder
  587. // (2) Call its CompareIDs to let it compare the rest of IDs.
  588. //
  589. LPITEMIDLIST pidlNext = ILCloneFirst(pidl1); // pidl2 would work as well
  590. if (pidlNext)
  591. {
  592. IShellFolder *psfNext;
  593. hr = psfParent->BindToObject(pidlNext, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
  594. if (SUCCEEDED(hr))
  595. {
  596. IShellFolder2 *psf2;
  597. if (SUCCEEDED(psfNext->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2))))
  598. {
  599. // we can use the lParam
  600. psf2->Release();
  601. }
  602. else // cant use the lParam
  603. lParam = 0;
  604. // columns arent valid to pass down
  605. // we just care about the flags param
  606. hr = psfNext->CompareIDs((lParam & ~SHCIDS_COLUMNMASK), pidlRel1, pidlRel2);
  607. psfNext->Release();
  608. }
  609. ILFree(pidlNext);
  610. }
  611. else
  612. {
  613. hr = E_OUTOFMEMORY;
  614. }
  615. }
  616. }
  617. return hr;
  618. }
  619. // in:
  620. // pszLeft
  621. // pidl
  622. //
  623. // in/out:
  624. // psr
  625. STDAPI StrRetCatLeft(LPCTSTR pszLeft, STRRET *psr, LPCITEMIDLIST pidl)
  626. {
  627. HRESULT hr;
  628. TCHAR szRight[MAX_PATH];
  629. UINT cchRight, cchLeft = ualstrlen(pszLeft);
  630. switch (psr->uType)
  631. {
  632. case STRRET_CSTR:
  633. cchRight = lstrlenA(psr->cStr);
  634. break;
  635. case STRRET_OFFSET:
  636. cchRight = lstrlenA(STRRET_OFFPTR(pidl, psr));
  637. break;
  638. case STRRET_WSTR:
  639. cchRight = lstrlenW(psr->pOleStr);
  640. break;
  641. }
  642. if (cchLeft + cchRight < MAX_PATH)
  643. {
  644. hr = StrRetToBuf(psr, pidl, szRight, ARRAYSIZE(szRight)); // will free psr for us
  645. if (SUCCEEDED(hr))
  646. {
  647. size_t cchTotal = (lstrlen(pszLeft) + 1 + cchRight);
  648. psr->pOleStr = (LPOLESTR)SHAlloc(cchTotal * sizeof(TCHAR));
  649. if (psr->pOleStr == NULL)
  650. {
  651. hr = E_OUTOFMEMORY;
  652. }
  653. else
  654. {
  655. psr->uType = STRRET_WSTR;
  656. StringCchCopy(psr->pOleStr, cchTotal, pszLeft);
  657. StringCchCat(psr->pOleStr, cchTotal, szRight);
  658. hr = S_OK;
  659. }
  660. }
  661. }
  662. else
  663. {
  664. hr = E_NOTIMPL;
  665. }
  666. return hr;
  667. }
  668. STDAPI_(void) StrRetFormat(STRRET *psr, LPCITEMIDLIST pidlRel, LPCTSTR pszTemplate, LPCTSTR pszAppend)
  669. {
  670. TCHAR szT[MAX_PATH];
  671. StrRetToBuf(psr, pidlRel, szT, ARRAYSIZE(szT));
  672. LPTSTR pszRet = ShellConstructMessageString(HINST_THISDLL, pszTemplate, pszAppend, szT);
  673. if (pszRet)
  674. {
  675. StringToStrRet(pszRet, psr);
  676. LocalFree(pszRet);
  677. }
  678. }
  679. //
  680. // Notes: This one passes SHGDN_FORPARSING to ISF::GetDisplayNameOf.
  681. //
  682. HRESULT ILGetRelDisplayName(IShellFolder *psf, STRRET *psr,
  683. LPCITEMIDLIST pidlRel, LPCTSTR pszName, LPCTSTR pszTemplate, DWORD dwFlags)
  684. {
  685. HRESULT hr;
  686. LPITEMIDLIST pidlLeft = ILCloneFirst(pidlRel);
  687. if (pidlLeft)
  688. {
  689. IShellFolder *psfNext;
  690. hr = psf->BindToObject(pidlLeft, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
  691. if (SUCCEEDED(hr))
  692. {
  693. LPCITEMIDLIST pidlRight = _ILNext(pidlRel);
  694. hr = psfNext->GetDisplayNameOf(pidlRight, dwFlags, psr);
  695. if (SUCCEEDED(hr))
  696. {
  697. if (pszTemplate)
  698. {
  699. StrRetFormat(psr, pidlRight, pszTemplate, pszName);
  700. }
  701. else
  702. {
  703. hr = StrRetCatLeft(pszName, psr, pidlRight);
  704. }
  705. }
  706. psfNext->Release();
  707. }
  708. ILFree(pidlLeft);
  709. }
  710. else
  711. {
  712. hr = E_OUTOFMEMORY;
  713. }
  714. return hr;
  715. }
  716. #undef ILCreateFromPath
  717. STDAPI_(LPITEMIDLIST) ILCreateFromPath(LPCTSTR pszPath)
  718. {
  719. return ILCreateFromPathW(pszPath);
  720. }