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.

542 lines
11 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: P I D L U T I L . C P P
  7. //
  8. // Contents: PIDL utility routines. This stuff is mainly copied from the
  9. // existing Namespace extension samples and real code, since
  10. // everyone and their gramma uses this stuff.
  11. //
  12. // Notes:
  13. //
  14. // Author: jeffspr 1 Oct 1997
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "pch.h"
  18. #pragma hdrstop
  19. #include "pidlutil.h"
  20. #if DBG
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Function: ILNext
  24. //
  25. // Purpose: Return the next PIDL in the list
  26. //
  27. // Arguments:
  28. // pidl []
  29. //
  30. // Returns:
  31. //
  32. // Author: jeffspr 1 Oct 1997 (from brianwen)
  33. //
  34. // Notes:
  35. //
  36. LPITEMIDLIST ILNext(LPCITEMIDLIST pidl)
  37. {
  38. if (pidl)
  39. {
  40. pidl = (LPITEMIDLIST) ((BYTE *)pidl + pidl->mkid.cb);
  41. }
  42. return (LPITEMIDLIST)pidl;
  43. }
  44. //+---------------------------------------------------------------------------
  45. //
  46. // Function: ILIsEmpty
  47. //
  48. // Purpose: Is this PIDL empty
  49. //
  50. // Arguments:
  51. // pidl []
  52. //
  53. // Returns:
  54. //
  55. // Author: jeffspr 1 Oct 1997 (from brianwen)
  56. //
  57. // Notes:
  58. //
  59. BOOL ILIsEmpty(LPCITEMIDLIST pidl)
  60. {
  61. return (!pidl || !pidl->mkid.cb);
  62. }
  63. #endif // #if DBG
  64. //+---------------------------------------------------------------------------
  65. //
  66. // Function: ILSkip
  67. //
  68. // Purpose: Skip to an offset
  69. //
  70. // Arguments:
  71. // pidl The input pidl
  72. // cb Offset to skip to
  73. //
  74. // Returns:
  75. //
  76. // Author: tongl 2/16/00 (from raymondc)
  77. //
  78. // Notes:
  79. //
  80. LPITEMIDLIST ILSkip(LPCITEMIDLIST pidl, UINT cb)
  81. {
  82. return const_cast<LPITEMIDLIST>
  83. (reinterpret_cast<LPCITEMIDLIST>
  84. (reinterpret_cast<const BYTE *>(pidl) + cb));
  85. }
  86. //+---------------------------------------------------------------------------
  87. //
  88. // Function: ILGetSizePriv
  89. //
  90. // Purpose: Return the size of a pidl.
  91. //
  92. // Arguments:
  93. // pidl []
  94. //
  95. // Returns:
  96. //
  97. // Author: jeffspr 1 Oct 1997 (from brianwen)
  98. //
  99. // Notes:
  100. //
  101. UINT ILGetSizePriv(LPCITEMIDLIST pidl)
  102. {
  103. UINT cbTotal = 0;
  104. if (pidl)
  105. {
  106. cbTotal += sizeof(pidl->mkid.cb); // Null terminator
  107. while (pidl->mkid.cb)
  108. {
  109. cbTotal += pidl->mkid.cb;
  110. pidl = ILNext(pidl);
  111. }
  112. }
  113. return cbTotal;
  114. }
  115. VOID FreeIDL(LPITEMIDLIST pidl)
  116. {
  117. Assert(pidl);
  118. SHFree(pidl);
  119. }
  120. //+---------------------------------------------------------------------------
  121. //
  122. // Function: ILIsSingleID
  123. //
  124. // Purpose: Returns TRUE if the idlist has just one ID in it.
  125. //
  126. // Arguments:
  127. // pidl []
  128. //
  129. // Returns:
  130. //
  131. // Author: jeffspr 1 Oct 1997 (from brianwen)
  132. //
  133. // Notes:
  134. //
  135. BOOL ILIsSingleID(LPCITEMIDLIST pidl)
  136. {
  137. if (pidl == NULL)
  138. return FALSE;
  139. return (pidl->mkid.cb == 0 || ILNext(pidl)->mkid.cb == 0);
  140. }
  141. //+---------------------------------------------------------------------------
  142. //
  143. // Function: ILGetCID
  144. //
  145. // Purpose: Returns the number of ID's in the list.
  146. //
  147. // Arguments:
  148. // pidl []
  149. //
  150. // Returns:
  151. //
  152. // Author: jeffspr 1 Oct 1997 (from brianwen)
  153. //
  154. // Notes:
  155. //
  156. UINT ILGetCID(LPCITEMIDLIST pidl)
  157. {
  158. UINT cid = 0;
  159. while (!ILIsEmpty(pidl))
  160. {
  161. ++ cid;
  162. pidl = ILNext(pidl);
  163. }
  164. return cid;
  165. }
  166. //+---------------------------------------------------------------------------
  167. //
  168. // Function: ILGetSizeCID
  169. //
  170. // Purpose: Get the length of the first cid items in a pidl.
  171. //
  172. // Arguments:
  173. // pidl []
  174. // cid []
  175. //
  176. // Returns:
  177. //
  178. // Author: jeffspr 1 Oct 1997 (from brianwen)
  179. //
  180. // Notes:
  181. //
  182. UINT ILGetSizeCID(LPCITEMIDLIST pidl, UINT cid)
  183. {
  184. UINT cbTotal = 0;
  185. if (pidl)
  186. {
  187. cbTotal += sizeof(pidl->mkid.cb); // Null terminator
  188. while (cid && !ILIsEmpty(pidl))
  189. {
  190. cbTotal += pidl->mkid.cb;
  191. pidl = ILNext(pidl);
  192. -- cid;
  193. }
  194. }
  195. return cbTotal;
  196. }
  197. //+---------------------------------------------------------------------------
  198. //
  199. // Function: CloneIDL
  200. //
  201. // Purpose: Clone an IDL (return a duplicate)
  202. //
  203. // Arguments:
  204. // pidl []
  205. //
  206. // Returns:
  207. //
  208. // Author: jeffspr 1 Oct 1997 (from brianwen)
  209. //
  210. // Notes:
  211. //
  212. LPITEMIDLIST CloneIDL(LPCITEMIDLIST pidl)
  213. {
  214. UINT cb = 0;
  215. LPITEMIDLIST pidlRet = NULL;
  216. if (pidl)
  217. {
  218. cb = ILGetSizePriv(pidl);
  219. pidlRet = (LPITEMIDLIST) SHAlloc(cb);
  220. if (pidlRet)
  221. {
  222. memcpy(pidlRet, pidl, cb);
  223. }
  224. }
  225. return pidlRet;
  226. }
  227. //+---------------------------------------------------------------------------
  228. //
  229. // Function: ILCreate
  230. //
  231. // Purpose: Create a PIDL
  232. //
  233. // Arguments:
  234. // cbSize []
  235. //
  236. // Returns:
  237. //
  238. // Author: jeffspr 1 Oct 1997 (from brianwen)
  239. //
  240. // Notes:
  241. //
  242. LPITEMIDLIST ILCreate(DWORD dwSize)
  243. {
  244. LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(dwSize);
  245. return pidl;
  246. }
  247. //+---------------------------------------------------------------------------
  248. //
  249. // Function: ILCombinePriv
  250. //
  251. // Purpose: Combine two PIDLs
  252. //
  253. // Arguments:
  254. // pidl1 []
  255. // pidl2 []
  256. //
  257. // Returns:
  258. //
  259. // Author: jeffspr 1 Oct 1997 (from brianwen)
  260. //
  261. // Notes:
  262. //
  263. LPITEMIDLIST ILCombinePriv(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  264. {
  265. LPITEMIDLIST pidlNew = NULL;
  266. // Let me pass in NULL pointers
  267. if (!pidl1)
  268. {
  269. if (!pidl2)
  270. {
  271. pidlNew = NULL;
  272. }
  273. else
  274. {
  275. pidlNew = CloneIDL(pidl2);
  276. }
  277. }
  278. else
  279. {
  280. if (!pidl2)
  281. {
  282. pidlNew = CloneIDL(pidl1);
  283. }
  284. else
  285. {
  286. UINT cb1 = ILGetSizePriv(pidl1) - sizeof(pidl1->mkid.cb);
  287. UINT cb2 = ILGetSizePriv(pidl2);
  288. pidlNew = ILCreate(cb1 + cb2);
  289. if (pidlNew)
  290. {
  291. memcpy(pidlNew, pidl1, cb1);
  292. memcpy((PWSTR)(((LPBYTE)pidlNew) + cb1), pidl2, cb2);
  293. Assert (ILGetSizePriv(pidlNew) == cb1+cb2);
  294. }
  295. }
  296. }
  297. return pidlNew;
  298. }
  299. //+---------------------------------------------------------------------------
  300. //
  301. // Function: ILFindLastIDPriv
  302. //
  303. // Purpose: Find the last ID in an IDL
  304. //
  305. // Arguments:
  306. // pidl []
  307. //
  308. // Returns:
  309. //
  310. // Author: jeffspr 1 Oct 1997 (from brianwen)
  311. //
  312. // Notes:
  313. //
  314. LPITEMIDLIST ILFindLastIDPriv(LPCITEMIDLIST pidl)
  315. {
  316. LPCITEMIDLIST pidlLast = pidl;
  317. LPCITEMIDLIST pidlNext = pidl;
  318. Assert(pidl);
  319. // Find the last one in the list
  320. //
  321. while (pidlNext->mkid.cb)
  322. {
  323. pidlLast = pidlNext;
  324. pidlNext = ILNext(pidlLast);
  325. }
  326. return (LPITEMIDLIST)pidlLast;
  327. }
  328. //+---------------------------------------------------------------------------
  329. //
  330. // Function: ILRemoveLastIDPriv
  331. //
  332. // Purpose: Remove the last ID from an IDL
  333. //
  334. // Arguments:
  335. // pidl []
  336. //
  337. // Returns:
  338. //
  339. // Author: jeffspr 1 Oct 1997
  340. //
  341. // Notes:
  342. //
  343. BOOL ILRemoveLastIDPriv(LPITEMIDLIST pidl)
  344. {
  345. BOOL fRemoved = FALSE;
  346. Assert(pidl);
  347. if (pidl->mkid.cb)
  348. {
  349. LPITEMIDLIST pidlLast = (LPITEMIDLIST)ILFindLastIDPriv(pidl);
  350. Assert(pidlLast->mkid.cb);
  351. Assert(ILNext(pidlLast)->mkid.cb==0);
  352. // Remove the last one
  353. pidlLast->mkid.cb = 0; // null-terminator
  354. fRemoved = TRUE;
  355. }
  356. return fRemoved;
  357. }
  358. //+---------------------------------------------------------------------------
  359. //
  360. // Function: HrCloneRgIDL
  361. //
  362. // Purpose: Clone a pidl array
  363. //
  364. // Arguments:
  365. // rgpidl [in] PIDL array to clone
  366. // cidl [in] Count of the pidl array
  367. // pppidl [out] Return pointer for pidl array
  368. //
  369. // Returns:
  370. //
  371. // Author: jeffspr 22 Oct 1997
  372. //
  373. // Notes:
  374. //
  375. HRESULT HrCloneRgIDL(
  376. LPCITEMIDLIST * rgpidl,
  377. ULONG cidl,
  378. LPITEMIDLIST ** pppidl,
  379. ULONG * pcidl)
  380. {
  381. HRESULT hr = NOERROR;
  382. LPITEMIDLIST * rgpidlReturn = NULL;
  383. ULONG irg = 0;
  384. ULONG cidlCopied = 0;
  385. Assert(pppidl);
  386. Assert(pcidl);
  387. Assert(rgpidl);
  388. if (!rgpidl || !cidl)
  389. {
  390. hr = E_INVALIDARG;
  391. goto Exit;
  392. }
  393. else
  394. {
  395. // Alloc the return buffer
  396. //
  397. rgpidlReturn = (LPITEMIDLIST *) SHAlloc(cidl * sizeof(LPITEMIDLIST));
  398. if (!rgpidlReturn)
  399. {
  400. hr = E_OUTOFMEMORY;
  401. goto Exit;
  402. }
  403. else
  404. {
  405. // Clone all elements within the passed in PIDL array
  406. //
  407. for (irg = 0; irg < cidl; irg++)
  408. {
  409. if (rgpidl[irg])
  410. {
  411. // Clone this element in the PIDL array
  412. //
  413. rgpidlReturn[cidlCopied++] = CloneIDL ((LPITEMIDLIST) rgpidl[irg]);
  414. if (!rgpidlReturn[irg])
  415. {
  416. hr = E_OUTOFMEMORY;
  417. goto Exit;
  418. }
  419. }
  420. else
  421. {
  422. // Make sure that we don't try to delete bogus data later.
  423. //
  424. rgpidlReturn[cidlCopied++] = NULL;
  425. AssertSz(FALSE, "Bogus element in the rgpidl in HrCloneRgIDL");
  426. hr = E_INVALIDARG;
  427. goto Exit;
  428. }
  429. }
  430. }
  431. }
  432. Exit:
  433. if (FAILED(hr))
  434. {
  435. // Free the already-allocated IDLISTs
  436. //
  437. ULONG irgT = 0;
  438. for (irgT = 0; irgT < irg; irgT++)
  439. {
  440. if (rgpidlReturn[irgT])
  441. {
  442. FreeIDL(rgpidlReturn[irgT]);
  443. }
  444. }
  445. SHFree(rgpidlReturn);
  446. *pppidl = NULL;
  447. }
  448. else
  449. {
  450. // Fill in the return var.
  451. //
  452. *pppidl = rgpidlReturn;
  453. *pcidl = cidlCopied;
  454. }
  455. TraceHr(ttidError, FAL, hr, FALSE, "HrCloneRgIDL");
  456. return hr;
  457. } // HrCloneRgIDL
  458. //+---------------------------------------------------------------------------
  459. //
  460. // Function: FreeRgIDL
  461. //
  462. // Purpose: Free a PIDL array
  463. //
  464. // Arguments:
  465. // cidl [in] Size of PIDL array
  466. // apidl [in] Pointer to the array itself.
  467. //
  468. // Returns:
  469. //
  470. // Author: jeffspr 27 Oct 1997
  471. //
  472. // Notes:
  473. //
  474. VOID FreeRgIDL(
  475. UINT cidl,
  476. LPITEMIDLIST * apidl)
  477. {
  478. if (apidl)
  479. {
  480. for (UINT i = 0; i < cidl; i++)
  481. {
  482. FreeIDL(apidl[i]);
  483. }
  484. SHFree(apidl);
  485. }
  486. }