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.

2400 lines
59 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // UserDef.c
  4. //
  5. // MS Office User Defined Property Information
  6. //
  7. // Notes:
  8. // To make this file useful for OLE objects, define OLE_PROPS.
  9. //
  10. // The macro lpDocObj must be used for all methods to access the
  11. // object data to ensure that this will compile with OLE_PROPS defined.
  12. //
  13. // Data structures:
  14. // The dictionary is stored internally as a map, mapping PIDs
  15. // to the string names.
  16. //
  17. // The properties themselves are stored internally as a linked list
  18. //
  19. // Change history:
  20. //
  21. // Date Who What
  22. // --------------------------------------------------------------------------
  23. // 06/27/94 B. Wentz Created file
  24. // 07/03/94 B. Wentz Added Iterator support
  25. // 07/20/94 M. Jansson Updated include statements, due to changes in PDK
  26. // 07/26/94 B. Wentz Changed Load & Save to use Document Summary stream
  27. // 07/08/96 MikeHill Ignore UserDef properties that aren't UDTYPEs.
  28. //
  29. ////////////////////////////////////////////////////////////////////////////////
  30. #include "priv.h"
  31. #pragma hdrstop
  32. static void PASCAL RemoveFromList (LPUDOBJ lpUDObj, LPUDPROP lpudprop);
  33. static void PASCAL DeallocNode (LPUDOBJ lpUDObj, LPUDPROP lpudp);
  34. static void PASCAL VUdpropFreeString (LPUDPROP lpudp, BOOL fName);
  35. static BOOL PASCAL FUdpropUpdate (LPUDPROP lpudp, LPUDOBJ lpUDObj, LPTSTR lpszPropName, LPTSTR lpszLinkMonik, LPVOID lpvValue, UDTYPES udtype, BOOL fLink);
  36. static BOOL PASCAL FUdpropSetString (LPUDPROP lpudp, LPTSTR lptstr, BOOL fLimitLength, BOOL fName);
  37. static BOOL PASCAL FUdpropMakeVisible (LPUDPROP lpudprop);
  38. static BOOL PASCAL FUserDefMakeHidden (LPUDOBJ lpUDObj, LPTSTR lpsz);
  39. static BOOL PASCAL FUdpropMakeHidden (LPUDPROP lpudprop);
  40. #define lpDocObj (lpUDObj)
  41. #define lpData ((LPUDINFO) lpUDObj->m_lpData)
  42. ////////////////////////////////////////////////////////////////////////////////
  43. //
  44. // OfficeDirtyUDObj
  45. //
  46. // Purpose:
  47. // Sets object state to dirty or clean.
  48. //
  49. ////////////////////////////////////////////////////////////////////////////////
  50. DLLEXPORT VOID OfficeDirtyUDObj
  51. (LPUDOBJ lpUDObj, // The object
  52. BOOL fDirty) // Flag indicating if the object is dirty.
  53. {
  54. Assert(lpUDObj != NULL);
  55. lpUDObj->m_fObjChanged = fDirty;
  56. } // OfficeDirtyUDObj
  57. ////////////////////////////////////////////////////////////////////////////////
  58. //
  59. // FreeUDData
  60. //
  61. // Purpose:
  62. // Deallocates all the member data for the object
  63. //
  64. // Note:
  65. // Assumes object is valid.
  66. //
  67. ////////////////////////////////////////////////////////////////////////////////
  68. void PASCAL
  69. FreeUDData
  70. (LPUDOBJ lpUDObj, // Pointer to valid object
  71. BOOL fTmp) // Indicates tmp data should be freed
  72. {
  73. LPUDPROP lpudp;
  74. LPUDPROP lpudpT;
  75. lpudp = (fTmp) ? lpData->lpudpTmpHead : lpData->lpudpHead;
  76. while (lpudp != NULL)
  77. {
  78. lpudpT = lpudp;
  79. lpudp = (LPUDPROP) lpudp->llist.lpllistNext;
  80. VUdpropFree(&lpudpT);
  81. }
  82. if (fTmp)
  83. {
  84. lpData->lpudpTmpCache = NULL;
  85. lpData->lpudpTmpHead = NULL;
  86. lpData->dwcTmpProps = 0;
  87. lpData->dwcTmpLinks = 0;
  88. }
  89. else
  90. {
  91. lpData->lpudpCache = NULL;
  92. lpData->lpudpHead = NULL;
  93. lpData->dwcProps = 0;
  94. lpData->dwcLinks = 0;
  95. }
  96. } // FreeUDData
  97. ////////////////////////////////////////////////////////////////////////////////
  98. //
  99. // FUserDefCreate
  100. //
  101. // Purpose:
  102. // Create a User-defined property exchange object.
  103. //
  104. ////////////////////////////////////////////////////////////////////////////////
  105. BOOL
  106. FUserDefCreate
  107. (LPUDOBJ FAR *lplpUDObj, // Pointer to pointer to object
  108. void *prglpfn[]) // Pointer to functions
  109. {
  110. LPUDOBJ lpUDObj; // Hack - a temp, must call it "lpUdObj" for macros to work!
  111. if (lplpUDObj == NULL)
  112. return(TRUE);
  113. // Make sure we get valid args before we start alloc'ing
  114. if ((prglpfn == NULL) || (prglpfn[ifnCPConvert] == NULL) ||
  115. ((prglpfn[ifnFSzToNum] == NULL) && (prglpfn[ifnFNumToSz] != NULL)) ||
  116. ((prglpfn[ifnFSzToNum] != NULL) && (prglpfn[ifnFNumToSz] == NULL))
  117. )
  118. {
  119. return FALSE;
  120. }
  121. if ((*lplpUDObj = PvMemAlloc(sizeof(USERPROP))) == NULL)
  122. {
  123. // REVIEW: Add alert
  124. return FALSE;
  125. }
  126. lpDocObj = *lplpUDObj;
  127. //
  128. // If alloc fails, free the original object too.
  129. //
  130. if ((lpData = PvMemAlloc(sizeof (UDINFO))) == NULL)
  131. {
  132. //
  133. // REVIEW: Add alert
  134. //
  135. VFreeMemP(*lplpUDObj, sizeof(USERPROP));
  136. return FALSE;
  137. }
  138. FillBuf ((void *) lpData, (int) 0, sizeof(UDINFO) );
  139. //
  140. // Save the fnc's for code page convert, SzToNum, NumToSz
  141. //
  142. lpData->lpfnFCPConvert = (BOOL (*)(LPTSTR, DWORD, DWORD, BOOL)) prglpfn[ifnCPConvert];
  143. lpData->lpfnFSzToNum = (BOOL (*)(NUM *, LPTSTR)) prglpfn[ifnFSzToNum];
  144. lpData->lpfnFNumToSz = (BOOL (*)(NUM *, LPTSTR, DWORD)) prglpfn[ifnFNumToSz];
  145. OfficeDirtyUDObj (*lplpUDObj, FALSE);
  146. (*lplpUDObj)->m_hPage = NULL;
  147. return TRUE;
  148. } // FUserDefCreate
  149. ////////////////////////////////////////////////////////////////////////////////
  150. //
  151. // FUserDefDestroy
  152. //
  153. // Purpose:
  154. // Destroy a User-defined property exchange object.
  155. //
  156. ////////////////////////////////////////////////////////////////////////////////
  157. BOOL
  158. FUserDefDestroy
  159. (LPUDOBJ FAR *lplpUDObj) // Pointer to pointer to object
  160. {
  161. #define lpUDData ((LPUDINFO)(((LPUDOBJ) *lplpUDObj)->m_lpData))
  162. DWORD irg;
  163. if ((lplpUDObj == NULL) || (*lplpUDObj == NULL))
  164. return TRUE;
  165. if (lpUDData != NULL)
  166. {
  167. FreeUDData (*lplpUDObj, FALSE);
  168. FreeUDData (*lplpUDObj, TRUE);
  169. //
  170. // Invalidate any OLE Automation DocumentProperty objects we might have
  171. //
  172. InvalidateVBAObjects(NULL, NULL, *lplpUDObj);
  173. VFreeMemP((*lplpUDObj)->m_lpData, sizeof(UDINFO));
  174. }
  175. VFreeMemP(*lplpUDObj, sizeof(USERPROP));
  176. *lplpUDObj = NULL;
  177. return TRUE;
  178. #undef lpUDData
  179. } // FUserDefDestroy
  180. ////////////////////////////////////////////////////////////////////////////////
  181. //
  182. // FUserDefClear
  183. //
  184. // Purpose:
  185. // Clears a User-defined property object without destroying it. All stored
  186. // data is lost.
  187. //
  188. ////////////////////////////////////////////////////////////////////////////////
  189. BOOL
  190. FUserDefClear(LPUDOBJ lpUDObj) // Pointer to object
  191. {
  192. if ((lpDocObj == NULL) || (lpData == NULL))
  193. return TRUE;
  194. FreeUDData (lpDocObj, FALSE);
  195. FreeUDData (lpDocObj, TRUE);
  196. //
  197. // Invalidate any OLE Automation DocumentProperty objects we might have
  198. //
  199. InvalidateVBAObjects(NULL, NULL, lpUDObj);
  200. //
  201. // Clear the data, don't blt over the fn's stored at the end.
  202. //
  203. FillBuf ((void *) lpData, (int) 0, (sizeof (UDINFO) - ifnUDMax*(sizeof (void *))));
  204. OfficeDirtyUDObj (lpUDObj, TRUE);
  205. return TRUE;
  206. } // FUserDefClear
  207. ////////////////////////////////////////////////////////////////////////////////
  208. //
  209. // FUserDefShouldSave
  210. //
  211. // Purpose:
  212. // Indicates if the data has changed, meaning a write is needed.
  213. //
  214. ////////////////////////////////////////////////////////////////////////////////
  215. DLLEXPORT BOOL
  216. FUserDefShouldSave
  217. (LPUDOBJ lpUDObj) // Pointer to object
  218. {
  219. if (lpUDObj == NULL)
  220. return FALSE;
  221. return lpDocObj->m_fObjChanged;
  222. } // FUserDefShouldSave
  223. ////////////////////////////////////////////////////////////////////////////////
  224. //
  225. // UdtypesUserDefType
  226. //
  227. // Purpose:
  228. // Returns the type of the given Property Value from the string
  229. //
  230. // Returns wUDInvalid on error
  231. //
  232. ////////////////////////////////////////////////////////////////////////////////
  233. DLLEXPORT UDTYPES
  234. UdtypesUserDefType
  235. (LPUDOBJ lpUDObj,
  236. LPTSTR lpsz)
  237. {
  238. LPUDPROP lpudprop;
  239. if ((lpUDObj == NULL) ||
  240. (lpData == NULL) ||
  241. (lpsz == NULL)
  242. )
  243. {
  244. return wUDinvalid;
  245. }
  246. //
  247. // Find the node that has this name.
  248. //
  249. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  250. if (lpudprop == NULL || lpudprop->lppropvar == NULL)
  251. return wUDinvalid;
  252. // Return the VarType (which is a UDTYPE)
  253. return (lpudprop->lppropvar->vt);
  254. } // UdtypesUserDefType
  255. ////////////////////////////////////////////////////////////////////////////////
  256. //
  257. // LpvoidUserDefGetPropVal
  258. //
  259. // Purpose:
  260. // This will return the Property Value for the given Property String.
  261. //
  262. ////////////////////////////////////////////////////////////////////////////////
  263. DLLEXPORT LPVOID
  264. LpvoidUserDefGetPropVal
  265. (LPUDOBJ lpUDObj, // Pointer to object
  266. LPTSTR lpszProp, // Property string
  267. DWORD cbMax, // Size of lpv
  268. LPVOID lpv, // Buffer for prop val
  269. DWORD dwMask, // Mask for what value is needed
  270. BOOL *pfLink, // Indicates a link
  271. BOOL *pfLinkInvalid) // Is the link invalid
  272. {
  273. LPUDPROP lpudprop;
  274. if ((lpUDObj == NULL) ||
  275. (lpData == NULL) ||
  276. (lpszProp == NULL) ||
  277. (cbMax == 0 && lpv != NULL) ||
  278. (pfLink == NULL) ||
  279. (pfLinkInvalid == NULL) ||
  280. ((lpv == NULL) && (!(dwMask & UD_PTRWIZARD)))
  281. )
  282. {
  283. return NULL;
  284. }
  285. //
  286. // Find the node that has this name.
  287. //
  288. lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
  289. if (lpudprop == NULL)
  290. return NULL;
  291. Assert (lpudprop->lppropvar != NULL);
  292. *pfLink = (lpudprop->lpstzLink != NULL);
  293. // Links are always invalid in the shell (there's no app to update the data).
  294. #ifdef SHELL
  295. *pfLinkInvalid = lpudprop->fLinkInvalid = TRUE;
  296. #else
  297. *pfLinkInvalid = lpudprop->fLinkInvalid;
  298. #endif
  299. //
  300. // Return based on the type and flags
  301. //
  302. if (dwMask & UD_LINK)
  303. {
  304. if (dwMask & UD_PTRWIZARD)
  305. {
  306. if (lpudprop->lpstzLink != NULL)
  307. return((LPVOID) (PSTR (lpudprop->lpstzLink)));
  308. return(NULL);
  309. }
  310. if (lpudprop->lpstzLink != NULL)
  311. {
  312. PbSzNCopy (lpv, lpudprop->lpstzLink, cbMax);
  313. return (lpv);
  314. }
  315. else
  316. return(NULL);
  317. }
  318. if (dwMask & UD_PTRWIZARD)
  319. {
  320. // If this is a string, return it's pointer from the
  321. // PropVariant. Otherwise, return a pointer into
  322. // the data of the PropVariant.
  323. return (lpudprop->lppropvar->vt == VT_LPTSTR) ?
  324. (LPVOID) lpudprop->lppropvar->pszVal :
  325. (LPVOID) &lpudprop->lppropvar->lVal;
  326. }
  327. // Copy the property from the PropVariant to the caller-provided
  328. // buffer.
  329. return( FPropVarCopyToBuf( lpudprop->lppropvar,
  330. cbMax,
  331. lpv
  332. ) ? lpv : NULL
  333. );
  334. } // LpvoidUserDefGetPropVal
  335. ////////////////////////////////////////////////////////////////////////////////
  336. //
  337. // LppropvarUserDefAddProp
  338. //
  339. // Purpose:
  340. // This will add a new Property to the set, with the given
  341. // Property string, type, and data.
  342. //
  343. ////////////////////////////////////////////////////////////////////////////////
  344. DLLEXPORT LPPROPVARIANT
  345. LppropvarUserDefAddProp
  346. (LPUDOBJ lpUDObj, // Pointer to object
  347. LPTSTR lpszPropName, // Property string
  348. LPVOID lpvVal, // Property value
  349. UDTYPES udtype, // Property type
  350. LPTSTR lpszLinkMonik, // Link name
  351. BOOL fLink, // Indicates the property is a link
  352. BOOL fHidden) // Indicates the property is hidden
  353. {
  354. LPUDPROP lpudprop;
  355. LPUDPROP lpudpropMatch;
  356. BOOL fCreated;
  357. if ((lpUDObj == NULL) ||
  358. (lpData == NULL) ||
  359. (lpszPropName == NULL) ||
  360. (*lpszPropName == 0) ||
  361. (lpvVal == NULL) ||
  362. (!ISUDTYPE(udtype)) ||
  363. (fLink && (lpszLinkMonik == NULL))
  364. )
  365. {
  366. return FALSE;
  367. }
  368. // Create a UDPROP to be added to the linked-list.
  369. lpudprop = LpudpropCreate();
  370. if (lpudprop == NULL)
  371. return FALSE;
  372. // Put the data into the UDPROP.
  373. if (!FUdpropUpdate( lpudprop,
  374. lpUDObj,
  375. lpszPropName,
  376. lpszLinkMonik,
  377. lpvVal,
  378. udtype,
  379. fLink)
  380. )
  381. {
  382. VUdpropFree (&lpudprop);
  383. return(FALSE);
  384. }
  385. //
  386. // Find this node
  387. //
  388. lpudpropMatch = LpudpropFindMatchingName (lpUDObj, lpszPropName);
  389. if (lpudpropMatch==NULL)
  390. {
  391. //
  392. // Create a node and put it in the list
  393. // If a new node was created, it must be added to the list...
  394. //
  395. if (fLink)
  396. lpData->dwcLinks++;
  397. lpData->dwcProps++;
  398. AddNodeToList (lpUDObj, lpudprop);
  399. } // if (lpudpropMatch==NULL)
  400. else
  401. {
  402. // We must replace the existing UDPROP with the new
  403. // value.
  404. // Free any existing property name and link name in this
  405. // UDPROP, and free its value.
  406. VUdpropFreeString (lpudpropMatch, TRUE);
  407. VUdpropFreeString (lpudpropMatch, FALSE);
  408. PropVariantClear (lpudpropMatch->lppropvar);
  409. CoTaskMemFree (lpudpropMatch->lppropvar);
  410. lpudpropMatch->lppropvar = NULL;
  411. // Put the linked-list pointer in the existing UDPROP into
  412. // the new UDPROP, then copy the new UDPROP back over
  413. // the matching PROP (this way, we don't have to
  414. // update the UDPROP that points to the match).
  415. lpudprop->llist=lpudpropMatch->llist;
  416. PbMemCopy(lpudpropMatch, lpudprop, sizeof(UDPROP));
  417. // Clear out the caller-provided UDPROP, free it, but
  418. // then set the pointer to the matching entry and clear
  419. // the match pointer. Thus, after we're done and whether
  420. // there was a match or not, lpudprop will point to the
  421. // correct UDPROP.
  422. FillBuf (lpudprop, 0, sizeof(UDPROP));
  423. VUdpropFree (&lpudprop);
  424. lpudprop = lpudpropMatch;
  425. lpudpropMatch = NULL;
  426. } // if (lpudpropMatch==NULL) ... else
  427. //
  428. // If the client asked for a hidden property, do it if
  429. // the name was the real name, not a link
  430. //
  431. if (fHidden && !fLink)
  432. {
  433. fCreated=FUserDefMakeHidden (lpUDObj, lpszPropName); // Should never return false
  434. Assert(fCreated);
  435. }
  436. OfficeDirtyUDObj (lpUDObj, TRUE);
  437. // If successful, return a pointer to the PropVariant with the value.
  438. if (lpudprop)
  439. return lpudprop->lppropvar;
  440. else
  441. return NULL;
  442. } // LppropvarUserDefAddProp
  443. ////////////////////////////////////////////////////////////////////////////////
  444. //
  445. // FUserDefDeleteProp
  446. //
  447. // Purpose:
  448. // This will delete a Property from the set given a Property string.
  449. //
  450. ////////////////////////////////////////////////////////////////////////////////
  451. DLLEXPORT BOOL
  452. FUserDefDeleteProp
  453. (LPUDOBJ lpUDObj, // Pointer to object
  454. LPTSTR lpsz) // String to delete
  455. {
  456. LPUDPROP lpudprop;
  457. if ((lpUDObj == NULL) ||
  458. (lpData == NULL) ||
  459. (lpsz == NULL))
  460. return FALSE;
  461. // Find the node
  462. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  463. if (lpudprop == NULL)
  464. return FALSE;
  465. lpData->dwcProps--;
  466. if (lpudprop->lpstzLink != NULL)
  467. lpData->dwcLinks--;
  468. RemoveFromList (lpUDObj, lpudprop);
  469. VUdpropFree (&lpudprop);
  470. OfficeDirtyUDObj (lpUDObj, TRUE);
  471. return TRUE;
  472. } // FUserDefDeleteProp
  473. ////////////////////////////////////////////////////////////////////////////////
  474. //
  475. // LpudiUserDefCreateIterator
  476. //
  477. // Purpose:
  478. // Create a User-defined Properties iterator
  479. //
  480. ////////////////////////////////////////////////////////////////////////////////
  481. DLLEXPORT LPUDITER
  482. LpudiUserDefCreateIterator
  483. (LPUDOBJ lpUDObj) // Pointer to object
  484. {
  485. LPUDITER lpudi;
  486. if ((lpUDObj == NULL) ||
  487. (lpData == NULL) ||
  488. (lpData->lpudpHead == NULL)) // No custom props
  489. return NULL;
  490. // Create & Init the iterator
  491. lpudi = PvMemAlloc(sizeof(UDITER));
  492. if (lpudi == NULL)
  493. return(NULL);
  494. FillBuf (lpudi, 0, sizeof (UDITER));
  495. lpudi->lpudp = lpData->lpudpHead;
  496. return lpudi;
  497. } // LpudiUserDefCreateIterator
  498. ////////////////////////////////////////////////////////////////////////////////
  499. //
  500. // FUserDefDestroyIterator
  501. //
  502. // Purpose:
  503. // Destroy a User-defined Properties iterator
  504. //
  505. ////////////////////////////////////////////////////////////////////////////////
  506. DLLEXPORT BOOL
  507. FUserDefDestroyIterator
  508. (LPUDITER *lplpUDIter) // Pointer to iterator
  509. {
  510. if ((lplpUDIter == NULL) || (*lplpUDIter == NULL))
  511. return TRUE;
  512. VFreeMemP(*lplpUDIter, sizeof(UDITER));
  513. *lplpUDIter = NULL;
  514. return TRUE;
  515. } // FUserDefDestroyIterator
  516. ////////////////////////////////////////////////////////////////////////////////
  517. //
  518. // FUserDefIteratorValid
  519. //
  520. // Purpose:
  521. // Determine if an iterator is still valid
  522. //
  523. ////////////////////////////////////////////////////////////////////////////////
  524. DLLEXPORT BOOL
  525. FUserDefIteratorValid
  526. (LPUDITER lpUDIter) // Pointer to iterator
  527. {
  528. if (lpUDIter == NULL)
  529. return FALSE;
  530. return (lpUDIter->lpudp != NULL);
  531. } // FUserDefIteratorValid
  532. ////////////////////////////////////////////////////////////////////////////////
  533. //
  534. // FUserDefIteratorNext
  535. //
  536. // Purpose:
  537. // Iterate to the next element
  538. //
  539. ////////////////////////////////////////////////////////////////////////////////
  540. DLLEXPORT BOOL
  541. FUserDefIteratorNext
  542. (LPUDITER lpUDIter) // Pointer to iterator
  543. {
  544. if (lpUDIter == NULL)
  545. return FALSE;
  546. // Move to the next node, if possible.
  547. #ifdef OLD
  548. if (lpUDIter->lpudp != NULL)
  549. lpUDIter->lpudp = (LPUDPROP) lpUDIter->lpudp->llist.lpllistNext;
  550. return TRUE;
  551. #endif
  552. if (lpUDIter->lpudp == NULL)
  553. return FALSE;
  554. lpUDIter->lpudp = (LPUDPROP) lpUDIter->lpudp->llist.lpllistNext;
  555. return(lpUDIter->lpudp != NULL);
  556. } // FUserDefIteratorNext
  557. ////////////////////////////////////////////////////////////////////////////////
  558. //
  559. // FUserDefIteratorIsLink
  560. //
  561. // Purpose:
  562. // Returns TRUE if the iterator is a link, FALSE otherwise
  563. //
  564. ////////////////////////////////////////////////////////////////////////////////
  565. DLLEXPORT BOOL
  566. FUserDefIteratorIsLink
  567. (LPUDITER lpUDIter) // Pointer to iterator
  568. {
  569. if ((lpUDIter == NULL) || (lpUDIter->lpudp == NULL))
  570. return FALSE;
  571. return(lpUDIter->lpudp->lpstzLink != NULL);
  572. } // FUserDefIteratorIsLink
  573. ////////////////////////////////////////////////////////////////////////////////
  574. //
  575. // FUserDefIteratorIsLinkInvalid
  576. //
  577. // Purpose:
  578. // Returns TRUE if the iterator is an invalid link, FALSE otherwise
  579. //
  580. ////////////////////////////////////////////////////////////////////////////////
  581. DLLEXPORT BOOL
  582. FUserDefIteratorIsLinkInvalid
  583. (LPUDITER lpUDIter) // Pointer to iterator
  584. {
  585. if ((lpUDIter == NULL) || (lpUDIter->lpudp == NULL))
  586. return(FALSE);
  587. if (lpUDIter->lpudp->lpstzLink == NULL)
  588. return(FALSE);
  589. return(lpUDIter->lpudp->fLinkInvalid);
  590. } // FUserDefIteratorIsLinkInvalid
  591. ////////////////////////////////////////////////////////////////////////////////
  592. //
  593. // UdtypesUserDefIteratorType
  594. //
  595. // Purpose:
  596. // Returns the type of the given Property Value from the iterator
  597. //
  598. ////////////////////////////////////////////////////////////////////////////////
  599. DLLEXPORT UDTYPES
  600. UdtypesUserDefIteratorType
  601. (LPUDITER lpUDIter) // Pointer to iterator
  602. {
  603. if ((lpUDIter == NULL) ||
  604. (lpUDIter->lpudp == NULL) ||
  605. (lpUDIter->lpudp->lppropvar == NULL))
  606. return wUDinvalid;
  607. return (lpUDIter->lpudp->lppropvar->vt);
  608. } // UdtypesUserDefIteratorType
  609. ////////////////////////////////////////////////////////////////////////////////
  610. //
  611. // LpvoidUserDefGetIteratorVal
  612. //
  613. // Purpose:
  614. // This will return the Property Value for the given iterator
  615. //
  616. ////////////////////////////////////////////////////////////////////////////////
  617. DLLEXPORT LPVOID
  618. LpvoidUserDefGetIteratorVal
  619. (LPUDITER lpUDIter, // Pointer to iterator
  620. DWORD cbMax, // Max size of lpv
  621. LPVOID lpv, // Buffer to copy data value to
  622. DWORD dwMask, // Mask indicating the value to get
  623. BOOL *pfLink, // Flag indicating the link is desired
  624. BOOL *pfLinkInvalid) // Flag indicating if the link is invalid
  625. {
  626. if ((cbMax == 0) ||
  627. ((lpv == NULL) && (!(dwMask & UD_PTRWIZARD))) ||
  628. (lpUDIter == NULL) ||
  629. (pfLink == NULL) ||
  630. (pfLinkInvalid == NULL) ||
  631. (lpUDIter->lpudp == NULL))
  632. return NULL;
  633. *pfLink = (lpUDIter->lpudp->lpstzLink != NULL);
  634. *pfLinkInvalid = lpUDIter->lpudp->fLinkInvalid;
  635. // Return based on the type and flags
  636. if (dwMask & UD_LINK)
  637. {
  638. if (dwMask & UD_PTRWIZARD)
  639. {
  640. if (lpUDIter->lpudp->lpstzLink != NULL)
  641. return((LPVOID) (PSTR (lpUDIter->lpudp->lpstzLink)));
  642. return(NULL);
  643. }
  644. if (lpUDIter->lpudp->lpstzLink != NULL)
  645. {
  646. PbSzNCopy (lpv, lpUDIter->lpudp->lpstzLink, cbMax);
  647. return (lpv);
  648. }
  649. else
  650. return(NULL);
  651. }
  652. if (dwMask & UD_PTRWIZARD)
  653. {
  654. Assert (lpUDIter->lpudp->lppropvar != NULL);
  655. Assert (lpUDIter->lpudp->lppropvar->vt == VT_LPTSTR
  656. ||
  657. lpUDIter->lpudp->lppropvar->vt == VT_INT_PTR);
  658. // If this is a string property, return a pointer to it.
  659. // Otherwise it is a Long/LongPtr, and we return its value.
  660. return ( lpUDIter->lpudp->lppropvar->vt == VT_LPTSTR
  661. ? (LPVOID) lpUDIter->lpudp->lppropvar->pszVal
  662. #ifdef _WIN64
  663. : (LPVOID) lpUDIter->lpudp->lppropvar->hVal.QuadPart
  664. #else
  665. : (LPVOID) lpUDIter->lpudp->lppropvar->lVal
  666. #endif
  667. );
  668. }
  669. // Copy the value of this property into a caller-provided buffer.
  670. return(FPropVarCopyToBuf(lpUDIter->lpudp->lppropvar, cbMax, lpv) ? lpv : NULL);
  671. } // LpvoidUserDefGetIteratorVal
  672. ////////////////////////////////////////////////////////////////////////////////
  673. //
  674. // LpszUserDefIteratorName
  675. //
  676. // Purpose:
  677. // This will return the Property String (name) for the property
  678. //
  679. ////////////////////////////////////////////////////////////////////////////////
  680. DLLEXPORT LPTSTR
  681. LpszUserDefIteratorName
  682. (LPUDITER lpUDIter, // Pointer to iterator
  683. DWORD cbMax, // Max size of lpsz
  684. LPTSTR lpsz) // Buffer to copy into, or UD_PTRWIZARD
  685. {
  686. if ((cbMax == 0) ||
  687. (lpsz == NULL) ||
  688. (lpUDIter == NULL) ||
  689. (lpUDIter->lpudp == NULL))
  690. {
  691. return NULL;
  692. }
  693. // If the lpsz input is not actually a pointer, but the
  694. // UD_PTRWIZARD value, then the caller doesn't want
  695. // us to copy the name into a buffer, they just want
  696. // us to return a pointer to the name.
  697. if ((INT_PTR) lpsz == UD_PTRWIZARD)
  698. {
  699. AssertSz ((IsBadReadPtr (lpsz, sizeof(LPTSTR))), TEXT("UD_PTRWIZARD should be a bogus pointer value!"));
  700. return (lpUDIter->lpudp->lpstzName);
  701. }
  702. // The caller gave us a real buffer in lpsz.
  703. // Copy the name into it, and return it.
  704. PbSzNCopy (lpsz, lpUDIter->lpudp->lpstzName, cbMax-1);
  705. lpsz[cbMax-1] = TEXT('\0');
  706. return lpsz;
  707. } // LpszUserDefIteratorName
  708. ////////////////////////////////////////////////////////////////////////////////
  709. //
  710. // FUserDefIteratorSetPropString
  711. //
  712. // Purpose:
  713. // Sets the name of the iterator.
  714. //
  715. ////////////////////////////////////////////////////////////////////////////////
  716. DLLFUNC BOOL OFC_CALLTYPE
  717. FUserDefIteratorSetPropString
  718. (LPUDOBJ lpUDObj, // Pointer to object
  719. LPUDITER lpUDIter, // Pointer to iterator
  720. LPTSTR lpszNew) // Pointer to new name
  721. {
  722. if ((lpUDObj == NULL) ||
  723. (lpData == NULL) ||
  724. (lpszNew == NULL) ||
  725. (lpUDIter == NULL) ||
  726. (lpUDIter->lpudp == NULL))
  727. return FALSE;
  728. // Update the node
  729. if (!FUdpropSetString (lpUDIter->lpudp, lpszNew, TRUE, TRUE))
  730. return FALSE;
  731. OfficeDirtyUDObj (lpUDObj, TRUE);
  732. return TRUE;
  733. } // FUserDefIteratorSetPropString
  734. ////////////////////////////////////////////////////////////////////////////////
  735. //
  736. // FUserDefIteratorChangeVal
  737. //
  738. // Purpose:
  739. // Changes the value of the data stored.
  740. //
  741. ////////////////////////////////////////////////////////////////////////////////
  742. DLLFUNC BOOL OFC_CALLTYPE
  743. FUserDefIteratorChangeVal
  744. (LPUDOBJ lpUDObj, // Pointer to object
  745. LPUDITER lpUDIter, // Pointer to iterator
  746. UDTYPES udtype, // The type
  747. LPVOID lpv, // New value.
  748. BOOL fLinkInvalid) // Is the link still valid?
  749. {
  750. if ((lpUDObj == NULL) ||
  751. (lpData == NULL) ||
  752. (lpUDIter == NULL) ||
  753. (!ISUDTYPE (udtype)) ||
  754. (lpUDIter->lpudp == NULL))
  755. return FALSE;
  756. if (fLinkInvalid)
  757. {
  758. if (lpUDIter->lpudp->lpstzLink == NULL)
  759. return FALSE;
  760. lpUDIter->lpudp->fLinkInvalid = TRUE;
  761. return TRUE;
  762. }
  763. else
  764. lpUDIter->lpudp->fLinkInvalid = FALSE;
  765. if (!FPropVarLoad (lpUDIter->lpudp->lppropvar, (VARTYPE)udtype, lpv))
  766. return FALSE;
  767. OfficeDirtyUDObj (lpUDObj, TRUE);
  768. return TRUE;
  769. } // FUserDefIteratorChangeVal
  770. ////////////////////////////////////////////////////////////////////////////////
  771. //
  772. // FUserDefIteratorSetLink
  773. //
  774. // Purpose:
  775. // Sets the link value for a property. This is NOT a public API.
  776. //
  777. ////////////////////////////////////////////////////////////////////////////////
  778. BOOL PASCAL
  779. FUserDefIteratorSetLink
  780. (LPUDOBJ lpUDObj, // Pointer to object
  781. LPUDITER lpUDIter, // Pointer to iterator
  782. LPTSTR lpszLink) // New link name
  783. {
  784. if ((lpUDObj == NULL) ||
  785. (lpData == NULL) ||
  786. (lpUDIter == NULL) ||
  787. (lpUDIter->lpudp == NULL))
  788. return FALSE;
  789. Assert(lpszLink != NULL);
  790. Assert(*lpszLink != TEXT('\0'));
  791. // Should already be a link
  792. Assert(lpUDIter->lpudp->lpstzLink != NULL);
  793. if (!FUdpropSetString (lpUDIter->lpudp, lpszLink, FALSE, FALSE))
  794. return FALSE;
  795. return TRUE;
  796. } // FUserDefIteratorSetLink
  797. ////////////////////////////////////////////////////////////////////////////////
  798. //
  799. // LpudiUserDefCreateIterFromLpudp
  800. //
  801. // Purpose:
  802. // Creates an iterator object from a node. This is not a public API.
  803. //
  804. ////////////////////////////////////////////////////////////////////////////////
  805. LPUDITER PASCAL
  806. LpudiUserDefCreateIterFromLpudp
  807. (LPUDOBJ lpUDObj, // Pointer to object
  808. LPUDPROP lpudp) // Pointer to node
  809. {
  810. LPUDITER lpudi;
  811. if ((lpUDObj == NULL) ||
  812. (lpData == NULL) ||
  813. (lpudp == NULL))
  814. return NULL;
  815. lpudi = LpudiUserDefCreateIterator (lpUDObj);
  816. if (lpudi != NULL)
  817. lpudi->lpudp = lpudp;
  818. return lpudi;
  819. } // LpudiUserDefCreateIterFromLpudp
  820. ////////////////////////////////////////////////////////////////////////////////
  821. //
  822. // FUserDefIsHidden
  823. //
  824. // Purpose:
  825. // Determine if a Property string is hidden.
  826. //
  827. ////////////////////////////////////////////////////////////////////////////////
  828. DLLEXPORT BOOL
  829. FUserDefIsHidden
  830. (LPUDOBJ lpUDObj, // Pointer to object
  831. LPTSTR lpsz) // Property string
  832. {
  833. if (lpsz == NULL)
  834. return FALSE;
  835. // We don't really need the object, we can tell from the name
  836. return (lpsz[0] == HIDDENPREFIX);
  837. } // FUserDefIsHidden
  838. ////////////////////////////////////////////////////////////////////////////////
  839. //
  840. // FUserDefMakeVisible
  841. //
  842. // Purpose:
  843. // Make a property visible based on the Property string
  844. //
  845. ////////////////////////////////////////////////////////////////////////////////
  846. DLLEXPORT BOOL
  847. FUserDefMakeVisible
  848. (LPUDOBJ lpUDObj, // Pointer to object
  849. LPTSTR lpsz) // String to hide.
  850. {
  851. LPUDPROP lpudprop;
  852. ULONG cb;
  853. if ((lpUDObj == NULL) ||
  854. (lpData == NULL) ||
  855. (lpsz == NULL))
  856. return FALSE;
  857. // Find the name
  858. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  859. if (lpudprop == NULL)
  860. return FALSE;
  861. if (!FUdpropMakeVisible (lpudprop))
  862. return FALSE;
  863. OfficeDirtyUDObj (lpUDObj, TRUE);
  864. return TRUE;
  865. } // FUserDefMakeVisible
  866. ////////////////////////////////////////////////////////////////////////////////
  867. //
  868. // FUserDefMakeHidden
  869. //
  870. // Purpose:
  871. // Hide a Property based on the Property string.
  872. //
  873. ////////////////////////////////////////////////////////////////////////////////
  874. static BOOL PASCAL
  875. FUserDefMakeHidden
  876. (LPUDOBJ lpUDObj, // Pointer to object
  877. LPTSTR lpsz) // String to hide
  878. {
  879. LPUDPROP lpudprop;
  880. LPTSTR lpstzT;
  881. if ((lpUDObj == NULL) ||
  882. (lpData == NULL) ||
  883. (lpsz == NULL))
  884. return FALSE;
  885. // Find the name
  886. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  887. if (lpudprop == NULL)
  888. return FALSE;
  889. if (!FUdpropMakeHidden (lpudprop))
  890. return FALSE;
  891. OfficeDirtyUDObj (lpUDObj, TRUE);
  892. return TRUE;
  893. } // FUserDefMakeHidden
  894. ////////////////////////////////////////////////////////////////////////////////
  895. //
  896. // LpudpropFindMatchingName
  897. //
  898. // Purpose:
  899. // Returns a node with a matching name, NULL otherwise.
  900. //
  901. ////////////////////////////////////////////////////////////////////////////////
  902. LPUDPROP PASCAL
  903. LpudpropFindMatchingName
  904. (LPUDOBJ lpUDObj, // Pointer to object
  905. LPTSTR lpsz) // String to search for
  906. {
  907. LPUDPROP lpudprop;
  908. TCHAR sz[256];
  909. BOOL fCopy = FALSE;
  910. if ((lpUDObj == NULL) || (lpData == NULL))
  911. return(NULL);
  912. if (CchTszLen(lpsz) > 255)
  913. {
  914. PbSzNCopy(sz, lpsz, 255);
  915. sz[255] = 0;
  916. fCopy = TRUE;
  917. }
  918. // Check the cache first
  919. if (lpData->lpudpCache != NULL)
  920. {
  921. Assert ((lpData->lpudpCache->lpstzName != NULL));
  922. // lstrcmpi returns 0 if 2 strings are equal.....
  923. if (!(lstrcmpi (fCopy ? sz : lpsz, (LPTSTR)PSTR (lpData->lpudpCache->lpstzName))))
  924. return lpData->lpudpCache;
  925. }
  926. lpudprop = lpData->lpudpHead;
  927. while (lpudprop != NULL)
  928. {
  929. Assert ((lpudprop->lpstzName != NULL));
  930. // lstrcmpi returns 0 if 2 strings are equal.....
  931. if (!(lstrcmpi (fCopy ? sz : lpsz, (LPTSTR)PSTR (lpudprop->lpstzName))))
  932. {
  933. // Set the cache to the last node found
  934. lpData->lpudpCache = lpudprop;
  935. return lpudprop;
  936. }
  937. lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
  938. } // while
  939. return NULL;
  940. } // LpudpropFindMatchingName
  941. ////////////////////////////////////////////////////////////////////////////////
  942. //
  943. // LpudpropFindMatchingPID
  944. //
  945. // Purpose:
  946. // Searches the linked-list in the caller-provided UDINFO structure
  947. // for a UDPROP with the requested PropID.
  948. //
  949. // Inputs:
  950. // LPUDOBJ - The UDINFO structure
  951. // PROPID - The PID to search for.
  952. //
  953. // Output:
  954. // The requested LPUDPROP, or NULL if not found.
  955. //
  956. ////////////////////////////////////////////////////////////////////////////////
  957. LPUDPROP PASCAL
  958. LpudpropFindMatchingPID
  959. (LPUDOBJ lpUDObj,
  960. PROPID propid)
  961. {
  962. // ------
  963. // Locals
  964. // ------
  965. LPUDPROP lpudprop = NULL;
  966. BOOL fCopy = FALSE;
  967. // -----
  968. // Begin
  969. // -----
  970. // Validate the inputs.
  971. if ((lpUDObj == NULL) || (lpData == NULL))
  972. {
  973. AssertSz (0, TEXT("Invalid inputs"));
  974. goto Exit;
  975. }
  976. // Check the cache first
  977. if (lpData->lpudpCache != NULL
  978. &&
  979. lpData->lpudpCache->propid == propid)
  980. {
  981. lpudprop = lpData->lpudpCache;
  982. goto Exit;
  983. }
  984. // Search the linked-list.
  985. lpudprop = lpData->lpudpHead;
  986. while (lpudprop != NULL)
  987. {
  988. if (lpudprop->propid == propid)
  989. {
  990. lpData->lpudpCache = lpudprop;
  991. goto Exit;
  992. }
  993. lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
  994. }
  995. // ----
  996. // Exit
  997. // ----
  998. Exit:
  999. return lpudprop;
  1000. } // LpudpropFindMatchingPID
  1001. ////////////////////////////////////////////////////////////////////////////////
  1002. //
  1003. // FAddPropToList
  1004. //
  1005. // Purpose:
  1006. // Adds the given object to the list. The type and value must
  1007. // be filled in before calling this.
  1008. //
  1009. // The linked-list we're adding to has one entry for each of
  1010. // the user-defined properties. Each entry has the property
  1011. // value, it's PID, and it's name. If the property is linked
  1012. // to document content, the link name (e.g. a Bookmark name
  1013. // in Word) is also in this entry. Note that the property set
  1014. // stores the property value as one property, with its name in the
  1015. // dictionary, and it stores the link name as a second property.
  1016. // Consequently, this routine will be called twice for such
  1017. // properties: on the first call we'll create a new entry in the
  1018. // linked-list, adding the property ID, name, and value; on the
  1019. // second call we'll pull out that entry, and add the link name.
  1020. //
  1021. // On success, the input lppropvar & lpstatpropstg are cleared.
  1022. // On error, all inputs are left unmodified.
  1023. //
  1024. ////////////////////////////////////////////////////////////////////////////////
  1025. BOOL PASCAL
  1026. FAddPropToList
  1027. (LPUDOBJ lpUDObj,
  1028. LPPROPVARIANT lppropvar,
  1029. STATPROPSTG *lpstatpropstg,
  1030. LPUDPROP lpudprop) // Property to add
  1031. {
  1032. // ------
  1033. // Locals
  1034. // ------
  1035. BOOL fSuccess = FALSE;
  1036. LPTSTR lpstz;
  1037. LPUDPROP lpudpT;
  1038. BOOL fLink;
  1039. USES_CONVERSION ;
  1040. Assert(lpUDObj != NULL);
  1041. Assert(lpudprop != NULL); // Is this a bogus assert?
  1042. Assert(lppropvar != NULL && lpstatpropstg != NULL);
  1043. // If the PId has one of the special masks, strip it off
  1044. // so the PId will match the normal value.
  1045. fLink = lpstatpropstg->propid & PID_LINKMASK;
  1046. lpstatpropstg->propid &= ~PID_LINKMASK;
  1047. // ------------------------------------------------------------
  1048. // See if we can find this property already in the linked-list.
  1049. // If we have a name, use that, otherwise use the PID.
  1050. // ------------------------------------------------------------
  1051. if (lpstatpropstg->lpwstrName != NULL)
  1052. {
  1053. // Search by name.
  1054. // [scotthan] Re: bogus cast to TCHAR in propio.c when this thing
  1055. // was read out of the file. If this is an ANSI build, it's going to store
  1056. // a TCHAR* value!. So we need to reciprocate the cast...
  1057. lpudpT = LpudpropFindMatchingName (lpUDObj, (LPTSTR)lpstatpropstg->lpwstrName );
  1058. }
  1059. else
  1060. {
  1061. // Search by PID
  1062. lpudpT = LpudpropFindMatchingPID (lpUDObj, lpstatpropstg->propid);
  1063. }
  1064. // --------------------------------------------------------------
  1065. // If this property isn't already in the linked-list, add it now.
  1066. // --------------------------------------------------------------
  1067. if (lpudpT == NULL)
  1068. {
  1069. // This should be a named property. If it's not
  1070. // named, then it should be a link, and the property
  1071. // it links should have been in the linked-list already
  1072. // (i.e., the lpudpT should have been non-NULL).
  1073. if (lpstatpropstg->lpwstrName == NULL)
  1074. {
  1075. AssertSz (0, TEXT("Missing name in User-Defined properties"));
  1076. goto Exit;
  1077. }
  1078. // Allocate memory for the property value.
  1079. lpudprop->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
  1080. if (lpudprop->lppropvar == NULL)
  1081. {
  1082. AssertSz (0, TEXT("Couldn't allocate lpudprop->lppropvar"));
  1083. goto Exit;
  1084. }
  1085. // Load the property ID, name, and value.
  1086. // Note that if we had an error before here, we left
  1087. // the caller's inputs un-touched. Since no more errors
  1088. // can occur, we'll never have half-modified data in an
  1089. // error case.
  1090. lpudprop->propid = lpstatpropstg->propid;
  1091. // [scotthan] Re: bogus cast to TCHAR in propio.c when this thing
  1092. // was read out of the file. If this is an ANSI build, it's going to store
  1093. // a TCHAR* value!. So we need to reciprocate the cast...
  1094. lpudprop->lpstzName = (LPTSTR)lpstatpropstg->lpwstrName;
  1095. lpstatpropstg->lpwstrName = NULL;
  1096. *lpudprop->lppropvar = *lppropvar;
  1097. PropVariantInit (lppropvar);
  1098. lpData->dwcProps++;
  1099. AddNodeToList (lpUDObj, lpudprop);
  1100. } // if ((lpudpT = LpudpropFindMatchingName (lpUDInfo, lpstatpropstg->lpwsz)) == NULL)
  1101. // --------------------------------------------------------
  1102. // Otherwise (this property is already in the linked-list),
  1103. // add this new link name or value to the UDPROP.
  1104. // --------------------------------------------------------
  1105. else
  1106. {
  1107. // If this is a link being added, then update the link-name in the
  1108. // extant property.
  1109. if (fLink)
  1110. {
  1111. // lpudpT points to the entry in our linked-list for this
  1112. // property. But it shouldn't already have a link-name (there
  1113. // can only be one link-name per property).
  1114. if (lpudpT->lpstzLink != NULL)
  1115. {
  1116. AssertSz (0, TEXT("Invalid property set - link name defined twice"));
  1117. goto Exit;
  1118. }
  1119. // Since this is a link-name, it should be a string.
  1120. if (lppropvar->vt != VT_LPTSTR)
  1121. {
  1122. AssertSz (0, TEXT("Invalid property set - link name isn't a string"));
  1123. goto Exit;
  1124. }
  1125. // Point the UDPROP to the link name, and take ownership
  1126. // of it by clearing the caller's pointer.
  1127. Assert (lppropvar->pszVal != NULL);
  1128. lpudpT->lpstzLink = (LPTSTR) lppropvar->pszVal;
  1129. PropVariantInit (lppropvar);
  1130. lpData->dwcLinks++;
  1131. } // if (fLink)
  1132. // Otherwise, this isn't a link name, it's a value. So point the
  1133. // UDPROP to it's data.
  1134. else
  1135. {
  1136. *lpudpT->lppropvar = *lppropvar;
  1137. PropVariantInit (lppropvar);
  1138. } // if (fLink) ... else
  1139. } // if ((lpudpT = LpudpropFindMatchingName ... else
  1140. fSuccess = TRUE;
  1141. Exit:
  1142. // Just in case we were given a name that we didn't
  1143. // need, clear it now so that the caller knows that
  1144. // on success, they needn't worry about the buffers
  1145. // pointed to by lppropvar & lpstatpropstg.
  1146. if (fSuccess)
  1147. {
  1148. if (lpstatpropstg->lpwstrName != NULL)
  1149. {
  1150. CoTaskMemFree (lpstatpropstg->lpwstrName);
  1151. lpstatpropstg->lpwstrName = NULL;
  1152. }
  1153. }
  1154. return(fSuccess);
  1155. } // FAddPropToList
  1156. ////////////////////////////////////////////////////////////////////////////////
  1157. //
  1158. // AddNodeToList
  1159. //
  1160. // Purpose:
  1161. // Adds the given node to the list.
  1162. //
  1163. ////////////////////////////////////////////////////////////////////////////////
  1164. void PASCAL
  1165. AddNodeToList
  1166. (LPUDOBJ lpUDObj, // Pointer to object
  1167. LPUDPROP lpudprop) // Node to add
  1168. {
  1169. // Put the new node at the end
  1170. if (lpData->lpudpHead != NULL)
  1171. {
  1172. if (lpData->lpudpHead->llist.lpllistPrev != NULL)
  1173. {
  1174. ((LPUDPROP) lpData->lpudpHead->llist.lpllistPrev)->llist.lpllistNext = (LPLLIST) lpudprop;
  1175. lpudprop->llist.lpllistPrev = lpData->lpudpHead->llist.lpllistPrev;
  1176. }
  1177. else
  1178. {
  1179. lpData->lpudpHead->llist.lpllistNext = (LPLLIST) lpudprop;
  1180. lpudprop->llist.lpllistPrev = (LPLLIST) lpData->lpudpHead;
  1181. }
  1182. lpData->lpudpHead->llist.lpllistPrev = (LPLLIST) lpudprop;
  1183. }
  1184. else
  1185. {
  1186. lpData->lpudpHead = lpudprop;
  1187. lpudprop->llist.lpllistPrev = NULL;
  1188. }
  1189. lpudprop->llist.lpllistNext = NULL;
  1190. lpData->lpudpCache = lpudprop;
  1191. } // AddNodeToList
  1192. ////////////////////////////////////////////////////////////////////////////////
  1193. //
  1194. // RemoveFromList
  1195. //
  1196. // Purpose:
  1197. // Removes the given node from the list
  1198. //
  1199. ////////////////////////////////////////////////////////////////////////////////
  1200. static void PASCAL
  1201. RemoveFromList
  1202. (LPUDOBJ lpUDObj, // Pointer to object
  1203. LPUDPROP lpudprop) // The node itself.
  1204. {
  1205. AssertSz ((lpData->lpudpHead != NULL), TEXT("List is corrupt"));
  1206. // If we're removing the cached node, invalidate the cache
  1207. if (lpudprop == lpData->lpudpCache)
  1208. {
  1209. lpData->lpudpCache = NULL;
  1210. }
  1211. // Be sure the head gets updated, if the node is at the front
  1212. if (lpudprop == lpData->lpudpHead)
  1213. {
  1214. lpData->lpudpHead = (LPUDPROP) lpudprop->llist.lpllistNext;
  1215. if (lpData->lpudpHead != NULL)
  1216. {
  1217. lpData->lpudpHead->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
  1218. }
  1219. return;
  1220. }
  1221. // Update the links
  1222. if (lpudprop->llist.lpllistNext != NULL)
  1223. {
  1224. ((LPUDPROP) lpudprop->llist.lpllistNext)->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
  1225. }
  1226. if (lpudprop->llist.lpllistPrev != NULL)
  1227. {
  1228. ((LPUDPROP) lpudprop->llist.lpllistPrev)->llist.lpllistNext = lpudprop->llist.lpllistNext;
  1229. }
  1230. // If it is the last node in the list, be sure the head is updated
  1231. if (lpudprop == (LPUDPROP) lpData->lpudpHead->llist.lpllistPrev)
  1232. {
  1233. lpData->lpudpHead->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
  1234. }
  1235. } // RemoveFromList
  1236. ////////////////////////////////////////////////////////////////////////////////
  1237. //
  1238. // DeallocValue
  1239. //
  1240. // Purpose:
  1241. // Deallocates the value in the buffer.
  1242. //
  1243. ////////////////////////////////////////////////////////////////////////////////
  1244. void PASCAL
  1245. DeallocValue
  1246. (LPVOID *lplpvBuf, // Pointer to buffer to dealloc
  1247. UDTYPES udtype) // Type stored in buffer
  1248. {
  1249. DWORD cb=0;
  1250. if (*lplpvBuf == NULL)
  1251. return;
  1252. switch (udtype)
  1253. {
  1254. case wUDdate :
  1255. case wUDfloat :
  1256. Assert(sizeof(FILETIME) == sizeof(NUM));
  1257. cb = sizeof(NUM);
  1258. break;
  1259. case wUDlpsz :
  1260. cb = CBTSTR(*lplpvBuf);
  1261. break;
  1262. case wUDbool:
  1263. case wUDdw:
  1264. AssertSz (((sizeof(LPVOID) >= sizeof(DWORD)) && (sizeof(LPVOID) >= sizeof(WORD))),
  1265. TEXT("Sizes of basic types have changed!"));
  1266. return;
  1267. default:
  1268. Assert(fFalse);
  1269. return;
  1270. }
  1271. VFreeMemP(*lplpvBuf,cb);
  1272. *lplpvBuf = NULL;
  1273. } // DeallocValue
  1274. ////////////////////////////////////////////////////////////////////////////////
  1275. //
  1276. // VUdpropFree
  1277. //
  1278. // Purpose:
  1279. // Free a UDPROP (which is in a linked-list).
  1280. //
  1281. // Inputs:
  1282. // LPUDPROP * - A pointer-to-pointer-to a UDPROP object.
  1283. //
  1284. // Output:
  1285. // None.
  1286. //
  1287. ////////////////////////////////////////////////////////////////////////////////
  1288. VOID
  1289. VUdpropFree
  1290. (LPUDPROP *lplpudp)
  1291. {
  1292. // Validate the inputs.
  1293. if (lplpudp == NULL
  1294. ||
  1295. *lplpudp == NULL)
  1296. {
  1297. goto Exit;
  1298. }
  1299. // If this property has a name, free that buffer.
  1300. if ((*lplpudp)->lpstzName)
  1301. {
  1302. CoTaskMemFree ((*lplpudp)->lpstzName);
  1303. }
  1304. // If this property has a link-name, free it too.
  1305. if ((*lplpudp)->lpstzLink)
  1306. {
  1307. CoTaskMemFree ((*lplpudp)->lpstzLink);
  1308. }
  1309. // Clear the property value, which will free any associated
  1310. // buffer. Then free the PropVariant itself.
  1311. PropVariantClear ((*lplpudp)->lppropvar);
  1312. CoTaskMemFree ((*lplpudp)->lppropvar);
  1313. CoTaskMemFree (*lplpudp);
  1314. *lplpudp = NULL;
  1315. Exit:
  1316. return;
  1317. } // VUdpropFree
  1318. ////////////////////////////////////////////////////////////////////////////////
  1319. //
  1320. // FUdpropUpdate
  1321. //
  1322. // Purpose:
  1323. // Updates the given node with the given data
  1324. //
  1325. // It's the caller's responsibility to free lpudp if this function
  1326. // fails.
  1327. //
  1328. // Inputs:
  1329. // LPUDPROP - The node in the linked-list for this property.
  1330. // LPUDOBJ - All User-Defined data (including the properties)
  1331. // LPTSTR - The property name.
  1332. // LPTSTR - The link-name
  1333. // LPVOID - The new value
  1334. // UDTYPES - The type of the value.
  1335. // BOOL - TRUE if this is a link.
  1336. //
  1337. ////////////////////////////////////////////////////////////////////////////////
  1338. static BOOL PASCAL
  1339. FUdpropUpdate
  1340. (LPUDPROP lpudp,
  1341. LPUDOBJ lpUDObj,
  1342. LPTSTR lpszPropName,
  1343. LPTSTR lpszLinkMonik,
  1344. LPVOID lpvValue,
  1345. UDTYPES udtype,
  1346. BOOL fLink)
  1347. {
  1348. // ------
  1349. // Locals
  1350. // ------
  1351. BOOL fSuccess = FALSE;
  1352. // -----
  1353. // Begin
  1354. // -----
  1355. // Validate the inputs.
  1356. if ((lpudp == NULL) ||
  1357. (lpszPropName == NULL) ||
  1358. (lpvValue == NULL) ||
  1359. (fLink && (lpszLinkMonik == NULL)) ||
  1360. (!ISUDTYPE(udtype)))
  1361. {
  1362. goto Exit;
  1363. }
  1364. // Update the property name
  1365. if (!FUdpropSetString (lpudp, lpszPropName, TRUE, TRUE))
  1366. goto Exit;
  1367. // If necessary, allocate a PropVariant for the UDPROPS
  1368. if (lpudp->lppropvar == NULL)
  1369. {
  1370. lpudp->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
  1371. if (lpudp->lppropvar == NULL)
  1372. {
  1373. goto Exit;
  1374. }
  1375. }
  1376. // Put the property value into the PropVariant
  1377. PropVariantClear (lpudp->lppropvar);
  1378. if (!FPropVarLoad (lpudp->lppropvar, (VARTYPE)udtype, lpvValue))
  1379. {
  1380. goto Exit;
  1381. }
  1382. // Update the link name if this is a link, otherwise
  1383. // free any existing link name.
  1384. if (fLink)
  1385. {
  1386. if(!FUdpropSetString (lpudp, lpszLinkMonik, FALSE, FALSE))
  1387. goto Exit;
  1388. }
  1389. else
  1390. {
  1391. VUdpropFreeString (lpudp, FALSE);
  1392. lpData->dwcLinks--;
  1393. }
  1394. // ----
  1395. // Exit
  1396. // ----
  1397. fSuccess = TRUE;
  1398. Exit:
  1399. return(fSuccess);
  1400. } // FUdpropUpdate
  1401. ////////////////////////////////////////////////////////////////////////////////
  1402. //
  1403. // FMakeTmpUDProps
  1404. //
  1405. // Purpose:
  1406. // Create a temporary copy of the User-Defined property data
  1407. //
  1408. ////////////////////////////////////////////////////////////////////////////////
  1409. BOOL
  1410. FMakeTmpUDProps
  1411. (LPUDOBJ lpUDObj) // Pointer to object
  1412. {
  1413. // ------
  1414. // Locals
  1415. // ------
  1416. BOOL fSuccess = FALSE;
  1417. LPUDPROP lpudpCur;
  1418. LPUDPROP lpudpTmpCur;
  1419. DWORD dw;
  1420. LPVOID lpv;
  1421. // -----
  1422. // Begin
  1423. // -----
  1424. // Validate the inputs.
  1425. if ((lpUDObj == NULL) ||
  1426. (lpData == NULL))
  1427. {
  1428. goto Exit;
  1429. }
  1430. FDeleteTmpUDProps (lpUDObj);
  1431. // Move all the original list data to the tmp list
  1432. lpData->dwcTmpLinks = lpData->dwcLinks;
  1433. lpData->dwcTmpProps = lpData->dwcProps;
  1434. lpData->lpudpTmpHead = lpData->lpudpHead;
  1435. lpData->lpudpTmpCache = lpData->lpudpCache;
  1436. // Reinitialize the object data
  1437. lpData->dwcLinks = 0;
  1438. lpData->dwcProps = 0;
  1439. lpData->lpudpCache = NULL;
  1440. lpudpTmpCur = lpData->lpudpHead = NULL;
  1441. // Remember that we just put all the original data in the tmp ptrs.
  1442. lpudpCur = lpData->lpudpTmpHead;
  1443. // Loop through the old data and copy to the temp list
  1444. while (lpudpCur != NULL)
  1445. {
  1446. // Create a new UDPROP
  1447. lpudpTmpCur = LpudpropCreate();
  1448. if (lpudpTmpCur == NULL)
  1449. goto Exit;
  1450. // Set the name in the UDPROP
  1451. if (!FUdpropSetString (lpudpTmpCur, lpudpCur->lpstzName, FALSE, TRUE))
  1452. goto Exit;
  1453. // If we have a link-name, set it too in the UDPROP
  1454. if (lpudpCur->lpstzLink != NULL)
  1455. {
  1456. if (!FUdpropSetString (lpudpTmpCur, lpudpCur->lpstzLink, FALSE, FALSE))
  1457. goto Exit;
  1458. lpData->dwcLinks++;
  1459. }
  1460. // Allocate a PropVariant to hold the property value.
  1461. lpudpTmpCur->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
  1462. if (lpudpTmpCur->lppropvar == NULL)
  1463. {
  1464. goto Exit;
  1465. }
  1466. // Copy the PropVariant into the temporary UDPROP.
  1467. PropVariantCopy (lpudpTmpCur->lppropvar, lpudpCur->lppropvar);
  1468. // Also show if this is an invalid link or not.
  1469. lpudpTmpCur->fLinkInvalid = lpudpCur->fLinkInvalid;
  1470. // Add this new temporary UDPROP to the linked-list.
  1471. AddNodeToList (lpUDObj, lpudpTmpCur);
  1472. lpData->dwcProps++;
  1473. // Move on to the next property.
  1474. lpudpCur = (LPUDPROP) lpudpCur->llist.lpllistNext;
  1475. } // while (lpudpCur != NULL)
  1476. // ----
  1477. // Exit
  1478. // ----
  1479. fSuccess = TRUE;
  1480. Exit:
  1481. // If there was an error, put everything back and deallocate anything we created
  1482. if (!fSuccess)
  1483. {
  1484. FSwapTmpUDProps (lpUDObj);
  1485. FDeleteTmpUDProps (lpUDObj);
  1486. }
  1487. return fSuccess;
  1488. } // FMakeTmpUDProps
  1489. ////////////////////////////////////////////////////////////////////////////////
  1490. //
  1491. // FSwapTmpUDProps
  1492. //
  1493. // Purpose:
  1494. // Swap the "temp" copy with the real copy of User-Defined property data
  1495. //
  1496. ////////////////////////////////////////////////////////////////////////////////
  1497. BOOL
  1498. FSwapTmpUDProps
  1499. (LPUDOBJ lpUDObj)
  1500. {
  1501. DWORD dwT;
  1502. LPUDPROP lpudpT;
  1503. if ((lpUDObj == NULL) ||
  1504. (lpData == NULL))
  1505. return FALSE;
  1506. dwT = lpData->dwcLinks;
  1507. lpData->dwcLinks = lpData->dwcTmpLinks;
  1508. lpData->dwcTmpLinks = dwT;
  1509. dwT = lpData->dwcProps;
  1510. lpData->dwcProps = lpData->dwcTmpProps;
  1511. lpData->dwcTmpProps = dwT;
  1512. lpudpT = lpData->lpudpHead;
  1513. lpData->lpudpHead = lpData->lpudpTmpHead;
  1514. lpData->lpudpTmpHead = lpudpT;
  1515. lpudpT = lpData->lpudpCache;
  1516. lpData->lpudpCache = lpData->lpudpTmpCache;
  1517. lpData->lpudpTmpCache = lpudpT;
  1518. return TRUE;
  1519. } // FSwapTmpUDProps
  1520. ////////////////////////////////////////////////////////////////////////////////
  1521. //
  1522. // FDeleteTmpUDProps
  1523. //
  1524. // Purpose:
  1525. // Delete the "temp" copy of the data
  1526. //
  1527. ////////////////////////////////////////////////////////////////////////////////
  1528. BOOL
  1529. FDeleteTmpUDProps
  1530. (LPUDOBJ lpUDObj)
  1531. {
  1532. if ((lpUDObj == NULL) ||
  1533. (lpData == NULL))
  1534. return FALSE;
  1535. FreeUDData (lpUDObj, TRUE);
  1536. return TRUE;
  1537. } // FDeleteTmpU
  1538. ////////////////////////////////////////////////////////////////////////////////
  1539. //
  1540. // FUdpropMakeVisible
  1541. //
  1542. // Purpose:
  1543. // Make a property in a UDPROP visibile by removing the
  1544. // "_" that prepends the property name.
  1545. //
  1546. // Inputs:
  1547. // LPUDPROP - The UDPROP to convert.
  1548. //
  1549. // Output:
  1550. // TRUE if successful.
  1551. //
  1552. ////////////////////////////////////////////////////////////////////////////////
  1553. static BOOL PASCAL
  1554. FUdpropMakeVisible (LPUDPROP lpudprop)
  1555. {
  1556. // ------
  1557. // Locals
  1558. // ------
  1559. BOOL fSuccess = FALSE;
  1560. ULONG cch;
  1561. // -----
  1562. // Begin
  1563. // -----
  1564. Assert (lpudprop != NULL);
  1565. // Is there anything to process?
  1566. if (lpudprop->lpstzName == NULL)
  1567. goto Exit;
  1568. // Simply move the string up one character, thus overlaying
  1569. // the prefix indicating a hidden property. If it's already
  1570. // a visible property we don't flag an error.
  1571. if (*lpudprop->lpstzName == HIDDENPREFIX)
  1572. {
  1573. cch = CchTszLen (lpudprop->lpstzName) + 1;
  1574. PbSzNCopy (lpudprop->lpstzName, &lpudprop->lpstzName[1], cch);
  1575. }
  1576. fSuccess = TRUE;
  1577. // ----
  1578. // Exit
  1579. // ----
  1580. Exit:
  1581. return (fSuccess);
  1582. } // FUdpropMakeVisible
  1583. ////////////////////////////////////////////////////////////////////////////////
  1584. //
  1585. // FUdpropMakeHidden
  1586. //
  1587. // Purpose:
  1588. // Convert a property in a UDPROP so that it is a hidden
  1589. // property. Properties are considered hidden if the
  1590. // first character in their name is an "_".
  1591. //
  1592. // Inputs:
  1593. // LPUDPROP - The UDPROP to convert.
  1594. //
  1595. // Output:
  1596. // TRUE if successful.
  1597. //
  1598. ////////////////////////////////////////////////////////////////////////////////
  1599. static BOOL PASCAL
  1600. FUdpropMakeHidden (LPUDPROP lpudprop)
  1601. {
  1602. // ------
  1603. // Locals
  1604. // ------
  1605. BOOL fSuccess = FALSE;
  1606. ULONG cch;
  1607. LPTSTR lpstzOld = NULL;
  1608. // -----
  1609. // Begin
  1610. // -----
  1611. // Intialize
  1612. Assert (lpudprop != NULL);
  1613. if (lpudprop->lpstzName == NULL)
  1614. goto Exit;
  1615. // Keep the old name.
  1616. lpstzOld = lpudprop->lpstzName;
  1617. // How many characters do we need in the new string?
  1618. cch = CchTszLen (lpstzOld) + 2; // Includes the NULL & prefix
  1619. // Allocate the memory.
  1620. lpudprop->lpstzName = CoTaskMemAlloc (cch * sizeof(TCHAR));
  1621. if (lpudprop->lpstzName == NULL)
  1622. goto Exit;
  1623. // Set the "_" prefix to indicate this is a hidden property.
  1624. lpudprop->lpstzName[0] = HIDDENPREFIX;
  1625. // Copy the original property name after the prefix in the UDPROP.
  1626. PbSzNCopy (&lpudprop->lpstzName[1],
  1627. lpstzOld,
  1628. cch - 1); // One chacter less than cch to accout for hidden prefix.
  1629. // Free the old buffer
  1630. CoTaskMemFree (lpstzOld);
  1631. // ----
  1632. // Exit
  1633. // ----
  1634. fSuccess = TRUE;
  1635. Exit:
  1636. // If there was an error, ensure that the UDPROP is left as
  1637. // we found it.
  1638. if (!fSuccess)
  1639. {
  1640. if (lpstzOld != NULL)
  1641. {
  1642. if (lpudprop->lpstzName != NULL)
  1643. {
  1644. CoTaskMemFree (lpudprop->lpstzName);
  1645. }
  1646. lpudprop->lpstzName = lpstzOld;
  1647. }
  1648. }
  1649. return (fSuccess);
  1650. } // FUdpropMakeHidden
  1651. ////////////////////////////////////////////////////////////////////////////////
  1652. //
  1653. // FUdpropSetString
  1654. //
  1655. // Purpose:
  1656. // Set the name or link-name string in a UDPROP.
  1657. // If the UDPROP already contains the string, free
  1658. // it.
  1659. //
  1660. // Inputs:
  1661. // LPUDPROP - A UDPROP (a property in the linked-list)
  1662. // LPTSTR - The new name or link-name
  1663. // BOOL - True => limit the length of the string to BUFMAX characters
  1664. // (including the NULL terminator)
  1665. // BOOL - True => set the (property) name, False => set the link-name
  1666. //
  1667. ////////////////////////////////////////////////////////////////////////////////
  1668. static BOOL PASCAL
  1669. FUdpropSetString
  1670. (LPUDPROP lpudp,
  1671. LPTSTR lptstr,
  1672. BOOL fLimitLength,
  1673. BOOL fName)
  1674. {
  1675. // ------
  1676. // Locals
  1677. // ------
  1678. BOOL fSuccess = FALSE; // Return value
  1679. LPTSTR lptstrNew = NULL; // Pointed to be the UDPROP.
  1680. ULONG cch, cb;
  1681. // ----------
  1682. // Initialize
  1683. // ----------
  1684. // Validate the inputs.
  1685. if (lpudp == NULL
  1686. ||
  1687. lptstr == NULL)
  1688. {
  1689. goto Exit;
  1690. }
  1691. // ----------------
  1692. // Set the new name
  1693. // ----------------
  1694. // Calculate the sizes.
  1695. cch = CchTszLen(lptstr);
  1696. if (fLimitLength && cch >= BUFMAX)
  1697. {
  1698. cch = BUFMAX - 1;
  1699. }
  1700. cb = (cch + 1) * sizeof(TCHAR); // Leave room for the NULL.
  1701. // Allocate new memory.
  1702. lptstrNew = CoTaskMemAlloc (cb);
  1703. if (lptstrNew == NULL)
  1704. {
  1705. goto Exit;
  1706. }
  1707. // Copy the buffer (the buffer size is cch+1 including the NULL)
  1708. // Also, terminate the target string, since it may be a truncation
  1709. // of the source string.
  1710. PbSzNCopy (lptstrNew, lptstr, cch+1);
  1711. lptstrNew[cch] = TEXT('\0');
  1712. // Put this new buffer in the UDPROP.
  1713. if (fName)
  1714. lpudp->lpstzName = lptstrNew;
  1715. else
  1716. lpudp->lpstzLink = lptstrNew;
  1717. lptstrNew = NULL;
  1718. // ----
  1719. // Exit
  1720. // ----
  1721. fSuccess = TRUE;
  1722. Exit:
  1723. if (lptstrNew != NULL)
  1724. CoTaskMemFree (lptstrNew);
  1725. return (fSuccess);
  1726. } // FUdpropSetString
  1727. ////////////////////////////////////////////////////////////////////////////////
  1728. //
  1729. // VUdpropFreeString
  1730. //
  1731. // Purpose:
  1732. // Free one of the two strings in a UDPROP - the
  1733. // name string or the link-name string. It is not
  1734. // considered an error if either the UDPROP or the
  1735. // string doesn't exist.
  1736. //
  1737. // Inputs:
  1738. // LPUDPROP - The UDPROP containing the strings.
  1739. // BOOL - TRUE indicates we should free the
  1740. // name, FALSE indicates we should free
  1741. // the link name.
  1742. //
  1743. // Output:
  1744. // None.
  1745. //
  1746. ////////////////////////////////////////////////////////////////////////////////
  1747. static void PASCAL
  1748. VUdpropFreeString
  1749. (LPUDPROP lpudp,
  1750. BOOL fName)
  1751. {
  1752. // Is this really a UDPROP?
  1753. if (lpudp != NULL)
  1754. {
  1755. // Should we delete the name?
  1756. if (fName && lpudp->lpstzName)
  1757. {
  1758. CoTaskMemFree (lpudp->lpstzName);
  1759. lpudp->lpstzName = NULL;
  1760. }
  1761. // Should we delete the link name?
  1762. else if (!fName && lpudp->lpstzLink)
  1763. {
  1764. CoTaskMemFree (lpudp->lpstzLink);
  1765. lpudp->lpstzLink = NULL;
  1766. }
  1767. } // if (lpudp != NULL)
  1768. return;
  1769. } // VUdpropFreeString
  1770. /////////////////////////////////////////////////////////////////////////////////////
  1771. //
  1772. // LpudpropCreate
  1773. //
  1774. // Purpose:
  1775. // Create a new UDPROP structure (an element of a linked-
  1776. // list, and holds information about a single property).
  1777. //
  1778. // Inputs:
  1779. // None
  1780. //
  1781. // Output:
  1782. // A LPUDPROP if successful, NULL otherwise.
  1783. //
  1784. /////////////////////////////////////////////////////////////////////////////////////
  1785. LPUDPROP
  1786. LpudpropCreate ( void )
  1787. {
  1788. // Create a buffer for the UDPROP
  1789. LPUDPROP lpudp = CoTaskMemAlloc (sizeof(UDPROP));
  1790. // Zero the buffer.
  1791. if (lpudp != NULL)
  1792. {
  1793. FillBuf (lpudp, 0, sizeof(UDPROP));
  1794. }
  1795. return (lpudp);
  1796. } // LpudpropCreate
  1797. ////////////////////////////////////////////////////////////////////////////////
  1798. //
  1799. // LppropvarUserDefGetPropVal
  1800. //
  1801. // Purpose:
  1802. // Return a PropVariant pointer for the requested
  1803. // property (requested by property name).
  1804. //
  1805. // Inputs:
  1806. // LPUDOBJ - All UD data (including properties)
  1807. // LPTSTR - The name of the desired property
  1808. // BOOL * - True if this is a link.
  1809. // BOOL * - True if this link is invalid.
  1810. //
  1811. // Output:
  1812. // An LPPROPVARINT, or NULL if there was an error.
  1813. //
  1814. ////////////////////////////////////////////////////////////////////////////////
  1815. DLLEXPORT LPPROPVARIANT
  1816. LppropvarUserDefGetPropVal
  1817. (LPUDOBJ lpUDObj, // Pointer to object
  1818. LPTSTR lpszProp, // Property string
  1819. BOOL *pfLink, // Indicates a link
  1820. BOOL *pfLinkInvalid) // Is the link invalid
  1821. {
  1822. // ------
  1823. // Locals
  1824. // ------
  1825. LPUDPROP lpudprop;
  1826. LPPROPVARIANT lppropvar;
  1827. // --------------
  1828. // Initialization
  1829. // --------------
  1830. if ((lpUDObj == NULL) ||
  1831. (lpData == NULL) ||
  1832. (lpszProp == NULL))
  1833. {
  1834. return NULL;
  1835. }
  1836. // ---------------------------------
  1837. // Find the node that has this name.
  1838. // ---------------------------------
  1839. lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
  1840. if (lpudprop == NULL)
  1841. return NULL;
  1842. // Is this a link?
  1843. if (pfLink != NULL)
  1844. {
  1845. *pfLink = (lpudprop->lpstzLink != NULL);
  1846. }
  1847. // Is this an invalid link? (In the Shell, all properties are
  1848. // invalid).
  1849. if (pfLinkInvalid != NULL)
  1850. {
  1851. #ifdef SHELL
  1852. *pfLinkInvalid = lpudprop->fLinkInvalid = TRUE;
  1853. #else
  1854. *pfLinkInvalid = lpudprop->fLinkInvalid;
  1855. #endif
  1856. }
  1857. // ----
  1858. // Exit
  1859. // ----
  1860. return (lpudprop->lppropvar);
  1861. } // LppropvarUserDefGetPropVal
  1862. ////////////////////////////////////////////////////////////////////////////////
  1863. //
  1864. // LppropvarUserDefGetIteratorVal
  1865. //
  1866. // Purpose:
  1867. // Given an iterator value, get the property value.
  1868. //
  1869. // Inputs:
  1870. // LPUDITER - The Iterator value.
  1871. // BOOL * - Set to True if this value is a link.
  1872. // BOLL * - Set to True if this value is invalid link.
  1873. //
  1874. // Outputs:
  1875. // LPPROPVARIANT of the property value.
  1876. //
  1877. ////////////////////////////////////////////////////////////////////////////////
  1878. DLLEXPORT LPPROPVARIANT
  1879. LppropvarUserDefGetIteratorVal
  1880. (LPUDITER lpUDIter,
  1881. BOOL *pfLink,
  1882. BOOL *pfLinkInvalid )
  1883. {
  1884. // Validate the inputs
  1885. if ((lpUDIter == NULL) ||
  1886. (lpUDIter->lpudp == NULL))
  1887. return NULL;
  1888. // Is this a Link?
  1889. if (pfLink != NULL)
  1890. {
  1891. *pfLink = (lpUDIter->lpudp->lpstzLink != NULL);
  1892. }
  1893. // Is this an invalid link?
  1894. if (pfLinkInvalid != NULL)
  1895. {
  1896. *pfLinkInvalid = lpUDIter->lpudp->fLinkInvalid;
  1897. }
  1898. // Return a pointer to the PropVariant
  1899. return (lpUDIter->lpudp->lppropvar);
  1900. } // LpvoidUserDefGetIteratorVal