Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1923 lines
49 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 FUserDefMakeHidden (LPUDOBJ lpUDObj, LPTSTR lpsz);
  38. static BOOL PASCAL FUdpropMakeHidden (LPUDPROP lpudprop);
  39. #define lpDocObj (lpUDObj)
  40. #define lpData ((LPUDINFO) lpUDObj->m_lpData)
  41. ////////////////////////////////////////////////////////////////////////////////
  42. //
  43. // OfficeDirtyUDObj
  44. //
  45. // Purpose:
  46. // Sets object state to dirty or clean.
  47. //
  48. ////////////////////////////////////////////////////////////////////////////////
  49. DLLEXPORT VOID OfficeDirtyUDObj
  50. (LPUDOBJ lpUDObj, // The object
  51. BOOL fDirty) // Flag indicating if the object is dirty.
  52. {
  53. Assert(lpUDObj != NULL);
  54. lpUDObj->m_fObjChanged = fDirty;
  55. } // OfficeDirtyUDObj
  56. ////////////////////////////////////////////////////////////////////////////////
  57. //
  58. // FreeUDData
  59. //
  60. // Purpose:
  61. // Deallocates all the member data for the object
  62. //
  63. // Note:
  64. // Assumes object is valid.
  65. //
  66. ////////////////////////////////////////////////////////////////////////////////
  67. void PASCAL
  68. FreeUDData
  69. (LPUDOBJ lpUDObj, // Pointer to valid object
  70. BOOL fTmp) // Indicates tmp data should be freed
  71. {
  72. LPUDPROP lpudp;
  73. LPUDPROP lpudpT;
  74. lpudp = (fTmp) ? lpData->lpudpTmpHead : lpData->lpudpHead;
  75. while (lpudp != NULL)
  76. {
  77. lpudpT = lpudp;
  78. lpudp = (LPUDPROP) lpudp->llist.lpllistNext;
  79. VUdpropFree(&lpudpT);
  80. }
  81. if (fTmp)
  82. {
  83. lpData->lpudpTmpCache = NULL;
  84. lpData->lpudpTmpHead = NULL;
  85. lpData->dwcTmpProps = 0;
  86. lpData->dwcTmpLinks = 0;
  87. }
  88. else
  89. {
  90. lpData->lpudpCache = NULL;
  91. lpData->lpudpHead = NULL;
  92. lpData->dwcProps = 0;
  93. lpData->dwcLinks = 0;
  94. }
  95. } // FreeUDData
  96. ////////////////////////////////////////////////////////////////////////////////
  97. //
  98. // FUserDefCreate
  99. //
  100. // Purpose:
  101. // Create a User-defined property exchange object.
  102. //
  103. ////////////////////////////////////////////////////////////////////////////////
  104. BOOL
  105. FUserDefCreate
  106. (LPUDOBJ FAR *lplpUDObj, // Pointer to pointer to object
  107. void *prglpfn[]) // Pointer to functions
  108. {
  109. LPUDOBJ lpUDObj; // Hack - a temp, must call it "lpUdObj" for macros to work!
  110. if (lplpUDObj == NULL)
  111. return(TRUE);
  112. // Make sure we get valid args before we start alloc'ing
  113. if ((prglpfn == NULL) || (prglpfn[ifnCPConvert] == NULL) ||
  114. ((prglpfn[ifnFSzToNum] == NULL) && (prglpfn[ifnFNumToSz] != NULL)) ||
  115. ((prglpfn[ifnFSzToNum] != NULL) && (prglpfn[ifnFNumToSz] == NULL))
  116. )
  117. {
  118. return FALSE;
  119. }
  120. if ((*lplpUDObj = LocalAlloc(LPTR, sizeof(USERPROP))) == NULL)
  121. {
  122. return FALSE;
  123. }
  124. lpDocObj = *lplpUDObj;
  125. //
  126. // If alloc fails, free the original object too.
  127. //
  128. if ((lpData = LocalAlloc(LPTR, sizeof (UDINFO))) == NULL)
  129. {
  130. LocalFree(*lplpUDObj);
  131. return FALSE;
  132. }
  133. //
  134. // Save the fnc's for code page convert, SzToNum, NumToSz
  135. //
  136. lpData->lpfnFCPConvert = (BOOL (*)(LPTSTR, DWORD, DWORD, BOOL)) prglpfn[ifnCPConvert];
  137. lpData->lpfnFSzToNum = (BOOL (*)(NUM *, LPTSTR)) prglpfn[ifnFSzToNum];
  138. lpData->lpfnFNumToSz = (BOOL (*)(NUM *, LPTSTR, DWORD)) prglpfn[ifnFNumToSz];
  139. OfficeDirtyUDObj (*lplpUDObj, FALSE);
  140. (*lplpUDObj)->m_hPage = NULL;
  141. return TRUE;
  142. } // FUserDefCreate
  143. ////////////////////////////////////////////////////////////////////////////////
  144. //
  145. // FUserDefDestroy
  146. //
  147. // Purpose:
  148. // Destroy a User-defined property exchange object.
  149. //
  150. ////////////////////////////////////////////////////////////////////////////////
  151. BOOL
  152. FUserDefDestroy
  153. (LPUDOBJ FAR *lplpUDObj) // Pointer to pointer to object
  154. {
  155. DWORD irg;
  156. LPUDINFO lpUDData;
  157. lpUDData = (LPUDINFO)(((LPUDOBJ) *lplpUDObj)->m_lpData);
  158. if ((lplpUDObj == NULL) || (*lplpUDObj == NULL))
  159. return TRUE;
  160. if (lpUDData != NULL)
  161. {
  162. FreeUDData (*lplpUDObj, FALSE);
  163. FreeUDData (*lplpUDObj, TRUE);
  164. //
  165. // Invalidate any OLE Automation DocumentProperty objects we might have
  166. //
  167. InvalidateVBAObjects(NULL, NULL, *lplpUDObj);
  168. LocalFree((*lplpUDObj)->m_lpData);
  169. }
  170. LocalFree(*lplpUDObj);
  171. *lplpUDObj = NULL;
  172. return TRUE;
  173. } // FUserDefDestroy
  174. ////////////////////////////////////////////////////////////////////////////////
  175. //
  176. // FUserDefClear
  177. //
  178. // Purpose:
  179. // Clears a User-defined property object without destroying it. All stored
  180. // data is lost.
  181. //
  182. ////////////////////////////////////////////////////////////////////////////////
  183. BOOL
  184. FUserDefClear(LPUDOBJ lpUDObj) // Pointer to object
  185. {
  186. if ((lpDocObj == NULL) || (lpData == NULL))
  187. return TRUE;
  188. FreeUDData (lpDocObj, FALSE);
  189. FreeUDData (lpDocObj, TRUE);
  190. //
  191. // Invalidate any OLE Automation DocumentProperty objects we might have
  192. //
  193. InvalidateVBAObjects(NULL, NULL, lpUDObj);
  194. //
  195. // Clear the data, don't blt over the fn's stored at the end.
  196. //
  197. ZeroMemory( lpData, sizeof (UDINFO) - ifnUDMax * sizeof(void *) );
  198. OfficeDirtyUDObj (lpUDObj, TRUE);
  199. return TRUE;
  200. } // FUserDefClear
  201. ////////////////////////////////////////////////////////////////////////////////
  202. //
  203. // FUserDefShouldSave
  204. //
  205. // Purpose:
  206. // Indicates if the data has changed, meaning a write is needed.
  207. //
  208. ////////////////////////////////////////////////////////////////////////////////
  209. DLLEXPORT BOOL
  210. FUserDefShouldSave
  211. (LPUDOBJ lpUDObj) // Pointer to object
  212. {
  213. if (lpUDObj == NULL)
  214. return FALSE;
  215. return lpDocObj->m_fObjChanged;
  216. } // FUserDefShouldSave
  217. ////////////////////////////////////////////////////////////////////////////////
  218. //
  219. // UdtypesUserDefType
  220. //
  221. // Purpose:
  222. // Returns the type of the given Property Value from the string
  223. //
  224. // Returns wUDInvalid on error
  225. //
  226. ////////////////////////////////////////////////////////////////////////////////
  227. DLLEXPORT UDTYPES
  228. UdtypesUserDefType
  229. (LPUDOBJ lpUDObj,
  230. LPTSTR lpsz)
  231. {
  232. LPUDPROP lpudprop;
  233. if ((lpUDObj == NULL) ||
  234. (lpData == NULL) ||
  235. (lpsz == NULL)
  236. )
  237. {
  238. return wUDinvalid;
  239. }
  240. //
  241. // Find the node that has this name.
  242. //
  243. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  244. if (lpudprop == NULL || lpudprop->lppropvar == NULL)
  245. return wUDinvalid;
  246. // Return the VarType (which is a UDTYPE)
  247. return (lpudprop->lppropvar->vt);
  248. } // UdtypesUserDefType
  249. ////////////////////////////////////////////////////////////////////////////////
  250. //
  251. // LpvoidUserDefGetPropVal
  252. //
  253. // Purpose:
  254. // This will return the Property Value for the given Property String.
  255. //
  256. ////////////////////////////////////////////////////////////////////////////////
  257. DLLEXPORT LPVOID
  258. LpvoidUserDefGetPropVal
  259. (LPUDOBJ lpUDObj, // Pointer to object
  260. LPTSTR lpszProp, // Property string
  261. DWORD dwMask, // Mask for what value is needed
  262. BOOL *pfLink, // Indicates a link
  263. BOOL *pfLinkInvalid) // Is the link invalid
  264. {
  265. LPUDPROP lpudprop;
  266. if ((lpUDObj == NULL) ||
  267. (lpData == NULL) ||
  268. (lpszProp == NULL) ||
  269. (pfLink == NULL) ||
  270. (pfLinkInvalid == NULL)
  271. )
  272. {
  273. return NULL;
  274. }
  275. //
  276. // Find the node that has this name.
  277. //
  278. lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
  279. if (lpudprop == NULL)
  280. return NULL;
  281. Assert (lpudprop->lppropvar != NULL);
  282. *pfLink = (lpudprop->lpstzLink != NULL);
  283. // Links are always invalid in the shell (there's no app to update the data).
  284. *pfLinkInvalid = lpudprop->fLinkInvalid = TRUE;
  285. //
  286. // Return based on the type and flags
  287. //
  288. if (dwMask & UD_LINK)
  289. {
  290. if (dwMask & UD_PTRWIZARD)
  291. {
  292. if (lpudprop->lpstzLink != NULL)
  293. {
  294. return (LPVOID) lpudprop->lpstzLink;
  295. }
  296. return(NULL);
  297. }
  298. return(NULL);
  299. }
  300. if (dwMask & UD_PTRWIZARD)
  301. {
  302. // If this is a string, return it's pointer from the
  303. // PropVariant. Otherwise, return a pointer into
  304. // the data of the PropVariant.
  305. return (lpudprop->lppropvar->vt == VT_LPTSTR) ?
  306. (LPVOID) lpudprop->lppropvar->pszVal :
  307. (LPVOID) &lpudprop->lppropvar->lVal;
  308. }
  309. // Copy the property from the PropVariant to the caller-provided
  310. // buffer.
  311. return( NULL );
  312. } // LpvoidUserDefGetPropVal
  313. ////////////////////////////////////////////////////////////////////////////////
  314. //
  315. // LppropvarUserDefAddProp
  316. //
  317. // Purpose:
  318. // This will add a new Property to the set, with the given
  319. // Property string, type, and data.
  320. //
  321. ////////////////////////////////////////////////////////////////////////////////
  322. DLLEXPORT LPPROPVARIANT
  323. LppropvarUserDefAddProp
  324. (LPUDOBJ lpUDObj, // Pointer to object
  325. LPTSTR lpszPropName, // Property string
  326. LPVOID lpvVal, // Property value
  327. UDTYPES udtype, // Property type
  328. LPTSTR lpszLinkMonik, // Link name
  329. BOOL fLink, // Indicates the property is a link
  330. BOOL fHidden) // Indicates the property is hidden
  331. {
  332. LPUDPROP lpudprop;
  333. LPUDPROP lpudpropMatch;
  334. BOOL fCreated;
  335. if ((lpUDObj == NULL) ||
  336. (lpData == NULL) ||
  337. (lpszPropName == NULL) ||
  338. (*lpszPropName == 0) ||
  339. (lpvVal == NULL) ||
  340. (!ISUDTYPE(udtype)) ||
  341. (fLink && (lpszLinkMonik == NULL))
  342. )
  343. {
  344. return FALSE;
  345. }
  346. // Create a UDPROP to be added to the linked-list.
  347. lpudprop = LpudpropCreate();
  348. if (lpudprop == NULL)
  349. return FALSE;
  350. // Put the data into the UDPROP.
  351. if (!FUdpropUpdate( lpudprop,
  352. lpUDObj,
  353. lpszPropName,
  354. lpszLinkMonik,
  355. lpvVal,
  356. udtype,
  357. fLink)
  358. )
  359. {
  360. VUdpropFree (&lpudprop);
  361. return(FALSE);
  362. }
  363. //
  364. // Find this node
  365. //
  366. lpudpropMatch = LpudpropFindMatchingName (lpUDObj, lpszPropName);
  367. if (lpudpropMatch==NULL)
  368. {
  369. //
  370. // Create a node and put it in the list
  371. // If a new node was created, it must be added to the list...
  372. //
  373. if (fLink)
  374. lpData->dwcLinks++;
  375. lpData->dwcProps++;
  376. AddNodeToList (lpUDObj, lpudprop);
  377. } // if (lpudpropMatch==NULL)
  378. else
  379. {
  380. // We must replace the existing UDPROP with the new
  381. // value.
  382. // Free any existing property name and link name in this
  383. // UDPROP, and free its value.
  384. VUdpropFreeString (lpudpropMatch, TRUE);
  385. VUdpropFreeString (lpudpropMatch, FALSE);
  386. PropVariantClear (lpudpropMatch->lppropvar);
  387. CoTaskMemFree (lpudpropMatch->lppropvar);
  388. lpudpropMatch->lppropvar = NULL;
  389. // Put the linked-list pointer in the existing UDPROP into
  390. // the new UDPROP, then copy the new UDPROP back over
  391. // the matching PROP (this way, we don't have to
  392. // update the UDPROP that points to the match).
  393. lpudprop->llist=lpudpropMatch->llist;
  394. CopyMemory(lpudpropMatch, lpudprop, sizeof(UDPROP));
  395. // Clear out the caller-provided UDPROP, free it, but
  396. // then set the pointer to the matching entry and clear
  397. // the match pointer. Thus, after we're done and whether
  398. // there was a match or not, lpudprop will point to the
  399. // correct UDPROP.
  400. ZeroMemory(lpudprop, sizeof(UDPROP));
  401. VUdpropFree (&lpudprop);
  402. lpudprop = lpudpropMatch;
  403. lpudpropMatch = NULL;
  404. } // if (lpudpropMatch==NULL) ... else
  405. //
  406. // If the client asked for a hidden property, do it if
  407. // the name was the real name, not a link
  408. //
  409. if (fHidden && !fLink)
  410. {
  411. fCreated=FUserDefMakeHidden (lpUDObj, lpszPropName); // Should never return false
  412. Assert(fCreated);
  413. }
  414. OfficeDirtyUDObj (lpUDObj, TRUE);
  415. // If successful, return a pointer to the PropVariant with the value.
  416. if (lpudprop)
  417. return lpudprop->lppropvar;
  418. else
  419. return NULL;
  420. } // LppropvarUserDefAddProp
  421. ////////////////////////////////////////////////////////////////////////////////
  422. //
  423. // FUserDefDeleteProp
  424. //
  425. // Purpose:
  426. // This will delete a Property from the set given a Property string.
  427. //
  428. ////////////////////////////////////////////////////////////////////////////////
  429. DLLEXPORT BOOL
  430. FUserDefDeleteProp
  431. (LPUDOBJ lpUDObj, // Pointer to object
  432. LPTSTR lpsz) // String to delete
  433. {
  434. LPUDPROP lpudprop;
  435. if ((lpUDObj == NULL) ||
  436. (lpData == NULL) ||
  437. (lpsz == NULL))
  438. return FALSE;
  439. // Find the node
  440. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  441. if (lpudprop == NULL)
  442. return FALSE;
  443. lpData->dwcProps--;
  444. if (lpudprop->lpstzLink != NULL)
  445. lpData->dwcLinks--;
  446. RemoveFromList (lpUDObj, lpudprop);
  447. VUdpropFree (&lpudprop);
  448. OfficeDirtyUDObj (lpUDObj, TRUE);
  449. return TRUE;
  450. } // FUserDefDeleteProp
  451. ////////////////////////////////////////////////////////////////////////////////
  452. //
  453. // LpudiUserDefCreateIterator
  454. //
  455. // Purpose:
  456. // Create a User-defined Properties iterator
  457. //
  458. ////////////////////////////////////////////////////////////////////////////////
  459. DLLEXPORT LPUDITER
  460. LpudiUserDefCreateIterator
  461. (LPUDOBJ lpUDObj) // Pointer to object
  462. {
  463. LPUDITER lpudi;
  464. if ((lpUDObj == NULL) ||
  465. (lpData == NULL) ||
  466. (lpData->lpudpHead == NULL)) // No custom props
  467. return NULL;
  468. // Create & Init the iterator
  469. lpudi = LocalAlloc(LPTR, sizeof(UDITER));
  470. if (lpudi == NULL)
  471. return(NULL);
  472. lpudi->lpudp = lpData->lpudpHead;
  473. return lpudi;
  474. } // LpudiUserDefCreateIterator
  475. ////////////////////////////////////////////////////////////////////////////////
  476. //
  477. // FUserDefDestroyIterator
  478. //
  479. // Purpose:
  480. // Destroy a User-defined Properties iterator
  481. //
  482. ////////////////////////////////////////////////////////////////////////////////
  483. DLLEXPORT BOOL
  484. FUserDefDestroyIterator
  485. (LPUDITER *lplpUDIter) // Pointer to iterator
  486. {
  487. if ((lplpUDIter == NULL) || (*lplpUDIter == NULL))
  488. return TRUE;
  489. LocalFree(*lplpUDIter);
  490. *lplpUDIter = NULL;
  491. return TRUE;
  492. } // FUserDefDestroyIterator
  493. ////////////////////////////////////////////////////////////////////////////////
  494. //
  495. // FUserDefIteratorValid
  496. //
  497. // Purpose:
  498. // Determine if an iterator is still valid
  499. //
  500. ////////////////////////////////////////////////////////////////////////////////
  501. DLLEXPORT BOOL
  502. FUserDefIteratorValid
  503. (LPUDITER lpUDIter) // Pointer to iterator
  504. {
  505. if (lpUDIter == NULL)
  506. return FALSE;
  507. return (lpUDIter->lpudp != NULL);
  508. } // FUserDefIteratorValid
  509. ////////////////////////////////////////////////////////////////////////////////
  510. //
  511. // FUserDefIteratorNext
  512. //
  513. // Purpose:
  514. // Iterate to the next element
  515. //
  516. ////////////////////////////////////////////////////////////////////////////////
  517. DLLEXPORT BOOL
  518. FUserDefIteratorNext
  519. (LPUDITER lpUDIter) // Pointer to iterator
  520. {
  521. if (lpUDIter == NULL)
  522. return FALSE;
  523. // Move to the next node, if possible.
  524. #ifdef OLD
  525. if (lpUDIter->lpudp != NULL)
  526. lpUDIter->lpudp = (LPUDPROP) lpUDIter->lpudp->llist.lpllistNext;
  527. return TRUE;
  528. #endif
  529. if (lpUDIter->lpudp == NULL)
  530. return FALSE;
  531. lpUDIter->lpudp = (LPUDPROP) lpUDIter->lpudp->llist.lpllistNext;
  532. return(lpUDIter->lpudp != NULL);
  533. } // FUserDefIteratorNext
  534. ////////////////////////////////////////////////////////////////////////////////
  535. //
  536. // FUserDefIteratorIsLink
  537. //
  538. // Purpose:
  539. // Returns TRUE if the iterator is a link, FALSE otherwise
  540. //
  541. ////////////////////////////////////////////////////////////////////////////////
  542. DLLEXPORT BOOL
  543. FUserDefIteratorIsLink
  544. (LPUDITER lpUDIter) // Pointer to iterator
  545. {
  546. if ((lpUDIter == NULL) || (lpUDIter->lpudp == NULL))
  547. return FALSE;
  548. return(lpUDIter->lpudp->lpstzLink != NULL);
  549. } // FUserDefIteratorIsLink
  550. ////////////////////////////////////////////////////////////////////////////////
  551. //
  552. // LpszUserDefIteratorName
  553. //
  554. // Purpose:
  555. // This will return the Property String (name) for the property
  556. //
  557. ////////////////////////////////////////////////////////////////////////////////
  558. DLLEXPORT LPTSTR
  559. LpszUserDefIteratorName(
  560. LPUDITER lpUDIter // Pointer to iterator
  561. )
  562. {
  563. if ((lpUDIter == NULL) ||
  564. (lpUDIter->lpudp == NULL))
  565. {
  566. return NULL;
  567. }
  568. return (lpUDIter->lpudp->lpstzName);
  569. } // LpszUserDefIteratorName
  570. ////////////////////////////////////////////////////////////////////////////////
  571. //
  572. // FUserDefMakeHidden
  573. //
  574. // Purpose:
  575. // Hide a Property based on the Property string.
  576. //
  577. ////////////////////////////////////////////////////////////////////////////////
  578. static BOOL PASCAL
  579. FUserDefMakeHidden
  580. (LPUDOBJ lpUDObj, // Pointer to object
  581. LPTSTR lpsz) // String to hide
  582. {
  583. LPUDPROP lpudprop;
  584. LPTSTR lpstzT;
  585. if ((lpUDObj == NULL) ||
  586. (lpData == NULL) ||
  587. (lpsz == NULL))
  588. return FALSE;
  589. // Find the name
  590. lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
  591. if (lpudprop == NULL)
  592. return FALSE;
  593. if (!FUdpropMakeHidden (lpudprop))
  594. return FALSE;
  595. OfficeDirtyUDObj (lpUDObj, TRUE);
  596. return TRUE;
  597. } // FUserDefMakeHidden
  598. ////////////////////////////////////////////////////////////////////////////////
  599. //
  600. // LpudpropFindMatchingName
  601. //
  602. // Purpose:
  603. // Returns a node with a matching name, NULL otherwise.
  604. //
  605. ////////////////////////////////////////////////////////////////////////////////
  606. LPUDPROP PASCAL
  607. LpudpropFindMatchingName
  608. (LPUDOBJ lpUDObj, // Pointer to object
  609. LPTSTR lpsz) // String to search for
  610. {
  611. LPUDPROP lpudprop;
  612. TCHAR sz[256];
  613. BOOL fCopy = FALSE;
  614. if ((lpUDObj == NULL) || (lpData == NULL))
  615. return(NULL);
  616. if (lstrlen(lpsz) > 255)
  617. {
  618. // Truncate on purpose
  619. StringCchCopy( sz, ARRAYSIZE(sz), lpsz );
  620. sz[255] = 0;
  621. fCopy = TRUE;
  622. }
  623. // Check the cache first
  624. if (lpData->lpudpCache != NULL)
  625. {
  626. Assert ((lpData->lpudpCache->lpstzName != NULL));
  627. // lstrcmpi returns 0 if 2 strings are equal.....
  628. if ( !lstrcmpi( fCopy ? sz : lpsz, lpData->lpudpCache->lpstzName ))
  629. {
  630. return lpData->lpudpCache;
  631. }
  632. }
  633. lpudprop = lpData->lpudpHead;
  634. while (lpudprop != NULL)
  635. {
  636. Assert ((lpudprop->lpstzName != NULL));
  637. // lstrcmpi returns 0 if 2 strings are equal.....
  638. if ( !lstrcmpi( fCopy ? sz : lpsz, lpudprop->lpstzName ))
  639. {
  640. // Set the cache to the last node found
  641. lpData->lpudpCache = lpudprop;
  642. return lpudprop;
  643. }
  644. lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
  645. } // while
  646. return NULL;
  647. } // LpudpropFindMatchingName
  648. ////////////////////////////////////////////////////////////////////////////////
  649. //
  650. // LpudpropFindMatchingPID
  651. //
  652. // Purpose:
  653. // Searches the linked-list in the caller-provided UDINFO structure
  654. // for a UDPROP with the requested PropID.
  655. //
  656. // Inputs:
  657. // LPUDOBJ - The UDINFO structure
  658. // PROPID - The PID to search for.
  659. //
  660. // Output:
  661. // The requested LPUDPROP, or NULL if not found.
  662. //
  663. ////////////////////////////////////////////////////////////////////////////////
  664. LPUDPROP PASCAL
  665. LpudpropFindMatchingPID
  666. (LPUDOBJ lpUDObj,
  667. PROPID propid)
  668. {
  669. // ------
  670. // Locals
  671. // ------
  672. LPUDPROP lpudprop = NULL;
  673. BOOL fCopy = FALSE;
  674. // -----
  675. // Begin
  676. // -----
  677. // Validate the inputs.
  678. if ((lpUDObj == NULL) || (lpData == NULL))
  679. {
  680. AssertSz (0, TEXT("Invalid inputs"));
  681. goto Exit;
  682. }
  683. // Check the cache first
  684. if (lpData->lpudpCache != NULL
  685. &&
  686. lpData->lpudpCache->propid == propid)
  687. {
  688. lpudprop = lpData->lpudpCache;
  689. goto Exit;
  690. }
  691. // Search the linked-list.
  692. lpudprop = lpData->lpudpHead;
  693. while (lpudprop != NULL)
  694. {
  695. if (lpudprop->propid == propid)
  696. {
  697. lpData->lpudpCache = lpudprop;
  698. goto Exit;
  699. }
  700. lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
  701. }
  702. // ----
  703. // Exit
  704. // ----
  705. Exit:
  706. return lpudprop;
  707. } // LpudpropFindMatchingPID
  708. ////////////////////////////////////////////////////////////////////////////////
  709. //
  710. // FAddPropToList
  711. //
  712. // Purpose:
  713. // Adds the given object to the list. The type and value must
  714. // be filled in before calling this.
  715. //
  716. // The linked-list we're adding to has one entry for each of
  717. // the user-defined properties. Each entry has the property
  718. // value, it's PID, and it's name. If the property is linked
  719. // to document content, the link name (e.g. a Bookmark name
  720. // in Word) is also in this entry. Note that the property set
  721. // stores the property value as one property, with its name in the
  722. // dictionary, and it stores the link name as a second property.
  723. // Consequently, this routine will be called twice for such
  724. // properties: on the first call we'll create a new entry in the
  725. // linked-list, adding the property ID, name, and value; on the
  726. // second call we'll pull out that entry, and add the link name.
  727. //
  728. // On success, the input lppropvar & lpstatpropstg are cleared.
  729. // On error, all inputs are left unmodified.
  730. //
  731. ////////////////////////////////////////////////////////////////////////////////
  732. BOOL PASCAL
  733. FAddPropToList
  734. (LPUDOBJ lpUDObj,
  735. LPPROPVARIANT lppropvar,
  736. STATPROPSTG *lpstatpropstg,
  737. LPUDPROP lpudprop) // Property to add
  738. {
  739. // ------
  740. // Locals
  741. // ------
  742. BOOL fSuccess = FALSE;
  743. LPTSTR lpstz;
  744. LPUDPROP lpudpT;
  745. BOOL fLink;
  746. Assert(lpUDObj != NULL);
  747. Assert(lpudprop != NULL); // Is this a bogus assert?
  748. Assert(lppropvar != NULL && lpstatpropstg != NULL);
  749. // If the PId has one of the special masks, strip it off
  750. // so the PId will match the normal value.
  751. fLink = lpstatpropstg->propid & PID_LINKMASK;
  752. lpstatpropstg->propid &= ~PID_LINKMASK;
  753. // ------------------------------------------------------------
  754. // See if we can find this property already in the linked-list.
  755. // If we have a name, use that, otherwise use the PID.
  756. // ------------------------------------------------------------
  757. if (lpstatpropstg->lpwstrName != NULL)
  758. {
  759. // Search by name.
  760. // [scotthan] Re: bogus cast to TCHAR in propio.c when this thing
  761. // was read out of the file. If this is an ANSI build, it's going to store
  762. // a TCHAR* value!. So we need to reciprocate the cast...
  763. lpudpT = LpudpropFindMatchingName (lpUDObj, (LPTSTR)lpstatpropstg->lpwstrName );
  764. }
  765. else
  766. {
  767. // Search by PID
  768. lpudpT = LpudpropFindMatchingPID (lpUDObj, lpstatpropstg->propid);
  769. }
  770. // --------------------------------------------------------------
  771. // If this property isn't already in the linked-list, add it now.
  772. // --------------------------------------------------------------
  773. if (lpudpT == NULL)
  774. {
  775. // This should be a named property. If it's not
  776. // named, then it should be a link, and the property
  777. // it links should have been in the linked-list already
  778. // (i.e., the lpudpT should have been non-NULL).
  779. if (lpstatpropstg->lpwstrName == NULL)
  780. {
  781. AssertSz (0, TEXT("Missing name in User-Defined properties"));
  782. goto Exit;
  783. }
  784. // Allocate memory for the property value.
  785. lpudprop->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
  786. if (lpudprop->lppropvar == NULL)
  787. {
  788. goto Exit;
  789. }
  790. // Load the property ID, name, and value.
  791. // Note that if we had an error before here, we left
  792. // the caller's inputs un-touched. Since no more errors
  793. // can occur, we'll never have half-modified data in an
  794. // error case.
  795. lpudprop->propid = lpstatpropstg->propid;
  796. // [scotthan] Re: bogus cast to TCHAR in propio.c when this thing
  797. // was read out of the file. If this is an ANSI build, it's going to store
  798. // a TCHAR* value!. So we need to reciprocate the cast...
  799. lpudprop->lpstzName = (LPTSTR)lpstatpropstg->lpwstrName;
  800. lpstatpropstg->lpwstrName = NULL;
  801. *lpudprop->lppropvar = *lppropvar;
  802. PropVariantInit (lppropvar);
  803. lpData->dwcProps++;
  804. AddNodeToList (lpUDObj, lpudprop);
  805. } // if ((lpudpT = LpudpropFindMatchingName (lpUDInfo, lpstatpropstg->lpwsz)) == NULL)
  806. // --------------------------------------------------------
  807. // Otherwise (this property is already in the linked-list),
  808. // add this new link name or value to the UDPROP.
  809. // --------------------------------------------------------
  810. else
  811. {
  812. // If this is a link being added, then update the link-name in the
  813. // extant property.
  814. if (fLink)
  815. {
  816. // lpudpT points to the entry in our linked-list for this
  817. // property. But it shouldn't already have a link-name (there
  818. // can only be one link-name per property).
  819. if (lpudpT->lpstzLink != NULL)
  820. {
  821. AssertSz (0, TEXT("Invalid property set - link name defined twice"));
  822. goto Exit;
  823. }
  824. // Since this is a link-name, it should be a string.
  825. if (lppropvar->vt != VT_LPTSTR)
  826. {
  827. AssertSz (0, TEXT("Invalid property set - link name isn't a string"));
  828. goto Exit;
  829. }
  830. // Point the UDPROP to the link name, and take ownership
  831. // of it by clearing the caller's pointer.
  832. Assert (lppropvar->pszVal != NULL);
  833. lpudpT->lpstzLink = (LPTSTR) lppropvar->pszVal;
  834. PropVariantInit (lppropvar);
  835. lpData->dwcLinks++;
  836. } // if (fLink)
  837. // Otherwise, this isn't a link name, it's a value. So point the
  838. // UDPROP to it's data.
  839. else
  840. {
  841. *lpudpT->lppropvar = *lppropvar;
  842. PropVariantInit (lppropvar);
  843. } // if (fLink) ... else
  844. } // if ((lpudpT = LpudpropFindMatchingName ... else
  845. fSuccess = TRUE;
  846. Exit:
  847. // Just in case we were given a name that we didn't
  848. // need, clear it now so that the caller knows that
  849. // on success, they needn't worry about the buffers
  850. // pointed to by lppropvar & lpstatpropstg.
  851. if (fSuccess)
  852. {
  853. if (lpstatpropstg->lpwstrName != NULL)
  854. {
  855. CoTaskMemFree (lpstatpropstg->lpwstrName);
  856. lpstatpropstg->lpwstrName = NULL;
  857. }
  858. }
  859. return(fSuccess);
  860. } // FAddPropToList
  861. ////////////////////////////////////////////////////////////////////////////////
  862. //
  863. // AddNodeToList
  864. //
  865. // Purpose:
  866. // Adds the given node to the list.
  867. //
  868. ////////////////////////////////////////////////////////////////////////////////
  869. void PASCAL
  870. AddNodeToList
  871. (LPUDOBJ lpUDObj, // Pointer to object
  872. LPUDPROP lpudprop) // Node to add
  873. {
  874. // Put the new node at the end
  875. if (lpData->lpudpHead != NULL)
  876. {
  877. if (lpData->lpudpHead->llist.lpllistPrev != NULL)
  878. {
  879. ((LPUDPROP) lpData->lpudpHead->llist.lpllistPrev)->llist.lpllistNext = (LPLLIST) lpudprop;
  880. lpudprop->llist.lpllistPrev = lpData->lpudpHead->llist.lpllistPrev;
  881. }
  882. else
  883. {
  884. lpData->lpudpHead->llist.lpllistNext = (LPLLIST) lpudprop;
  885. lpudprop->llist.lpllistPrev = (LPLLIST) lpData->lpudpHead;
  886. }
  887. lpData->lpudpHead->llist.lpllistPrev = (LPLLIST) lpudprop;
  888. }
  889. else
  890. {
  891. lpData->lpudpHead = lpudprop;
  892. lpudprop->llist.lpllistPrev = NULL;
  893. }
  894. lpudprop->llist.lpllistNext = NULL;
  895. lpData->lpudpCache = lpudprop;
  896. } // AddNodeToList
  897. ////////////////////////////////////////////////////////////////////////////////
  898. //
  899. // RemoveFromList
  900. //
  901. // Purpose:
  902. // Removes the given node from the list
  903. //
  904. ////////////////////////////////////////////////////////////////////////////////
  905. static void PASCAL
  906. RemoveFromList
  907. (LPUDOBJ lpUDObj, // Pointer to object
  908. LPUDPROP lpudprop) // The node itself.
  909. {
  910. AssertSz ((lpData->lpudpHead != NULL), TEXT("List is corrupt"));
  911. // If we're removing the cached node, invalidate the cache
  912. if (lpudprop == lpData->lpudpCache)
  913. {
  914. lpData->lpudpCache = NULL;
  915. }
  916. // Be sure the head gets updated, if the node is at the front
  917. if (lpudprop == lpData->lpudpHead)
  918. {
  919. lpData->lpudpHead = (LPUDPROP) lpudprop->llist.lpllistNext;
  920. if (lpData->lpudpHead != NULL)
  921. {
  922. lpData->lpudpHead->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
  923. }
  924. return;
  925. }
  926. // Update the links
  927. if (lpudprop->llist.lpllistNext != NULL)
  928. {
  929. ((LPUDPROP) lpudprop->llist.lpllistNext)->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
  930. }
  931. if (lpudprop->llist.lpllistPrev != NULL)
  932. {
  933. ((LPUDPROP) lpudprop->llist.lpllistPrev)->llist.lpllistNext = lpudprop->llist.lpllistNext;
  934. }
  935. // If it is the last node in the list, be sure the head is updated
  936. if (lpudprop == (LPUDPROP) lpData->lpudpHead->llist.lpllistPrev)
  937. {
  938. lpData->lpudpHead->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
  939. }
  940. } // RemoveFromList
  941. ////////////////////////////////////////////////////////////////////////////////
  942. //
  943. // VUdpropFree
  944. //
  945. // Purpose:
  946. // Free a UDPROP (which is in a linked-list).
  947. //
  948. // Inputs:
  949. // LPUDPROP * - A pointer-to-pointer-to a UDPROP object.
  950. //
  951. // Output:
  952. // None.
  953. //
  954. ////////////////////////////////////////////////////////////////////////////////
  955. VOID
  956. VUdpropFree
  957. (LPUDPROP *lplpudp)
  958. {
  959. // Validate the inputs.
  960. if (lplpudp == NULL || *lplpudp == NULL )
  961. goto Exit;
  962. // If this property has a name, free that buffer.
  963. if ((*lplpudp)->lpstzName)
  964. {
  965. CoTaskMemFree ((*lplpudp)->lpstzName);
  966. }
  967. // If this property has a link-name, free it too.
  968. if ((*lplpudp)->lpstzLink)
  969. {
  970. CoTaskMemFree ((*lplpudp)->lpstzLink);
  971. }
  972. // Clear the property value, which will free any associated
  973. // buffer. Then free the PropVariant itself.
  974. PropVariantClear ((*lplpudp)->lppropvar);
  975. CoTaskMemFree ((*lplpudp)->lppropvar);
  976. CoTaskMemFree (*lplpudp);
  977. *lplpudp = NULL;
  978. Exit:
  979. return;
  980. } // VUdpropFree
  981. ////////////////////////////////////////////////////////////////////////////////
  982. //
  983. // FUdpropUpdate
  984. //
  985. // Purpose:
  986. // Updates the given node with the given data
  987. //
  988. // It's the caller's responsibility to free lpudp if this function
  989. // fails.
  990. //
  991. // Inputs:
  992. // LPUDPROP - The node in the linked-list for this property.
  993. // LPUDOBJ - All User-Defined data (including the properties)
  994. // LPTSTR - The property name.
  995. // LPTSTR - The link-name
  996. // LPVOID - The new value
  997. // UDTYPES - The type of the value.
  998. // BOOL - TRUE if this is a link.
  999. //
  1000. ////////////////////////////////////////////////////////////////////////////////
  1001. static BOOL PASCAL
  1002. FUdpropUpdate
  1003. (LPUDPROP lpudp,
  1004. LPUDOBJ lpUDObj,
  1005. LPTSTR lpszPropName,
  1006. LPTSTR lpszLinkMonik,
  1007. LPVOID lpvValue,
  1008. UDTYPES udtype,
  1009. BOOL fLink)
  1010. {
  1011. // ------
  1012. // Locals
  1013. // ------
  1014. BOOL fSuccess = FALSE;
  1015. // -----
  1016. // Begin
  1017. // -----
  1018. // Validate the inputs.
  1019. if ((lpudp == NULL) ||
  1020. (lpszPropName == NULL) ||
  1021. (lpvValue == NULL) ||
  1022. (fLink && (lpszLinkMonik == NULL)) ||
  1023. (!ISUDTYPE(udtype)))
  1024. {
  1025. goto Exit;
  1026. }
  1027. // Update the property name
  1028. if (!FUdpropSetString (lpudp, lpszPropName, TRUE, TRUE))
  1029. goto Exit;
  1030. // If necessary, allocate a PropVariant for the UDPROPS
  1031. if (lpudp->lppropvar == NULL)
  1032. {
  1033. lpudp->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
  1034. if (lpudp->lppropvar == NULL)
  1035. goto Exit;
  1036. }
  1037. // Put the property value into the PropVariant
  1038. PropVariantClear (lpudp->lppropvar);
  1039. if (!FPropVarLoad (lpudp->lppropvar, (VARTYPE)udtype, lpvValue))
  1040. goto Exit;
  1041. // Update the link name if this is a link, otherwise
  1042. // free any existing link name.
  1043. if (fLink)
  1044. {
  1045. if(!FUdpropSetString (lpudp, lpszLinkMonik, FALSE, FALSE))
  1046. goto Exit;
  1047. }
  1048. else
  1049. {
  1050. VUdpropFreeString (lpudp, FALSE);
  1051. lpData->dwcLinks--;
  1052. }
  1053. // ----
  1054. // Exit
  1055. // ----
  1056. fSuccess = TRUE;
  1057. Exit:
  1058. return(fSuccess);
  1059. } // FUdpropUpdate
  1060. ////////////////////////////////////////////////////////////////////////////////
  1061. //
  1062. // FMakeTmpUDProps
  1063. //
  1064. // Purpose:
  1065. // Create a temporary copy of the User-Defined property data
  1066. //
  1067. ////////////////////////////////////////////////////////////////////////////////
  1068. BOOL
  1069. FMakeTmpUDProps
  1070. (LPUDOBJ lpUDObj) // Pointer to object
  1071. {
  1072. // ------
  1073. // Locals
  1074. // ------
  1075. BOOL fSuccess = FALSE;
  1076. LPUDPROP lpudpCur;
  1077. LPUDPROP lpudpTmpCur;
  1078. DWORD dw;
  1079. LPVOID lpv;
  1080. // -----
  1081. // Begin
  1082. // -----
  1083. // Validate the inputs.
  1084. if ( lpUDObj == NULL || lpData == NULL )
  1085. goto Exit;
  1086. FDeleteTmpUDProps (lpUDObj);
  1087. // Move all the original list data to the tmp list
  1088. lpData->dwcTmpLinks = lpData->dwcLinks;
  1089. lpData->dwcTmpProps = lpData->dwcProps;
  1090. lpData->lpudpTmpHead = lpData->lpudpHead;
  1091. lpData->lpudpTmpCache = lpData->lpudpCache;
  1092. // Reinitialize the object data
  1093. lpData->dwcLinks = 0;
  1094. lpData->dwcProps = 0;
  1095. lpData->lpudpCache = NULL;
  1096. lpudpTmpCur = lpData->lpudpHead = NULL;
  1097. // Remember that we just put all the original data in the tmp ptrs.
  1098. lpudpCur = lpData->lpudpTmpHead;
  1099. // Loop through the old data and copy to the temp list
  1100. while (lpudpCur != NULL)
  1101. {
  1102. // Create a new UDPROP
  1103. lpudpTmpCur = LpudpropCreate();
  1104. if (lpudpTmpCur == NULL)
  1105. goto Exit;
  1106. // Set the name in the UDPROP
  1107. if (!FUdpropSetString (lpudpTmpCur, lpudpCur->lpstzName, FALSE, TRUE))
  1108. goto Exit;
  1109. // If we have a link-name, set it too in the UDPROP
  1110. if (lpudpCur->lpstzLink != NULL)
  1111. {
  1112. if (!FUdpropSetString (lpudpTmpCur, lpudpCur->lpstzLink, FALSE, FALSE))
  1113. goto Exit;
  1114. lpData->dwcLinks++;
  1115. }
  1116. // Allocate a PropVariant to hold the property value.
  1117. lpudpTmpCur->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
  1118. if (lpudpTmpCur->lppropvar == NULL)
  1119. goto Exit;
  1120. // Copy the PropVariant into the temporary UDPROP.
  1121. PropVariantCopy (lpudpTmpCur->lppropvar, lpudpCur->lppropvar);
  1122. // Also show if this is an invalid link or not.
  1123. lpudpTmpCur->fLinkInvalid = lpudpCur->fLinkInvalid;
  1124. // Add this new temporary UDPROP to the linked-list.
  1125. AddNodeToList (lpUDObj, lpudpTmpCur);
  1126. lpData->dwcProps++;
  1127. // Move on to the next property.
  1128. lpudpCur = (LPUDPROP) lpudpCur->llist.lpllistNext;
  1129. } // while (lpudpCur != NULL)
  1130. // ----
  1131. // Exit
  1132. // ----
  1133. fSuccess = TRUE;
  1134. Exit:
  1135. // If there was an error, put everything back and deallocate anything we created
  1136. if (!fSuccess)
  1137. {
  1138. FSwapTmpUDProps (lpUDObj);
  1139. FDeleteTmpUDProps (lpUDObj);
  1140. }
  1141. return fSuccess;
  1142. } // FMakeTmpUDProps
  1143. ////////////////////////////////////////////////////////////////////////////////
  1144. //
  1145. // FSwapTmpUDProps
  1146. //
  1147. // Purpose:
  1148. // Swap the "temp" copy with the real copy of User-Defined property data
  1149. //
  1150. ////////////////////////////////////////////////////////////////////////////////
  1151. BOOL
  1152. FSwapTmpUDProps
  1153. (LPUDOBJ lpUDObj)
  1154. {
  1155. DWORD dwT;
  1156. LPUDPROP lpudpT;
  1157. if ( lpUDObj == NULL || lpData == NULL )
  1158. return FALSE;
  1159. dwT = lpData->dwcLinks;
  1160. lpData->dwcLinks = lpData->dwcTmpLinks;
  1161. lpData->dwcTmpLinks = dwT;
  1162. dwT = lpData->dwcProps;
  1163. lpData->dwcProps = lpData->dwcTmpProps;
  1164. lpData->dwcTmpProps = dwT;
  1165. lpudpT = lpData->lpudpHead;
  1166. lpData->lpudpHead = lpData->lpudpTmpHead;
  1167. lpData->lpudpTmpHead = lpudpT;
  1168. lpudpT = lpData->lpudpCache;
  1169. lpData->lpudpCache = lpData->lpudpTmpCache;
  1170. lpData->lpudpTmpCache = lpudpT;
  1171. return TRUE;
  1172. } // FSwapTmpUDProps
  1173. ////////////////////////////////////////////////////////////////////////////////
  1174. //
  1175. // FDeleteTmpUDProps
  1176. //
  1177. // Purpose:
  1178. // Delete the "temp" copy of the data
  1179. //
  1180. ////////////////////////////////////////////////////////////////////////////////
  1181. BOOL
  1182. FDeleteTmpUDProps
  1183. (LPUDOBJ lpUDObj)
  1184. {
  1185. if ((lpUDObj == NULL) ||
  1186. (lpData == NULL))
  1187. return FALSE;
  1188. FreeUDData (lpUDObj, TRUE);
  1189. return TRUE;
  1190. } // FDeleteTmpU
  1191. ////////////////////////////////////////////////////////////////////////////////
  1192. //
  1193. // FUdpropMakeHidden
  1194. //
  1195. // Purpose:
  1196. // Convert a property in a UDPROP so that it is a hidden
  1197. // property. Properties are considered hidden if the
  1198. // first character in their name is an "_".
  1199. //
  1200. // Inputs:
  1201. // LPUDPROP - The UDPROP to convert.
  1202. //
  1203. // Output:
  1204. // TRUE if successful.
  1205. //
  1206. ////////////////////////////////////////////////////////////////////////////////
  1207. static BOOL PASCAL
  1208. FUdpropMakeHidden (LPUDPROP lpudprop)
  1209. {
  1210. // ------
  1211. // Locals
  1212. // ------
  1213. BOOL fSuccess = FALSE;
  1214. ULONG cch;
  1215. LPTSTR lpstzOld = NULL;
  1216. // -----
  1217. // Begin
  1218. // -----
  1219. // Intialize
  1220. Assert (lpudprop != NULL);
  1221. if (lpudprop->lpstzName == NULL)
  1222. goto Exit;
  1223. // Keep the old name.
  1224. lpstzOld = lpudprop->lpstzName;
  1225. // How many characters do we need in the new string?
  1226. cch = lstrlen(lpstzOld) + 2; // Includes the NULL & prefix
  1227. // Allocate the memory.
  1228. lpudprop->lpstzName = CoTaskMemAlloc (cch * sizeof(TCHAR));
  1229. if (lpudprop->lpstzName == NULL)
  1230. goto Exit;
  1231. // Set the "_" prefix to indicate this is a hidden property.
  1232. lpudprop->lpstzName[0] = HIDDENPREFIX;
  1233. // Copy the original property name after the prefix in the UDPROP.
  1234. StringCchCopy( &lpudprop->lpstzName[1], cch - 1, lpstzOld ); // One chacter less than cch to accout for hidden prefix.
  1235. // Free the old buffer
  1236. CoTaskMemFree (lpstzOld);
  1237. // ----
  1238. // Exit
  1239. // ----
  1240. fSuccess = TRUE;
  1241. Exit:
  1242. // If there was an error, ensure that the UDPROP is left as
  1243. // we found it.
  1244. if (!fSuccess)
  1245. {
  1246. if (lpstzOld != NULL)
  1247. {
  1248. if (lpudprop->lpstzName != NULL)
  1249. {
  1250. CoTaskMemFree (lpudprop->lpstzName);
  1251. }
  1252. lpudprop->lpstzName = lpstzOld;
  1253. }
  1254. }
  1255. return (fSuccess);
  1256. } // FUdpropMakeHidden
  1257. ////////////////////////////////////////////////////////////////////////////////
  1258. //
  1259. // FUdpropSetString
  1260. //
  1261. // Purpose:
  1262. // Set the name or link-name string in a UDPROP.
  1263. // If the UDPROP already contains the string, free
  1264. // it.
  1265. //
  1266. // Inputs:
  1267. // LPUDPROP - A UDPROP (a property in the linked-list)
  1268. // LPTSTR - The new name or link-name
  1269. // BOOL - True => limit the length of the string to BUFMAX characters
  1270. // (including the NULL terminator)
  1271. // BOOL - True => set the (property) name, False => set the link-name
  1272. //
  1273. ////////////////////////////////////////////////////////////////////////////////
  1274. static BOOL PASCAL
  1275. FUdpropSetString
  1276. (LPUDPROP lpudp,
  1277. LPTSTR lptstr,
  1278. BOOL fLimitLength,
  1279. BOOL fName)
  1280. {
  1281. // ------
  1282. // Locals
  1283. // ------
  1284. BOOL fSuccess = FALSE; // Return value
  1285. LPTSTR lptstrNew = NULL; // Pointed to be the UDPROP.
  1286. ULONG cch, cb;
  1287. // ----------
  1288. // Initialize
  1289. // ----------
  1290. // Validate the inputs.
  1291. if (lpudp == NULL || lptstr == NULL)
  1292. {
  1293. goto Exit;
  1294. }
  1295. // ----------------
  1296. // Set the new name
  1297. // ----------------
  1298. // Calculate the sizes.
  1299. cch = lstrlen(lptstr);
  1300. if (fLimitLength && cch >= BUFMAX)
  1301. {
  1302. cch = BUFMAX - 1;
  1303. }
  1304. cb = (cch + 1) * sizeof(TCHAR); // Leave room for the NULL.
  1305. // Allocate new memory.
  1306. lptstrNew = CoTaskMemAlloc (cb);
  1307. if (lptstrNew == NULL)
  1308. {
  1309. goto Exit;
  1310. }
  1311. // Copy the buffer (the buffer size is cch+1 including the NULL)
  1312. // Also, terminate the target string, since it may be a truncation
  1313. // of the source string.
  1314. // Purposely truncate
  1315. StringCchCopy( lptstrNew, cch + 1, lptstr );
  1316. lptstrNew[cch] = TEXT('\0');
  1317. // Put this new buffer in the UDPROP.
  1318. if (fName)
  1319. {
  1320. lpudp->lpstzName = lptstrNew;
  1321. }
  1322. else
  1323. {
  1324. lpudp->lpstzLink = lptstrNew;
  1325. }
  1326. lptstrNew = NULL;
  1327. // ----
  1328. // Exit
  1329. // ----
  1330. fSuccess = TRUE;
  1331. Exit:
  1332. if (lptstrNew != NULL)
  1333. {
  1334. CoTaskMemFree (lptstrNew);
  1335. }
  1336. return (fSuccess);
  1337. } // FUdpropSetString
  1338. ////////////////////////////////////////////////////////////////////////////////
  1339. //
  1340. // VUdpropFreeString
  1341. //
  1342. // Purpose:
  1343. // Free one of the two strings in a UDPROP - the
  1344. // name string or the link-name string. It is not
  1345. // considered an error if either the UDPROP or the
  1346. // string doesn't exist.
  1347. //
  1348. // Inputs:
  1349. // LPUDPROP - The UDPROP containing the strings.
  1350. // BOOL - TRUE indicates we should free the
  1351. // name, FALSE indicates we should free
  1352. // the link name.
  1353. //
  1354. // Output:
  1355. // None.
  1356. //
  1357. ////////////////////////////////////////////////////////////////////////////////
  1358. static void PASCAL
  1359. VUdpropFreeString
  1360. (LPUDPROP lpudp,
  1361. BOOL fName)
  1362. {
  1363. // Is this really a UDPROP?
  1364. if (lpudp != NULL)
  1365. {
  1366. // Should we delete the name?
  1367. if (fName && lpudp->lpstzName)
  1368. {
  1369. CoTaskMemFree (lpudp->lpstzName);
  1370. lpudp->lpstzName = NULL;
  1371. }
  1372. // Should we delete the link name?
  1373. else if (!fName && lpudp->lpstzLink)
  1374. {
  1375. CoTaskMemFree (lpudp->lpstzLink);
  1376. lpudp->lpstzLink = NULL;
  1377. }
  1378. } // if (lpudp != NULL)
  1379. return;
  1380. } // VUdpropFreeString
  1381. /////////////////////////////////////////////////////////////////////////////////////
  1382. //
  1383. // LpudpropCreate
  1384. //
  1385. // Purpose:
  1386. // Create a new UDPROP structure (an element of a linked-
  1387. // list, and holds information about a single property).
  1388. //
  1389. // Inputs:
  1390. // None
  1391. //
  1392. // Output:
  1393. // A LPUDPROP if successful, NULL otherwise.
  1394. //
  1395. /////////////////////////////////////////////////////////////////////////////////////
  1396. LPUDPROP
  1397. LpudpropCreate ( void )
  1398. {
  1399. // Create a buffer for the UDPROP
  1400. LPUDPROP lpudp = CoTaskMemAlloc (sizeof(UDPROP));
  1401. // Zero the buffer.
  1402. if (lpudp != NULL)
  1403. {
  1404. ZeroMemory(lpudp, sizeof(UDPROP));
  1405. }
  1406. return (lpudp);
  1407. } // LpudpropCreate
  1408. ////////////////////////////////////////////////////////////////////////////////
  1409. //
  1410. // LppropvarUserDefGetPropVal
  1411. //
  1412. // Purpose:
  1413. // Return a PropVariant pointer for the requested
  1414. // property (requested by property name).
  1415. //
  1416. // Inputs:
  1417. // LPUDOBJ - All UD data (including properties)
  1418. // LPTSTR - The name of the desired property
  1419. // BOOL * - True if this is a link.
  1420. // BOOL * - True if this link is invalid.
  1421. //
  1422. // Output:
  1423. // An LPPROPVARINT, or NULL if there was an error.
  1424. //
  1425. ////////////////////////////////////////////////////////////////////////////////
  1426. DLLEXPORT LPPROPVARIANT
  1427. LppropvarUserDefGetPropVal
  1428. (LPUDOBJ lpUDObj, // Pointer to object
  1429. LPTSTR lpszProp, // Property string
  1430. BOOL *pfLink, // Indicates a link
  1431. BOOL *pfLinkInvalid) // Is the link invalid
  1432. {
  1433. // ------
  1434. // Locals
  1435. // ------
  1436. LPUDPROP lpudprop;
  1437. LPPROPVARIANT lppropvar;
  1438. // --------------
  1439. // Initialization
  1440. // --------------
  1441. if ((lpUDObj == NULL) ||
  1442. (lpData == NULL) ||
  1443. (lpszProp == NULL))
  1444. {
  1445. return NULL;
  1446. }
  1447. // ---------------------------------
  1448. // Find the node that has this name.
  1449. // ---------------------------------
  1450. lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
  1451. if (lpudprop == NULL)
  1452. return NULL;
  1453. // Is this a link?
  1454. if (pfLink != NULL)
  1455. {
  1456. *pfLink = (lpudprop->lpstzLink != NULL);
  1457. }
  1458. // Is this an invalid link? (In the Shell, all properties are
  1459. // invalid).
  1460. if (pfLinkInvalid != NULL)
  1461. {
  1462. *pfLinkInvalid = lpudprop->fLinkInvalid = TRUE;
  1463. }
  1464. // ----
  1465. // Exit
  1466. // ----
  1467. return (lpudprop->lppropvar);
  1468. } // LppropvarUserDefGetPropVal
  1469. ////////////////////////////////////////////////////////////////////////////////
  1470. //
  1471. // LppropvarUserDefGetIteratorVal
  1472. //
  1473. // Purpose:
  1474. // Given an iterator value, get the property value.
  1475. //
  1476. // Inputs:
  1477. // LPUDITER - The Iterator value.
  1478. // BOOL * - Set to True if this value is a link.
  1479. // BOLL * - Set to True if this value is invalid link.
  1480. //
  1481. // Outputs:
  1482. // LPPROPVARIANT of the property value.
  1483. //
  1484. ////////////////////////////////////////////////////////////////////////////////
  1485. DLLEXPORT LPPROPVARIANT
  1486. LppropvarUserDefGetIteratorVal
  1487. (LPUDITER lpUDIter,
  1488. BOOL *pfLink,
  1489. BOOL *pfLinkInvalid )
  1490. {
  1491. // Validate the inputs
  1492. if ((lpUDIter == NULL) ||
  1493. (lpUDIter->lpudp == NULL))
  1494. return NULL;
  1495. // Is this a Link?
  1496. if (pfLink != NULL)
  1497. {
  1498. *pfLink = (lpUDIter->lpudp->lpstzLink != NULL);
  1499. }
  1500. // Is this an invalid link?
  1501. if (pfLinkInvalid != NULL)
  1502. {
  1503. *pfLinkInvalid = lpUDIter->lpudp->fLinkInvalid;
  1504. }
  1505. // Return a pointer to the PropVariant
  1506. return (lpUDIter->lpudp->lppropvar);
  1507. } // LpvoidUserDefGetIteratorVal