Source code of Windows XP (NT5)
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.

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