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.

752 lines
18 KiB

  1. #include <windows.h>
  2. #include <shlobj.h>
  3. #include "debug.h"
  4. #include "idlist.h"
  5. #include "common.h"
  6. #ifdef DEBUG
  7. // Dugging aids for making sure we dont use free pidls
  8. #define VALIDATE_PIDL(pidl) Assert((pidl)->mkid.cb != 0xC5C5)
  9. #else
  10. #define VALIDATE_PIDL(pidl)
  11. #endif
  12. // BUGBUG: should call shell alocator
  13. #define SHAlloc(cb) (void *)LocalAlloc(LPTR, cb)
  14. #define SHFree(p) LocalFree((HLOCAL)p)
  15. #define SHGetSize(p) LocalSize((HLOCAL)p)
  16. #define SHRealloc(p, cb) (void *)LocalReAlloc((HLOCAL)p, cb, LMEM_MOVEABLE | LMEM_ZEROINIT)
  17. LPITEMIDLIST ILGetNext(LPCITEMIDLIST pidl)
  18. {
  19. if (pidl && pidl->mkid.cb)
  20. {
  21. VALIDATE_PIDL(pidl);
  22. return _ILNext(pidl);
  23. }
  24. return NULL;
  25. }
  26. UINT ILGetSize(LPCITEMIDLIST pidl)
  27. {
  28. UINT cbTotal = 0;
  29. if (pidl)
  30. {
  31. VALIDATE_PIDL(pidl);
  32. cbTotal += sizeof(pidl->mkid.cb); // Null terminator
  33. while (pidl->mkid.cb)
  34. {
  35. cbTotal += pidl->mkid.cb;
  36. pidl = _ILNext(pidl);
  37. }
  38. }
  39. return cbTotal;
  40. }
  41. #define CBIDL_MIN 256
  42. #define CBIDL_INCL 256
  43. LPITEMIDLIST _ILCreate(UINT cbSize)
  44. {
  45. return (LPITEMIDLIST)SHAlloc(cbSize);
  46. }
  47. LPITEMIDLIST ILCreate()
  48. {
  49. return (LPITEMIDLIST)SHAlloc(CBIDL_MIN);
  50. }
  51. /*
  52. ** _ILResize
  53. *
  54. * PARAMETERS:
  55. * cbExtra is the amount to add to cbRequired if the block needs to grow,
  56. * or it is 0 if we want to resize to the exact size
  57. *
  58. * DESCRIPTION:
  59. *
  60. * RETURNS:
  61. *
  62. */
  63. LPITEMIDLIST _ILResize(LPITEMIDLIST pidl, UINT cbRequired, UINT cbExtra)
  64. {
  65. if (pidl==NULL)
  66. {
  67. pidl = _ILCreate(cbRequired+cbExtra);
  68. }
  69. else if (!cbExtra || SHGetSize(pidl) < cbRequired)
  70. {
  71. pidl = (LPITEMIDLIST)SHRealloc(pidl, cbRequired+cbExtra);
  72. }
  73. return pidl;
  74. }
  75. LPITEMIDLIST ILFindLastID(LPCITEMIDLIST pidl)
  76. {
  77. LPCITEMIDLIST pidlLast = pidl;
  78. LPCITEMIDLIST pidlNext = pidl;
  79. VALIDATE_PIDL(pidl);
  80. if (pidl == NULL)
  81. return NULL;
  82. // Find the last one
  83. while (pidlNext->mkid.cb)
  84. {
  85. pidlLast = pidlNext;
  86. pidlNext = _ILNext(pidlLast);
  87. }
  88. return (LPITEMIDLIST)pidlLast;
  89. }
  90. BOOL ILRemoveLastID(LPITEMIDLIST pidl)
  91. {
  92. BOOL fRemoved = FALSE;
  93. if (pidl == NULL)
  94. return(FALSE);
  95. if (pidl->mkid.cb)
  96. {
  97. LPITEMIDLIST pidlLast = (LPITEMIDLIST)ILFindLastID(pidl);
  98. Assert(pidlLast->mkid.cb);
  99. Assert(_ILNext(pidlLast)->mkid.cb==0);
  100. // Remove the last one
  101. pidlLast->mkid.cb = 0; // null-terminator
  102. fRemoved = TRUE;
  103. }
  104. return fRemoved;
  105. }
  106. LPITEMIDLIST ILClone(LPCITEMIDLIST pidl)
  107. {
  108. UINT cb = ILGetSize(pidl);
  109. LPITEMIDLIST pidlRet = (LPITEMIDLIST)SHAlloc(cb);
  110. if (pidlRet)
  111. {
  112. // Notes: no need to zero-init.
  113. CopyMemory(pidlRet, pidl, cb);
  114. }
  115. return pidlRet;
  116. }
  117. LPITEMIDLIST ILCloneFirst(LPCITEMIDLIST pidl)
  118. {
  119. UINT cb = pidl->mkid.cb+sizeof(pidl->mkid.cb);
  120. LPITEMIDLIST pidlRet = (LPITEMIDLIST)SHAlloc(cb);
  121. if (pidlRet)
  122. {
  123. // Notes: no need to zero-init.
  124. CopyMemory(pidlRet, pidl, pidl->mkid.cb);
  125. _ILNext(pidlRet)->mkid.cb = 0;
  126. }
  127. return pidlRet;
  128. }
  129. BOOL ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  130. {
  131. IShellFolder *psfDesktop;
  132. if (FAILED(SHGetDesktopFolder(&psfDesktop)))
  133. return FALSE;
  134. VALIDATE_PIDL(pidl1);
  135. VALIDATE_PIDL(pidl2);
  136. return psfDesktop->lpVtbl->CompareIDs(psfDesktop, 0, pidl1, pidl2) == 0;
  137. }
  138. // test if
  139. // pidl1 is a parent of pidl2
  140. BOOL ILIsParent(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, BOOL fImmediate)
  141. {
  142. LPITEMIDLIST pidl2Prefix;
  143. UINT cb;
  144. LPCITEMIDLIST pidl1T;
  145. LPCITEMIDLIST pidl2T;
  146. VALIDATE_PIDL(pidl1);
  147. VALIDATE_PIDL(pidl2);
  148. if (!pidl1 || !pidl2)
  149. return FALSE;
  150. for (pidl1T = pidl1, pidl2T = pidl2; !ILIsEmpty(pidl1T);
  151. pidl1T = _ILNext(pidl1T), pidl2T = _ILNext(pidl2T))
  152. {
  153. // if pidl2 is shorter than pidl1, pidl1 can't be its parent.
  154. if (ILIsEmpty(pidl2T))
  155. return FALSE;
  156. }
  157. if (fImmediate)
  158. {
  159. // If fImmediate is TRUE, pidl2T should contain exactly one ID.
  160. if (ILIsEmpty(pidl2T) || !ILIsEmpty(_ILNext(pidl2T)))
  161. return FALSE;
  162. }
  163. //
  164. // Create a new IDList from a portion of pidl2, which contains the
  165. // same number of IDs as pidl1.
  166. //
  167. cb = (UINT)pidl2T - (UINT)pidl2;
  168. pidl2Prefix = _ILCreate(cb + sizeof(pidl2->mkid.cb));
  169. if (pidl2Prefix)
  170. {
  171. BOOL fRet;
  172. CopyMemory(pidl2Prefix, pidl2, cb);
  173. Assert(ILGetSize(pidl2Prefix) == cb + sizeof(pidl2->mkid.cb));
  174. fRet = ILIsEqual(pidl1, pidl2Prefix);
  175. ILFree(pidl2Prefix);
  176. return fRet;
  177. }
  178. return FALSE;
  179. }
  180. // this returns a pointer to the child id ie:
  181. // given pidlParent = \chicago\desktop
  182. // pidlChild = \chicago\desktop\foo\bar
  183. // the return will point to the ID that represents \foo\bar
  184. // NULL is returned if pidlParent is not a parent of pidlChild
  185. LPITEMIDLIST ILFindChild(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild)
  186. {
  187. if (ILIsParent(pidlParent, pidlChild, FALSE))
  188. {
  189. while (!ILIsEmpty(pidlParent))
  190. {
  191. pidlChild = _ILNext(pidlChild);
  192. pidlParent = _ILNext(pidlParent);
  193. }
  194. return (LPITEMIDLIST)pidlChild;
  195. }
  196. return NULL;
  197. }
  198. LPITEMIDLIST ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  199. {
  200. LPITEMIDLIST pidlNew;
  201. UINT cb1 = ILGetSize(pidl1) - sizeof(pidl1->mkid.cb);
  202. UINT cb2 = ILGetSize(pidl2);
  203. VALIDATE_PIDL(pidl1);
  204. VALIDATE_PIDL(pidl2);
  205. pidlNew = _ILCreate(cb1 + cb2);
  206. if (pidlNew)
  207. {
  208. CopyMemory(pidlNew, pidl1, cb1);
  209. CopyMemory(((LPSTR)pidlNew) + cb1, pidl2, cb2);
  210. Assert(ILGetSize(pidlNew) == cb1+cb2);
  211. }
  212. return pidlNew;
  213. }
  214. void ILFree(LPITEMIDLIST pidl)
  215. {
  216. if (pidl)
  217. {
  218. #ifdef DEBUG
  219. UINT cbSize = SHGetSize(pidl);
  220. VALIDATE_PIDL(pidl);
  221. // Fill the memory with some bad value...
  222. _memset(pidl, 0xE5, cbSize);
  223. // If large enough try to save the call return address of who
  224. // freed us in the 3-6 byte of the structure.
  225. if (cbSize >= 6)
  226. *((UINT*)((LPSTR)pidl + 2)) = *(((UINT*)&pidl) - 1);
  227. #endif
  228. SHFree(pidl);
  229. }
  230. }
  231. LPITEMIDLIST ILCreateFromPath(LPCSTR pszPath)
  232. {
  233. LPITEMIDLIST pidl = NULL;
  234. IShellFolder *psfDesktop;
  235. if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
  236. {
  237. ULONG cchEaten;
  238. WCHAR wszPath[MAX_PATH];
  239. StrToOleStrN(wszPath, ARRAYSIZE(wszPath), pszPath, -1);
  240. psfDesktop->lpVtbl->ParseDisplayName(psfDesktop, NULL, NULL, wszPath, &cchEaten, &pidl, NULL);
  241. }
  242. return pidl;
  243. }
  244. //===========================================================================
  245. // IDLIST: Stream access
  246. // BUGBUG: check bytes read on Read calls?
  247. //===========================================================================
  248. HRESULT ILLoadFromStream(LPSTREAM pstm, LPITEMIDLIST * ppidl)
  249. {
  250. HRESULT hres;
  251. ULONG cb;
  252. Assert(ppidl);
  253. // Delete the old one if any.
  254. if (*ppidl)
  255. {
  256. ILFree(*ppidl);
  257. *ppidl = NULL;
  258. }
  259. // Read the size of the IDLIST
  260. cb = 0; // WARNING: We need to fill its HIWORD!
  261. hres = pstm->lpVtbl->Read(pstm, &cb, sizeof(USHORT), NULL); // Yes, USHORT
  262. if (SUCCEEDED(hres) && cb)
  263. {
  264. // Create a IDLIST
  265. LPITEMIDLIST pidl = _ILCreate(cb);
  266. if (pidl)
  267. {
  268. // Read its contents
  269. hres = pstm->lpVtbl->Read(pstm, pidl, cb, NULL);
  270. if (SUCCEEDED(hres))
  271. {
  272. *ppidl = pidl;
  273. }
  274. else
  275. {
  276. ILFree(pidl);
  277. }
  278. }
  279. else
  280. {
  281. hres = E_OUTOFMEMORY;
  282. }
  283. }
  284. return hres;
  285. }
  286. // BUGBUG: check bytes written on Write calls?
  287. HRESULT ILSaveToStream(LPSTREAM pstm, LPCITEMIDLIST pidl)
  288. {
  289. HRESULT hres;
  290. ULONG cb = ILGetSize(pidl);
  291. Assert(HIWORD(cb) == 0);
  292. hres = pstm->lpVtbl->Write(pstm, &cb, sizeof(USHORT), NULL); // Yes, USHORT
  293. if (SUCCEEDED(hres) && cb)
  294. {
  295. if (SUCCEEDED(hres))
  296. {
  297. hres = pstm->lpVtbl->Write(pstm, pidl, cb, NULL);
  298. }
  299. }
  300. return hres;
  301. }
  302. #ifdef _HIDA
  303. //===========================================================================
  304. // IDLARRAY stuff
  305. //===========================================================================
  306. #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
  307. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  308. HIDA HIDA_Create(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST * apidl)
  309. {
  310. HIDA hida;
  311. UINT i;
  312. UINT offset = sizeof(CIDA) + sizeof(UINT)*cidl;
  313. UINT cbTotal = offset + ILGetSize(pidlFolder);
  314. for (i=0; i<cidl ; i++) {
  315. cbTotal += ILGetSize(apidl[i]);
  316. }
  317. hida = GlobalAlloc(GPTR, cbTotal); // This MUST be GlobalAlloc!!!
  318. if (hida)
  319. {
  320. LPIDA pida = (LPIDA)hida; // no need to lock
  321. LPCITEMIDLIST pidlNext;
  322. pida->cidl = cidl;
  323. for (i=0, pidlNext=pidlFolder; ; pidlNext=apidl[i++])
  324. {
  325. UINT cbSize = ILGetSize(pidlNext);
  326. pida->aoffset[i] = offset;
  327. CopyMemory(((LPBYTE)pida)+offset, pidlNext, cbSize);
  328. offset += cbSize;
  329. Assert(ILGetSize(HIDA_GetPIDLItem(pida,i-1)) == cbSize);
  330. if (i==cidl)
  331. break;
  332. }
  333. Assert(offset == cbTotal);
  334. }
  335. return hida;
  336. }
  337. HIDA HIDA_Create2(LPVOID pida, UINT cb)
  338. {
  339. HIDA hida = GlobalAlloc(GPTR, cb);
  340. if (hida)
  341. {
  342. CopyMemory((LPIDA)hida, pida, cb); // no need to lock
  343. }
  344. return hida;
  345. }
  346. HIDA HIDA_Clone(HIDA hida)
  347. {
  348. UINT cbTotal = GlobalSize(hida);
  349. HIDA hidaCopy = GlobalAlloc(GPTR, cbTotal);
  350. if (hidaCopy)
  351. {
  352. LPIDA pida = (LPIDA)GlobalLock(hida);
  353. CopyMemory((LPIDA)hidaCopy, pida, cbTotal); // no need to lock
  354. GlobalUnlock(hida);
  355. }
  356. return hidaCopy;
  357. }
  358. UINT HIDA_GetCount(HIDA hida)
  359. {
  360. UINT count = 0;
  361. LPIDA pida = (LPIDA)GlobalLock(hida);
  362. if (pida) {
  363. count = pida->cidl;
  364. GlobalUnlock(hida);
  365. }
  366. return count;
  367. }
  368. UINT HIDA_GetIDList(HIDA hida, UINT i, LPITEMIDLIST pidlOut, UINT cbMax)
  369. {
  370. LPIDA pida = (LPIDA)GlobalLock(hida);
  371. if (pida)
  372. {
  373. LPCITEMIDLIST pidlFolder = HIDA_GetPIDLFolder(pida);
  374. LPCITEMIDLIST pidlItem = HIDA_GetPIDLItem(pida, i);
  375. UINT cbFolder = ILGetSize(pidlFolder)-sizeof(USHORT);
  376. UINT cbItem = ILGetSize(pidlItem);
  377. if (cbMax < cbFolder+cbItem) {
  378. if (pidlOut) {
  379. pidlOut->mkid.cb = 0;
  380. }
  381. } else {
  382. CopyMemory(pidlOut, pidlFolder, cbFolder);
  383. CopyMemory(((LPBYTE)pidlOut)+cbFolder, pidlItem, cbItem);
  384. }
  385. GlobalUnlock(hida);
  386. return (cbFolder+cbItem);
  387. }
  388. return 0;
  389. }
  390. //
  391. // This one reallocated pidl if necessary. NULL is valid to pass in as pidl.
  392. //
  393. LPITEMIDLIST HIDA_FillIDList(HIDA hida, UINT i, LPITEMIDLIST pidl)
  394. {
  395. UINT cbRequired = HIDA_GetIDList(hida, i, NULL, 0);
  396. pidl = _ILResize(pidl, cbRequired, 32); // extra 32-byte if we realloc
  397. if (pidl)
  398. {
  399. HIDA_GetIDList(hida, i, pidl, cbRequired);
  400. }
  401. return pidl;
  402. }
  403. LPCITEMIDLIST IDA_GetIDListPtr(LPIDA pida, UINT i)
  404. {
  405. if (i == (UINT)-1 || i < pida->cidl)
  406. {
  407. return HIDA_GetPIDLItem(pida, i);
  408. }
  409. return NULL;
  410. }
  411. LPITEMIDLIST IDA_ILClone(LPIDA pida, UINT i)
  412. {
  413. if (i < pida->cidl)
  414. return ILCombine(HIDA_GetPIDLFolder(pida), HIDA_GetPIDLItem(pida, i));
  415. return NULL;
  416. }
  417. LPITEMIDLIST HIDA_ILClone(HIDA hida, UINT i)
  418. {
  419. LPIDA pida = (LPIDA)GlobalLock(hida);
  420. if (pida)
  421. {
  422. LPITEMIDLIST pidl = IDA_ILClone(pida, i);
  423. GlobalUnlock(hida);
  424. return pidl;
  425. }
  426. return NULL;
  427. }
  428. void HIDA_ReleaseStgMedium(LPIDA pida, STGMEDIUM *pmedium)
  429. {
  430. if (pmedium->hGlobal && (pmedium->tymed==TYMED_HGLOBAL))
  431. {
  432. #ifdef DEBUG
  433. if (pida)
  434. {
  435. LPIDA pidaT = (LPIDA)GlobalLock(pmedium->hGlobal);
  436. Assert(pidaT == pida);
  437. GlobalUnlock(pmedium->hGlobal);
  438. }
  439. #endif
  440. GlobalUnlock(pmedium->hGlobal);
  441. }
  442. else
  443. {
  444. Assert(0);
  445. }
  446. SHReleaseStgMedium(pmedium);
  447. }
  448. #endif // _HIDA
  449. BOOL StrRetToStrN(LPSTR szOut, UINT uszOut, LPSTRRET pStrRet, LPCITEMIDLIST pidl)
  450. {
  451. switch (pStrRet->uType)
  452. {
  453. case STRRET_WSTR:
  454. OleStrToStrN(szOut, uszOut, pStrRet->pOleStr, -1);
  455. SHFree(pStrRet->pOleStr);
  456. break;
  457. case STRRET_CSTR:
  458. lstrcpyn(szOut, pStrRet->cStr, uszOut);
  459. break;
  460. case STRRET_OFFSET:
  461. if (pidl)
  462. {
  463. lstrcpyn(szOut, ((LPCSTR)&pidl->mkid)+pStrRet->uOffset, uszOut);
  464. break;
  465. }
  466. // Fall through
  467. default:
  468. if (uszOut)
  469. *szOut = '\0';
  470. return FALSE;
  471. }
  472. return TRUE;
  473. }
  474. #if 0
  475. //
  476. // This is a helper function to be called from within IShellFolder::CompareIDs.
  477. // When the first IDs of pidl1 and pidl2 are the (logically) same.
  478. //
  479. // Required:
  480. // psf && pidl1 && pidl2 && !ILEmpty(pidl1) && !ILEmpty(pidl2)
  481. //
  482. HRESULT ILCompareRelIDs(IShellFolder *psfParent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  483. {
  484. HRESULT hres;
  485. LPCITEMIDLIST pidlRel1 = _ILNext(pidl1);
  486. LPCITEMIDLIST pidlRel2 = _ILNext(pidl2);
  487. if (ILIsEmpty(pidlRel1))
  488. {
  489. if (ILIsEmpty(pidlRel2)) {
  490. hres = 0;
  491. } else {
  492. hres = (HRESULT)-1;
  493. }
  494. }
  495. else
  496. {
  497. if (ILIsEmpty(pidlRel2))
  498. {
  499. hres = 1;
  500. }
  501. else
  502. {
  503. //
  504. // Neither pidlRel1 nor pidlRel2 is empty.
  505. // (1) Bind to the next level of the IShellFolder
  506. // (2) Call its CompareIDs to let it compare the rest of IDs.
  507. //
  508. // Notes: We should create pidlNext not from pidl2 but from pidl1
  509. // because fstreex.c may pass simple pidl2.
  510. //
  511. LPITEMIDLIST pidlNext = ILClone(pidl1);
  512. if (pidlNext)
  513. {
  514. IShellFolder *psfNext;
  515. _ILNext(pidlNext)->mkid.cb = 0;
  516. hres = psfParent->lpVtbl->BindToObject(psfParent, pidlNext, NULL,
  517. &IID_IShellFolder, &psfNext);
  518. if (SUCCEEDED(hres))
  519. {
  520. hres = psfNext->lpVtbl->CompareIDs(psfNext, 0, pidlRel1, pidlRel2);
  521. psfNext->lpVtbl->Release(psfNext);
  522. }
  523. ILFree(pidlNext);
  524. }
  525. else
  526. {
  527. hres = E_OUTOFMEMORY;
  528. }
  529. }
  530. }
  531. return hres;
  532. }
  533. void StrRetFormat(LPSTRRET pStrRet, LPCITEMIDLIST pidlRel, LPCSTR pszTemplate, LPCSTR pszAppend)
  534. {
  535. LPSTR pszRet;
  536. char szT[MAX_PATH];
  537. StrRetToStrN(szT, sizeof(szT), pStrRet, pidlRel);
  538. pszRet = ShellConstructMessageString(HINST_THISDLL, pszTemplate, pszAppend, szT);
  539. if (pszRet)
  540. {
  541. pStrRet->uType = STRRET_CSTR;
  542. lstrcpyn(pStrRet->cStr, pszRet, sizeof(pStrRet->cStr));
  543. Free(pszRet);
  544. }
  545. }
  546. //
  547. // Notes: This one passes SHGDN_FORMARSING to ISF::GetDisplayNameOf.
  548. //
  549. HRESULT ILGetRelDisplayName(IShellFolder *psf, LPSTRRET pStrRet,
  550. LPCITEMIDLIST pidlRel, LPCSTR pszName,
  551. LPCSTR pszTemplate)
  552. {
  553. HRESULT hres;
  554. LPITEMIDLIST pidlLeft = ILCloneFirst(pidlRel);
  555. if (pidlLeft)
  556. {
  557. IShellFolder *psfNext;
  558. hres = psf->lpVtbl->BindToObject(psf, pidlLeft, NULL,
  559. &IID_IShellFolder, &psfNext);
  560. if (SUCCEEDED(hres))
  561. {
  562. LPCITEMIDLIST pidlRight = _ILNext(pidlRel);
  563. hres = psfNext->lpVtbl->GetDisplayNameOf(psfNext, pidlRight, SHGDN_INFOLDER|SHGDN_FORPARSING, pStrRet);
  564. if (SUCCEEDED(hres))
  565. {
  566. if (pszTemplate)
  567. {
  568. StrRetFormat(pStrRet, pidlRight, pszTemplate, pszName);
  569. }
  570. else
  571. {
  572. hres = StrRetCatLeft(pszName, pStrRet, pidlRight);
  573. }
  574. }
  575. psfNext->lpVtbl->Release(psfNext);
  576. }
  577. ILFree(pidlLeft);
  578. }
  579. else
  580. {
  581. hres = E_OUTOFMEMORY;
  582. }
  583. return hres;
  584. }
  585. LPITEMIDLIST ILAppendID(LPITEMIDLIST pidl, LPCSHITEMID pmkid, BOOL fAppend)
  586. {
  587. UINT cbUsed, cbRequired;
  588. // Create the ID list, if it is not given.
  589. if (!pidl)
  590. {
  591. pidl = ILCreate();
  592. if (!pidl)
  593. return NULL; // memory overflow
  594. }
  595. cbUsed = ILGetSize(pidl);
  596. cbRequired = cbUsed + pmkid->cb;
  597. pidl = _ILResize(pidl, cbRequired, CBIDL_INCL);
  598. if (!pidl)
  599. return NULL; // memory overflow
  600. if (fAppend)
  601. {
  602. // Append it.
  603. CopyMemory(_ILSkip(pidl, cbUsed-sizeof(pidl->mkid.cb)), pmkid, pmkid->cb);
  604. }
  605. else
  606. {
  607. // Put it at the top
  608. MoveMemory(_ILSkip(pidl, pmkid->cb), pidl, cbUsed);
  609. CopyMemory(pidl, pmkid, pmkid->cb);
  610. Assert(ILGetSize(_ILNext(pidl))==cbUsed);
  611. }
  612. // We must put zero-terminator because of LMEM_ZEROINIT.
  613. _ILSkip(pidl, cbRequired-sizeof(pidl->mkid.cb))->mkid.cb = 0;
  614. Assert(ILGetSize(pidl) == cbRequired);
  615. return pidl;
  616. }
  617. BOOL ILGetDisplayName(LPCITEMIDLIST pidl, LPSTR pszPath)
  618. {
  619. BOOL fSuccess = FALSE; // assume error
  620. STRRET srName;
  621. IShellFolder *psfDesktop;
  622. SHGetDesktopFolder(&psfDesktop);
  623. VALIDATE_PIDL(pidl);
  624. if (SUCCEEDED(psfDesktop->lpVtbl->GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &srName)))
  625. {
  626. StrRetToStrN(pszPath, MAX_PATH, &srName, pidl);
  627. fSuccess = TRUE;
  628. }
  629. return fSuccess;
  630. }
  631. #endif // not used