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.

1993 lines
58 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994
  5. //
  6. // File: ntpropb.cxx
  7. //
  8. // Contents: Nt property set implementation based on OLE Appendix B.
  9. //
  10. // History:
  11. // 5-Dec-94 vich created
  12. // 09-May-96 MikeHill Use the 'boolVal' member of PropVariant,
  13. // rather than the member named 'bool'
  14. // (which is a reserved keyword).
  15. // 22-May-96 MikeHill - Get the OSVersion during a CreatePropSet.
  16. // - Let CPropSetStm allocate prop name buffers.
  17. // 07-Jun-96 MikeHill - Correct ClipData.cbSize to include
  18. // sizeof(ulClipFmt).
  19. // - Removed unnecessary Flushes.
  20. // - Take the psstm lock on RtlClosePropSet.
  21. // 12-Jun-96 MikeHill - Fix locking in RtlClosePropertySet.
  22. // - VT_I1 support (under ifdefs)
  23. // 25-Jul-96 MikeHill - Removed Win32 SEH.
  24. // - BSTRs & prop names: WCHAR => OLECHAR.
  25. // - Added RtlOnMappedStreamEvent
  26. // - Enabled for use in "iprop.dll".
  27. // 03-Mar-98 MikeHill - Chagned "Pr" routines to "Stg".
  28. // 06-May-98 MikeHill - Removed UnicodeCallouts.
  29. // - Use CoTaskMem rather than new/delete.
  30. // - Added support for VT_VECTOR|VT_I1
  31. // 18-May-98 MikeHill - Fixed typos.
  32. // 11-June-98 MikeHIll - Removed some old Cairo code.
  33. // - Dbg output.
  34. // - Add a pCodePage to PrSetProperties.
  35. //
  36. //---------------------------------------------------------------------------
  37. #include <pch.cxx>
  38. #include "propvar.h"
  39. #include <olechar.h>
  40. #include <stgprop.h>
  41. #define Dbg DEBTRACE_NTPROP
  42. #define DbgS(s) (NT_SUCCESS(s)? Dbg : DEBTRACE_ERROR)
  43. #if DBG
  44. ULONG DebugLevel = DEBTRACE_ERROR;
  45. //ULONG DebugLevel = DEBTRACE_ERROR | DEBTRACE_CREATESTREAM;
  46. //ULONG DebugLevel = DEBTRACE_ERROR | MAXULONG;
  47. ULONG DebugIndent;
  48. ULONG cAlloc;
  49. ULONG cFree;
  50. #endif
  51. #if defined(WINNT) && !defined(IPROPERTY_DLL)
  52. GUID guidStorage = PSGUID_STORAGE;
  53. #endif // #if defined(WINNT) && !defined(IPROPERTY_DLL)
  54. //+---------------------------------------------------------------------------
  55. // Function: UnLock, private
  56. //
  57. // Synopsis: Unlock a PropertySetStream, and return the
  58. // more severe of two NTSTATUSs; the result of
  59. // the Unlock, or the one passed in by the caller.
  60. //
  61. // Arguments: [ppsstm] -- The CPropertySetStream to unlock
  62. // [Status] -- NTSTATUS
  63. //
  64. // Returns: NTSTATUS
  65. //---------------------------------------------------------------------------
  66. inline NTSTATUS
  67. Unlock( CPropertySetStream *ppsstm, NTSTATUS Status )
  68. {
  69. NTSTATUS StatusT = ppsstm->Unlock();
  70. // Note that the statement below preserves
  71. // success codes in the original Status unless
  72. // there was an error in the Unlock.
  73. if( NT_SUCCESS(Status) && !NT_SUCCESS(StatusT) )
  74. Status = StatusT;
  75. return( Status );
  76. }
  77. //+---------------------------------------------------------------------------
  78. // Function: PrCreatePropertySet, public
  79. //
  80. // Synopsis: Allocate and initialize a property set context
  81. //
  82. // Arguments: [ms] -- Nt Mapped Stream
  83. // [Flags] -- *one* of READ/WRITE/CREATE/CREATEIF/DELETE
  84. // [pguid] -- property set guid (create only)
  85. // [pclsid] -- CLASSID of propset code (create only)
  86. // [ma] -- caller's memory allocator
  87. // [LocaleId] -- Locale Id (create only)
  88. // [pOSVersion] -- pointer to the OS Version header field
  89. // [pCodePage] -- pointer to new/returned CodePage of propset
  90. // [pgrfBehavior] -- pointer to PROPSET_BEHAVIOR_* flags
  91. // [pnp] -- pointer to returned property set context
  92. //
  93. // Returns: Status code
  94. //---------------------------------------------------------------------------
  95. NTSTATUS
  96. PrCreatePropertySet(
  97. IN NTMAPPEDSTREAM ms, // Nt Mapped Stream
  98. IN USHORT Flags, // *one* of READ/WRITE/CREATE/CREATEIF/DELETE
  99. OPTIONAL IN GUID const *pguid, // property set guid (create only)
  100. OPTIONAL IN GUID const *pclsid, // CLASSID of propset code (create only)
  101. IN NTMEMORYALLOCATOR ma, // caller's memory allocator
  102. IN ULONG LocaleId, // Locale Id (create only)
  103. OPTIONAL OUT ULONG *pOSVersion, // OS Version from the propset header
  104. IN OUT USHORT *pCodePage, // IN: CodePage of property set (create only)
  105. // OUT: CodePage of property set (always)
  106. IN OUT DWORD *pgrfBehavior, // IN: Behavior of property set (create only)
  107. // OUT: Behavior of property set (always)
  108. OUT NTPROP *pnp) // pointer to return prop set context
  109. {
  110. NTSTATUS Status;
  111. IMappedStream *pmstm = (IMappedStream *) ms;
  112. CPropertySetStream *ppsstm = NULL;
  113. BOOLEAN fLocked = FALSE;
  114. BOOLEAN fOpened = FALSE;
  115. IFDBG( HRESULT &hr = Status );
  116. propITraceStatic( "PrCreatePropertySet" );
  117. propTraceParameters(( "ms=%p, f=0x%x, codepage=0x%x)", ms, Flags, *pCodePage ));
  118. *pnp = NULL;
  119. Status = STATUS_INVALID_PARAMETER;
  120. if( pOSVersion != NULL )
  121. *pOSVersion = PROPSETHDR_OSVERSION_UNKNOWN;
  122. // Validate the input flags
  123. if (Flags & ~(CREATEPROP_MODEMASK | CREATEPROP_NONSIMPLE))
  124. {
  125. propDbg(( DEB_ERROR, "PrCreatePropertySet(ms=%x, Flags=%x) ==> bad flags!\n",
  126. ms, Flags));
  127. goto Exit;
  128. }
  129. PROPASSERT( (0 == *pgrfBehavior) || (CREATEPROP_CREATE & Flags) );
  130. PROPASSERT( !(*pgrfBehavior & ~PROPSET_BEHAVIOR_CASE_SENSITIVE) );
  131. switch (Flags & CREATEPROP_MODEMASK)
  132. {
  133. case CREATEPROP_DELETE:
  134. case CREATEPROP_CREATE:
  135. case CREATEPROP_CREATEIF:
  136. case CREATEPROP_WRITE:
  137. if (!pmstm->IsWriteable())
  138. {
  139. Status = STATUS_ACCESS_DENIED;
  140. goto Exit;
  141. }
  142. // FALLTHROUGH
  143. case CREATEPROP_READ:
  144. case CREATEPROP_UNKNOWN:
  145. if (ma == NULL)
  146. {
  147. goto Exit;
  148. }
  149. break;
  150. default:
  151. propDbg(( DEB_ERROR, "PrCreatePropertySet(ms=%x, Flags=%x) ==> invalid mode!\n",
  152. ms, Flags));
  153. goto Exit;
  154. }
  155. Status = pmstm->Lock((Flags & CREATEPROP_MODEMASK) != CREATEPROP_READ);
  156. if( !NT_SUCCESS(Status) ) goto Exit;
  157. fLocked = TRUE;
  158. ppsstm = new CPropertySetStream( Flags, pmstm, (PMemoryAllocator *) ma);
  159. if (ppsstm == NULL)
  160. {
  161. Status = STATUS_INSUFFICIENT_RESOURCES;
  162. goto Exit;
  163. }
  164. else
  165. {
  166. ppsstm->Open(pguid, pclsid, LocaleId,
  167. pOSVersion, *pCodePage, *pgrfBehavior, &Status);
  168. if( !NT_SUCCESS(Status) ) goto Exit;
  169. }
  170. // ----
  171. // Exit
  172. // ----
  173. Exit:
  174. if (fLocked)
  175. {
  176. NTSTATUS StatusT = Status;
  177. if( ppsstm )
  178. ppsstm->Unlock();
  179. else
  180. pmstm->Unlock();
  181. if( NT_SUCCESS(Status) && !NT_SUCCESS(StatusT) )
  182. Status = StatusT;
  183. }
  184. // If we were successfull with everything, set the
  185. // out-parameters.
  186. if( NT_SUCCESS(Status) )
  187. {
  188. // pOSVersion has already been set.
  189. *pCodePage = ppsstm->GetCodePage();
  190. *pgrfBehavior = ppsstm->GetBehavior();
  191. *pnp = (NTPROP) ppsstm;
  192. }
  193. // Otherwise, if we created a CPropertySetStream object, but
  194. // the overall operation failed, we must close/delete
  195. // the object. Note that we must do this after
  196. // the above unlock, since ppsstm will be gone after
  197. // this call.
  198. else if( NULL != ppsstm )
  199. {
  200. PrClosePropertySet((NTPROP) ppsstm);
  201. }
  202. if( STATUS_PROPSET_NOT_FOUND == Status )
  203. propSuppressExitErrors();
  204. return(Status);
  205. }
  206. //+---------------------------------------------------------------------------
  207. // Function: PrClosePropertySet, public
  208. //
  209. // Synopsis: Delete a property set context
  210. //
  211. // Arguments: [np] -- property set context
  212. //
  213. // Returns: Status code
  214. //---------------------------------------------------------------------------
  215. NTSTATUS
  216. PrClosePropertySet(
  217. IN NTPROP np) // property set context
  218. {
  219. NTSTATUS Status = STATUS_SUCCESS;
  220. BOOL fLocked = FALSE;
  221. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  222. IFDBG( HRESULT &hr = Status );
  223. propITraceStatic( "PrClosePropertySet" );
  224. propTraceParameters(( "np=%p", np ));
  225. // Lock the mapped stream, because this close
  226. // may trigger a Write.
  227. Status = ppsstm->Lock(TRUE);
  228. if( !NT_SUCCESS(Status) ) goto Exit;
  229. fLocked = TRUE;
  230. // Note that we haven't ReOpen-ed the mapped stream. This
  231. // isn't required for the CPropertySetStream::Close method.
  232. ppsstm->Close(&Status);
  233. if( !NT_SUCCESS(Status) ) goto Exit;
  234. // ----
  235. // Exit
  236. // ----
  237. Exit:
  238. if (fLocked)
  239. Status = Unlock( ppsstm, Status );
  240. if( STG_E_REVERTED == Status )
  241. propSuppressExitErrors();
  242. delete ppsstm;
  243. return(Status);
  244. }
  245. //+---------------------------------------------------------------------------
  246. // Function: PrOnMappedStreamEvent, public
  247. //
  248. // Synopsis: Handle a MappedStream event. Every such
  249. // event requires a byte-swap of the property set
  250. // headers.
  251. //
  252. // Arguments: [np] -- property set context
  253. // [pbuf] -- property set buffer
  254. // [cbstm] -- size of mapped stream (or CBSTM_UNKNOWN)
  255. //
  256. // NOTE: It is assumed that the caller has already taken
  257. // the CPropertySetStream::Lock.
  258. //
  259. // Returns: Status code
  260. //---------------------------------------------------------------------------
  261. NTSTATUS
  262. PrOnMappedStreamEvent(
  263. IN VOID * np, // property set context (an NTPROP)
  264. IN VOID *pbuf, // property set buffer
  265. IN ULONG cbstm )
  266. {
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  269. IFDBG( HRESULT &hr = Status );
  270. propITraceStatic( "PrOnMappedStreamEvent" );
  271. propTraceParameters(( "np=%p, pbuf=%p, cbstm=%lu", np, pbuf, cbstm ));
  272. // Byte-swap the property set headers.
  273. ppsstm->ByteSwapHeaders((PROPERTYSETHEADER*) pbuf, cbstm, &Status );
  274. if( !NT_SUCCESS(Status) ) goto Exit;
  275. // ----
  276. // Exit
  277. // ----
  278. Exit:
  279. return(Status);
  280. } // PrOnMappedStreamEvent()
  281. //+---------------------------------------------------------------------------
  282. // Function: PrFlushPropertySet, public
  283. //
  284. // Synopsis: Flush property set changes to disk
  285. //
  286. // Arguments: [np] -- property set context
  287. //
  288. // Returns: Status code
  289. //---------------------------------------------------------------------------
  290. NTSTATUS
  291. PrFlushPropertySet(
  292. IN NTPROP np) // property set context
  293. {
  294. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  295. NTSTATUS Status = STATUS_SUCCESS;
  296. BOOL fLocked = FALSE;
  297. IFDBG( HRESULT &hr = Status );
  298. propITraceStatic( "PrFlushPropertySet" );
  299. propTraceParameters(( "np=%p", np ));
  300. Status = ppsstm->Lock(TRUE);
  301. if( !NT_SUCCESS(Status) ) goto Exit;
  302. fLocked = TRUE;
  303. if (ppsstm->IsModified())
  304. {
  305. ppsstm->ReOpen(&Status); // Reload header/size info
  306. if( !NT_SUCCESS(Status) ) goto Exit;
  307. ppsstm->Validate(&Status);
  308. if( !NT_SUCCESS(Status) ) goto Exit;
  309. ppsstm->Flush(&Status);
  310. if( !NT_SUCCESS(Status) ) goto Exit;
  311. ppsstm->Validate(&Status);
  312. if( !NT_SUCCESS(Status) ) goto Exit;
  313. }
  314. Exit:
  315. if( fLocked )
  316. Status = Unlock( ppsstm, Status );
  317. return(Status);
  318. }
  319. //+---------------------------------------------------------------------------
  320. // Function: MapNameToPropId, private
  321. //
  322. // Synopsis: Find an available propid and map it to the passed name
  323. //
  324. // Arguments: [ppsstm] -- property set stream
  325. // [CodePage] -- property set codepage
  326. // [aprs] -- array of property specifiers
  327. // [cprop] -- count of property specifiers
  328. // [iprop] -- index of propspec with name to map
  329. // [pidStart] -- first PROPID to start mapping attempts
  330. // [pstatus] -- NTSTATUS code
  331. //
  332. // Returns: PROPID mapped to passed name
  333. //
  334. // Note: Find the first unused propid starting at pidStart.
  335. //---------------------------------------------------------------------------
  336. PROPID
  337. MapNameToPropId(
  338. IN CPropertySetStream *ppsstm, // property set stream
  339. IN USHORT CodePage,
  340. IN PROPSPEC const aprs[], // array of property specifiers
  341. IN ULONG cprop,
  342. IN ULONG iprop,
  343. IN PROPID pidStart,
  344. OUT NTSTATUS *pstatus)
  345. {
  346. PROPID pid = PID_ILLEGAL;
  347. const OLECHAR *poszName = NULL;
  348. OLECHAR *poszNameFromDictionary = NULL;
  349. ULONG cbName;
  350. *pstatus = STATUS_SUCCESS;
  351. PROPASSERT(aprs[iprop].ulKind == PRSPEC_LPWSTR);
  352. poszName = aprs[iprop].lpwstr;
  353. PROPASSERT(IsOLECHARString( poszName, MAXULONG ));
  354. IFDBG( HRESULT &hr = *pstatus );
  355. propITraceStatic( "MapNameToPropId" );
  356. propTraceParameters(( "ppsstm=%p, CodePage=%d, aprs=%p, cprop=%d, iprop=%d, pidStart=%d",
  357. ppsstm, CodePage, aprs, cprop, iprop, pidStart ));
  358. // Starting with the caller-provided PID, search sequentially
  359. // until we find a PID we can use.
  360. for (pid = pidStart; ; pid++)
  361. {
  362. ULONG i;
  363. // The caller must specify a starting propid of 2 or larger, and we
  364. // must not increment into the reserved propids.
  365. if (pid == PID_DICTIONARY ||
  366. pid == PID_CODEPAGE ||
  367. pid < PID_FIRST_USABLE)
  368. {
  369. *pstatus = STATUS_INVALID_PARAMETER;
  370. goto Exit;
  371. }
  372. // Do not assign any propids that explitly appear in the array of
  373. // propspecs involved in this PrSetProperties call, nor any propids
  374. // that are associated with any names in the propspec array.
  375. for (i = 0; i < cprop; i++)
  376. {
  377. if (i != iprop) // skip the entry we are mapping
  378. {
  379. // Is the current PID in the PropSpec[]?
  380. if (aprs[i].ulKind == PRSPEC_PROPID &&
  381. aprs[i].propid == pid)
  382. {
  383. goto nextpid; // skip colliding pid
  384. }
  385. // Is the current PID already used in the property set?
  386. if (aprs[i].ulKind == PRSPEC_LPWSTR &&
  387. ppsstm->QueryPropid(aprs[i].lpwstr, pstatus) == pid)
  388. {
  389. goto nextpid; // skip colliding pid
  390. }
  391. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  392. }
  393. } // for (i = 0; i < cprop; i++)
  394. // Do not assign any propids that currently map to any name.
  395. // Note that the property name we are mapping does not appear in the
  396. // dictionary -- the caller checked for this case already.
  397. if( ppsstm->QueryPropertyNames( 1, &pid, &poszNameFromDictionary, pstatus ))
  398. {
  399. CoTaskMemFree( poszNameFromDictionary );
  400. poszNameFromDictionary = NULL;
  401. }
  402. else
  403. {
  404. // The property name could not be found in the dictionary.
  405. ULONG cbT;
  406. SERIALIZEDPROPERTYVALUE const *pprop;
  407. PROPASSERT( NULL == poszNameFromDictionary );
  408. // Was the name not found due to an error in QueryPropertyNameBuf?
  409. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  410. // Do not assign any propids that currently have a property value.
  411. pprop = ppsstm->GetValue(pid, &cbT, pstatus);
  412. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  413. if (pprop == NULL)
  414. {
  415. // There was no property value corresponding to this PID.
  416. DebugTrace(0, Dbg, (
  417. "MapNameToPropId(Set Entry: pid=%x, name=L'%ws')\n",
  418. pid,
  419. poszName));
  420. // Add the caller-provided name to the dictionary, using
  421. // the PID that we now know is nowhere in use.
  422. ppsstm->SetPropertyNames(1, &pid, &poszName, pstatus);
  423. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  424. ppsstm->Validate(pstatus);
  425. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  426. break;
  427. } // if (pprop == NULL)
  428. } // if (!ppsstm->QueryPropertyNameBuf(pid, awcName, &cbName, pstatus))
  429. nextpid:
  430. ;
  431. } // for (pid = pidStart; ; pid++)
  432. Exit:
  433. if( NULL != poszNameFromDictionary )
  434. CoTaskMemFree( poszNameFromDictionary );
  435. return(pid);
  436. }
  437. //+---------------------------------------------------------------------------
  438. // Function: ConvertVariantToPropInfo, private
  439. //
  440. // Synopsis: Convert variant property values to PROPERTY_INFORMATION values
  441. //
  442. // Arguments: [ppsstm] -- property set stream
  443. // [cprop] -- property count
  444. // [pidNameFirst] -- first PROPID for new named properties
  445. // [aprs] -- array of property specifiers
  446. // [apid] -- buffer for array of propids
  447. // [avar] -- array of PROPVARIANTs
  448. // [apinfo] -- output array of property info
  449. // [pcIndirect] -- output count of indirect properties
  450. //
  451. // Returns: None
  452. //
  453. // Note: If pcIndirect is NULL,
  454. //---------------------------------------------------------------------------
  455. VOID
  456. ConvertVariantToPropInfo(
  457. IN CPropertySetStream *ppsstm, // property set stream
  458. IN ULONG cprop, // property count
  459. IN PROPID pidNameFirst, // first PROPID for new named properties
  460. IN PROPSPEC const aprs[], // array of property specifiers
  461. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  462. OPTIONAL IN PROPVARIANT const avar[],// array of properties+values
  463. OUT PROPERTY_INFORMATION *apinfo, // output array of property info
  464. OUT ULONG *pcIndirect, // output count of indirect properties
  465. OUT NTSTATUS *pstatus )
  466. {
  467. *pstatus = STATUS_SUCCESS;
  468. USHORT CodePage = ppsstm->GetCodePage();
  469. PROPID pidStart = pidNameFirst;
  470. ULONG iprop;
  471. IFDBG( HRESULT &hr = *pstatus );
  472. propITraceStatic( "ConvertVariantToPropInfo" );
  473. propTraceParameters(( "ppsstm=%p, cprop=%d, pidNameFirst=%d, aprs=%p, apid=%p, avar=%p, apinfo=%p, pcIndirect=%p",
  474. ppsstm, cprop, pidNameFirst, aprs, apid, avar, apinfo, pcIndirect ));
  475. if (pcIndirect != NULL)
  476. {
  477. *pcIndirect = 0;
  478. }
  479. for (iprop = 0; iprop < cprop; iprop++)
  480. {
  481. PROPID pid;
  482. ULONG cbprop;
  483. switch(aprs[iprop].ulKind)
  484. {
  485. case PRSPEC_LPWSTR:
  486. {
  487. PROPASSERT(IsOLECHARString(aprs[iprop].lpwstr, MAXULONG));
  488. pid = ppsstm->QueryPropid(aprs[iprop].lpwstr, pstatus);
  489. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  490. if (pid == PID_ILLEGAL && avar != NULL)
  491. {
  492. pid = MapNameToPropId(
  493. ppsstm,
  494. CodePage,
  495. aprs,
  496. cprop,
  497. iprop,
  498. pidStart,
  499. pstatus);
  500. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  501. pidStart = pid + 1;
  502. }
  503. break;
  504. }
  505. case PRSPEC_PROPID:
  506. pid = aprs[iprop].propid;
  507. break;
  508. default:
  509. PROPASSERT(!"Bad ulKind");
  510. *pstatus = STATUS_INVALID_PARAMETER;
  511. goto Exit;
  512. break;
  513. }
  514. if (apid != NULL)
  515. {
  516. apid[iprop] = pid;
  517. }
  518. // StgConvertVariantToProperty returns NULL on overflow and
  519. // Raises on bad data.
  520. cbprop = 0; // Assume property deletion
  521. if (pid != PID_ILLEGAL && avar != NULL)
  522. {
  523. StgConvertVariantToPropertyNoEH(
  524. &avar[iprop],
  525. CodePage,
  526. NULL, // Don't actualy convert. We just want to calc cbprop.
  527. &cbprop,
  528. pid,
  529. FALSE, FALSE, // Not a vector or array recursive call
  530. pcIndirect,
  531. NULL, // Don't check for min format version required yet
  532. pstatus);
  533. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  534. PROPASSERT(cbprop == DwordAlign(cbprop));
  535. }
  536. apinfo[iprop].cbprop = cbprop;
  537. apinfo[iprop].pid = pid;
  538. } // for (iprop = 0; iprop < cprop; iprop++)
  539. // ----
  540. // Exit
  541. // ----
  542. Exit:
  543. if( STATUS_NOT_SUPPORTED == *pstatus )
  544. propSuppressExitErrors();
  545. return;
  546. }
  547. //+---------------------------------------------------------------------------
  548. // Function: BuildIndirectIndexArray, private
  549. //
  550. // Synopsis: Set property values for a property set
  551. //
  552. // Arguments: [cprop] -- count of properties in avar
  553. // [cAlloc] -- max count of indirect properties
  554. // [cIndirect] -- count of indirect properties in avar
  555. // [avar] -- array of PROPVARIANTs
  556. // [ppip] -- ptr to ptr to Indirect property structures
  557. //
  558. // Returns: None
  559. //---------------------------------------------------------------------------
  560. VOID
  561. BuildIndirectIndexArray(
  562. IN ULONG cprop, // count of properties in avar
  563. IN ULONG cAlloc, // max count of indirect properties
  564. IN ULONG cIndirect, // count of indirect properties in avar
  565. IN PROPVARIANT const avar[],// array of properties+values
  566. OPTIONAL OUT INDIRECTPROPERTY **ppip, // pointer to returned pointer to
  567. // MAXULONG terminated array of Indirect
  568. // properties w/indexes into aprs & avar
  569. OUT NTSTATUS *pstatus)
  570. {
  571. *pstatus = STATUS_SUCCESS;
  572. IFDBG( HRESULT &hr = *pstatus );
  573. propITraceStatic( "BuildIndirectIndexArray" );
  574. propTraceParameters(( "cprop=%d, cAlloc=%d, cIndirect=%d, avar=%p",
  575. cprop, cAlloc, cIndirect, avar ));
  576. PROPASSERT(cIndirect > 0);
  577. PROPASSERT(cAlloc >= cIndirect);
  578. PROPASSERT(cprop >= cAlloc);
  579. if (ppip != NULL)
  580. {
  581. INDIRECTPROPERTY *pip;
  582. ULONG iprop;
  583. if (cprop == 1)
  584. {
  585. pip = (INDIRECTPROPERTY *) ppip;
  586. }
  587. else
  588. {
  589. pip = (INDIRECTPROPERTY *) CoTaskMemAlloc( (cAlloc+1) * sizeof(INDIRECTPROPERTY) );
  590. if (pip == NULL)
  591. {
  592. *pstatus = STATUS_INSUFFICIENT_RESOURCES;
  593. goto Exit;
  594. }
  595. *ppip = pip;
  596. }
  597. for (iprop = 0; iprop < cprop; iprop++)
  598. {
  599. if (IsIndirectVarType(avar[iprop].vt))
  600. {
  601. PROPASSERT(cprop == 1 || (ULONG) (pip - *ppip) < cIndirect);
  602. pip->Index = iprop;
  603. pip->poszName = NULL;
  604. pip++;
  605. }
  606. }
  607. if (cprop > 1)
  608. {
  609. pip->Index = MAXULONG;
  610. PROPASSERT((ULONG) (pip - *ppip) == cIndirect);
  611. }
  612. }
  613. // ----
  614. // Exit
  615. // ----
  616. Exit:
  617. return;
  618. }
  619. //+---------------------------------------------------------------------------
  620. // Function: PrSetProperties, public
  621. //
  622. // Synopsis: Set property values for a property set
  623. //
  624. // Arguments: [np] -- property set context
  625. // [cprop] -- property count
  626. // [pidNameFirst] -- first PROPID for new named properties
  627. // [aprs] -- array of property specifiers
  628. // [apid] -- buffer for array of propids
  629. // -- values to write in place of indirect properties
  630. // [ppip] -- ptr to ptr to Indirect property structures
  631. // [avar] -- array of PROPVARIANTs
  632. //
  633. // Returns: Status code
  634. //---------------------------------------------------------------------------
  635. NTSTATUS
  636. PrSetProperties(
  637. IN NTPROP np, // property set context
  638. IN ULONG cprop, // property count
  639. IN PROPID pidNameFirst, // first PROPID for new named properties
  640. IN PROPSPEC const aprs[], // array of property specifiers
  641. OUT USHORT *pCodePage,
  642. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  643. OPTIONAL OUT INDIRECTPROPERTY **ppip, // pointer to returned pointer to
  644. // MAXULONG terminated array of Indirect
  645. // properties w/indexes into aprs & avar
  646. IN PROPVARIANT const avar[]) // array of properties+values
  647. {
  648. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  649. NTSTATUS Status = STATUS_SUCCESS;
  650. BOOL fLocked = FALSE;
  651. PROPERTY_INFORMATION apinfoStack[6];
  652. PROPERTY_INFORMATION *apinfo = apinfoStack;
  653. ULONG cIndirect = 0;
  654. IFDBG( HRESULT &hr = Status );
  655. propITraceStatic( "PrSetProperties" );
  656. propTraceParameters(( "np=%p, cprop=%d, pidNameFirst=%d, aprs=%p, CodePage=%d, apid=%p, ppip=%p, avar=%p",
  657. np, cprop, pidNameFirst, aprs, *pCodePage, apid, ppip, avar ));
  658. // Initialize the INDIRECTPROPERTY structure.
  659. if (ppip != NULL)
  660. {
  661. *ppip = NULL;
  662. // If cprop is 1, ppip is actually pip (one level
  663. // of indirection).
  664. if (cprop == 1)
  665. {
  666. // Default the index.
  667. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  668. }
  669. }
  670. // Lock the property set.
  671. Status = ppsstm->Lock(TRUE);
  672. if( !NT_SUCCESS(Status) ) goto Exit;
  673. fLocked = TRUE;
  674. // Is the stack-based apinfo big enough?
  675. if (cprop > sizeof(apinfoStack)/sizeof(apinfoStack[0]))
  676. {
  677. // No - we need to allocate an apinfo.
  678. apinfo = reinterpret_cast<PROPERTY_INFORMATION*>
  679. ( CoTaskMemAlloc( sizeof(PROPERTY_INFORMATION) * cprop ));
  680. if( NULL == apinfo )
  681. {
  682. Status = STATUS_INSUFFICIENT_RESOURCES;
  683. goto Exit;
  684. }
  685. }
  686. ppsstm->ReOpen(&Status); // Reload header/size info
  687. if( !NT_SUCCESS(Status) ) goto Exit;
  688. ppsstm->Validate(&Status);
  689. if( !NT_SUCCESS(Status) ) goto Exit;
  690. // Describe the request into the apinfo array. This also writes the names
  691. // to the dictionary.
  692. ConvertVariantToPropInfo(
  693. ppsstm,
  694. cprop,
  695. pidNameFirst,
  696. aprs,
  697. apid,
  698. avar,
  699. apinfo,
  700. ppip == NULL? NULL : &cIndirect,
  701. &Status);
  702. if( !NT_SUCCESS(Status) ) goto Exit;
  703. // If the caller wants to know about indirect streams and
  704. // storages (and if there were any), allocate memory for a
  705. // MAXULONG terminated array of indexes to the indirect
  706. // variant structures, and fill it in.
  707. ppsstm->SetValue(cprop, ppip, avar, apinfo, pCodePage, &Status);
  708. if( !NT_SUCCESS(Status) ) goto Exit;
  709. ppsstm->Validate(&Status);
  710. if( !NT_SUCCESS(Status) ) goto Exit;
  711. // ----
  712. // Exit
  713. // ----
  714. Exit:
  715. // If we allocated a temporary apinfo buffer, free it.
  716. if (apinfo != apinfoStack)
  717. {
  718. CoTaskMemFree( apinfo );
  719. }
  720. if (!NT_SUCCESS(Status))
  721. {
  722. if (ppip != NULL)
  723. {
  724. if (cprop == 1)
  725. {
  726. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  727. }
  728. else if (*ppip != NULL)
  729. {
  730. CoTaskMemFree( *ppip );
  731. *ppip = NULL;
  732. }
  733. }
  734. }
  735. if (fLocked)
  736. Status = Unlock( ppsstm, Status );
  737. if( STATUS_NOT_SUPPORTED == Status )
  738. propSuppressExitErrors();
  739. return(Status);
  740. }
  741. //+---------------------------------------------------------------------------
  742. // Function: PrQueryProperties, public
  743. //
  744. // Synopsis: Query property values from a property set
  745. //
  746. // Arguments: [np] -- property set context
  747. // [cprop] -- property count
  748. // [aprs] -- array of property specifiers
  749. // [apid] -- buffer for array of propids
  750. // [ppip] -- ptr to ptr to Indirect property structures
  751. // [avar] -- array of PROPVARIANTs
  752. //
  753. // Returns: Status code
  754. //---------------------------------------------------------------------------
  755. NTSTATUS
  756. PrQueryProperties(
  757. IN NTPROP np, // property set context
  758. IN ULONG cprop, // property count
  759. IN PROPSPEC const aprs[], // array of property specifiers
  760. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  761. OPTIONAL OUT INDIRECTPROPERTY **ppip, // pointer to returned pointer to
  762. // MAXULONG terminated array of Indirect
  763. // properties w/indexes into aprs & avar
  764. IN OUT PROPVARIANT *avar, // IN: array of uninitialized PROPVARIANTs,
  765. // OUT: may contain pointers to alloc'd memory
  766. OUT ULONG *pcpropFound) // count of property values retrieved
  767. {
  768. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  769. SERIALIZEDPROPERTYVALUE const *pprop = NULL;
  770. NTSTATUS Status = STATUS_SUCCESS;
  771. ULONG cIndirect = 0;
  772. ULONG iprop;
  773. BOOL fLocked = FALSE;
  774. IFDBG( HRESULT &hr = Status );
  775. propITraceStatic( "PrQueryProperties" );
  776. propTraceParameters(( "np=%p, cprop=%d, aprs=%p, apid=%p, ppip=%p)",
  777. np, cprop, aprs, apid, ppip ));
  778. // Initialize the variant array enough to allow it to be cleaned up
  779. // by the caller (even on partial failure).
  780. *pcpropFound = 0;
  781. if (ppip != NULL)
  782. {
  783. *ppip = NULL;
  784. if (cprop == 1)
  785. {
  786. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  787. }
  788. }
  789. // Zero-ing out the caller-provided PropVariants, essentially
  790. // sets them all to VT_EMPTY. It also zeros out the data portion,
  791. // which prevents cleanup problems in error paths.
  792. RtlZeroMemory(avar, cprop * sizeof(avar[0]));
  793. Status = ppsstm->Lock(FALSE);
  794. if( !NT_SUCCESS(Status) ) goto Exit;
  795. fLocked = TRUE;
  796. ppsstm->ReOpen(&Status); // Reload header/size info
  797. if( !NT_SUCCESS(Status) ) goto Exit;
  798. ppsstm->Validate(&Status);
  799. if( !NT_SUCCESS(Status) ) goto Exit;
  800. for (iprop = 0; iprop < cprop; iprop++)
  801. {
  802. PROPID pid;
  803. ULONG cbprop;
  804. switch(aprs[iprop].ulKind)
  805. {
  806. case PRSPEC_LPWSTR:
  807. pid = ppsstm->QueryPropid(aprs[iprop].lpwstr, &Status);
  808. if( !NT_SUCCESS(Status) ) goto Exit;
  809. break;
  810. case PRSPEC_PROPID:
  811. pid = aprs[iprop].propid;
  812. break;
  813. default:
  814. PROPASSERT(!"Bad ulKind");
  815. Status = STATUS_INVALID_PARAMETER;
  816. goto Exit;
  817. }
  818. pprop = ppsstm->GetValue(pid, &cbprop, &Status);
  819. if( !NT_SUCCESS(Status) ) goto Exit;
  820. if (pprop != NULL)
  821. {
  822. BOOL fIndirect;
  823. (*pcpropFound)++;
  824. fIndirect = StgConvertPropertyToVariantNoEH(
  825. pprop,
  826. ppsstm->GetCodePage(),
  827. &avar[iprop],
  828. ppsstm->GetAllocator(),
  829. &Status);
  830. if( !NT_SUCCESS(Status) ) goto Exit;
  831. PROPASSERT( ( !(VT_ARRAY & avar[iprop].vt)
  832. &&
  833. !(VT_BYREF & avar[iprop].vt)
  834. &&
  835. VT_DECIMAL != avar[iprop].vt
  836. &&
  837. VT_I1 != avar[iprop].vt
  838. &&
  839. VT_INT != avar[iprop].vt
  840. &&
  841. VT_UINT != avar[iprop].vt
  842. )
  843. ||
  844. PROPSET_WFORMAT_EXPANDED_VTS <= ppsstm->GetFormatVersion()
  845. );
  846. if( fIndirect )
  847. {
  848. cIndirect++;
  849. }
  850. }
  851. if (apid != NULL)
  852. {
  853. apid[iprop] = pid;
  854. }
  855. } // for (iprop = 0; iprop < cprop; iprop++)
  856. // If the caller wants to know about indirect streams and
  857. // storages (and if there were any), allocate memory for a
  858. // MAXULONG terminated array of indexes to the indirect
  859. // variant structures, and fill it in.
  860. if (cIndirect != 0)
  861. {
  862. BuildIndirectIndexArray(
  863. cprop,
  864. cIndirect,
  865. cIndirect,
  866. avar,
  867. ppip,
  868. &Status);
  869. if( !NT_SUCCESS(Status) ) goto Exit;
  870. }
  871. ppsstm->Validate(&Status);
  872. if( !NT_SUCCESS(Status) ) goto Exit;
  873. // ----
  874. // Exit
  875. // ----
  876. Exit:
  877. if( !NT_SUCCESS(Status) )
  878. {
  879. if (ppip != NULL)
  880. {
  881. if (cprop == 1)
  882. {
  883. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  884. }
  885. else if (*ppip != NULL)
  886. {
  887. CoTaskMemFree( *ppip );
  888. *ppip = NULL;
  889. }
  890. }
  891. CleanupVariants(avar, cprop, ppsstm->GetAllocator());
  892. }
  893. if (fLocked)
  894. Status = Unlock( ppsstm, Status );
  895. if( STATUS_NOT_SUPPORTED == Status )
  896. propSuppressExitErrors();
  897. return(Status);
  898. }
  899. //+---------------------------------------------------------------------------
  900. // Function: PrEnumerateProperties, public
  901. //
  902. // Synopsis: Enumerate properties in a property set
  903. //
  904. // Arguments: [np] -- property set context
  905. // [cskip] -- count of properties to skip
  906. // [pcprop] -- pointer to property count
  907. // [Flags] -- flags: No Names (propids only), etc.
  908. // [asps] -- array of STATPROPSTGs
  909. //
  910. // Returns: Status code
  911. //---------------------------------------------------------------------------
  912. NTSTATUS
  913. PrEnumerateProperties(
  914. IN NTPROP np, // property set context
  915. IN ULONG Flags, // flags: No Names (propids only), etc.
  916. IN ULONG *pkey, // count of properties to skip
  917. IN OUT ULONG *pcprop, // pointer to property count
  918. OPTIONAL OUT PROPSPEC aprs[],// IN: array of uninitialized PROPSPECs
  919. // OUT: may contain pointers to alloc'd strings
  920. OPTIONAL OUT STATPROPSTG asps[]) // IN: array of uninitialized STATPROPSTGs
  921. // OUT: may contain pointers to alloc'd strings
  922. {
  923. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  924. NTSTATUS Status = STATUS_SUCCESS;
  925. SERIALIZEDPROPERTYVALUE const *pprop = NULL;
  926. PROPSPEC *pprs;
  927. STATPROPSTG *psps;
  928. PROPID *ppidBase = NULL;
  929. ULONG i;
  930. ULONG cpropin;
  931. BOOL fLocked = FALSE;
  932. PROPID apidStack[20];
  933. PROPID *ppid;
  934. ULONG cprop;
  935. PMemoryAllocator *pma = ppsstm->GetAllocator();
  936. // PERF: It'd be good to rewrite this name code so that it uses
  937. // a default-sized stack buffer where possible, which will be most of
  938. // the time.
  939. OLECHAR *poszName = NULL;
  940. IFDBG( HRESULT &hr = Status );
  941. propITraceStatic( "PrEnumerateProperties" );
  942. propTraceParameters(( "np=%p, Flags=0x%x, key=0x%x, cprop=%d, aprs=%p, asps=%p)\n",
  943. np, Flags, *pkey, *pcprop, aprs, asps));
  944. cpropin = *pcprop;
  945. // Eliminate confusion for easy cleanup
  946. if (aprs != NULL)
  947. {
  948. // Set all the PropSpecs to PROPID (which require
  949. // no cleanup).
  950. for (i = 0; i < cpropin; i++)
  951. {
  952. aprs[i].ulKind = PRSPEC_PROPID;
  953. }
  954. }
  955. // Zero all pointers in the array for easy cleanup
  956. if (asps != NULL)
  957. {
  958. RtlZeroMemory(asps, cpropin * sizeof(asps[0]));
  959. }
  960. Status = ppsstm->Lock(FALSE);
  961. if( !NT_SUCCESS(Status) ) goto Exit;
  962. fLocked = TRUE;
  963. ppidBase = NULL;
  964. cprop = ppsstm->ReOpen(&Status); // Reload header/size info
  965. if( !NT_SUCCESS(Status) ) goto Exit;
  966. if (cprop > cpropin)
  967. {
  968. cprop = cpropin;
  969. }
  970. ppsstm->Validate(&Status);
  971. if( !NT_SUCCESS(Status) ) goto Exit;
  972. ppid = NULL;
  973. if (aprs != NULL || asps != NULL)
  974. {
  975. ppid = apidStack;
  976. if (cprop > sizeof(apidStack)/sizeof(apidStack[0]))
  977. {
  978. ppidBase = reinterpret_cast<PROPID*>( CoTaskMemAlloc( cprop * sizeof(PROPID) ));
  979. if (ppidBase == NULL)
  980. {
  981. Status = STATUS_INSUFFICIENT_RESOURCES;
  982. goto Exit;
  983. }
  984. ppid = ppidBase;
  985. }
  986. }
  987. ppsstm->EnumeratePropids(pkey, &cprop, ppid, &Status);
  988. if( !NT_SUCCESS(Status) ) goto Exit;
  989. *pcprop = cprop;
  990. if (ppid != NULL)
  991. {
  992. psps = asps;
  993. pprs = aprs;
  994. while (cprop-- > 0)
  995. {
  996. ULONG cbprop;
  997. BOOLEAN fHasName;
  998. PROPASSERT(*ppid != PID_DICTIONARY && *ppid != PID_CODEPAGE);
  999. fHasName = FALSE;
  1000. if ((Flags & ENUMPROP_NONAMES) == 0)
  1001. {
  1002. fHasName = ppsstm->QueryPropertyNames( 1, ppid, &poszName, &Status );
  1003. if( !NT_SUCCESS(Status) ) goto Exit;
  1004. }
  1005. if (pprs != NULL)
  1006. {
  1007. PROPASSERT(pprs->ulKind == PRSPEC_PROPID);
  1008. if (fHasName)
  1009. {
  1010. pprs->lpwstr = ppsstm->DuplicatePropertyName(
  1011. poszName,
  1012. (ocslen(poszName)+1)*sizeof(OLECHAR),
  1013. &Status);
  1014. if( !NT_SUCCESS(Status) ) goto Exit;
  1015. PROPASSERT(pprs->lpwstr != NULL);
  1016. // Make this assignment *after* memory allocation
  1017. // succeeds so we free only valid pointers in below
  1018. // cleanup code.
  1019. pprs->ulKind = PRSPEC_LPWSTR;
  1020. }
  1021. else
  1022. {
  1023. pprs->propid = *ppid;
  1024. }
  1025. pprs++;
  1026. } // if (pprs != NULL)
  1027. if (psps != NULL)
  1028. {
  1029. pprop = ppsstm->GetValue(*ppid, &cbprop, &Status);
  1030. if( !NT_SUCCESS(Status) ) goto Exit;
  1031. PROPASSERT(psps->lpwstrName == NULL);
  1032. if (fHasName)
  1033. {
  1034. psps->lpwstrName = ppsstm->DuplicatePropertyName(
  1035. poszName,
  1036. (ocslen(poszName)+1)*sizeof(OLECHAR),
  1037. &Status);
  1038. if( !NT_SUCCESS(Status) ) goto Exit;
  1039. PROPASSERT(psps->lpwstrName != NULL);
  1040. }
  1041. psps->propid = *ppid;
  1042. psps->vt = (VARTYPE) PropByteSwap( pprop->dwType );
  1043. psps++;
  1044. } // if (psps != NULL)
  1045. ppid++;
  1046. CoTaskMemFree( poszName ); poszName = NULL;
  1047. } // while (cprop-- > 0)
  1048. } // if (ppid != NULL)
  1049. ppsstm->Validate(&Status);
  1050. if( !NT_SUCCESS(Status) ) goto Exit;
  1051. // ----
  1052. // Exit
  1053. // ----
  1054. Exit:
  1055. if (fLocked)
  1056. Status = Unlock( ppsstm, Status );
  1057. if( NULL != poszName )
  1058. CoTaskMemFree( poszName );
  1059. CoTaskMemFree( ppidBase );
  1060. if (!NT_SUCCESS(Status))
  1061. {
  1062. PMemoryAllocator *pma = ppsstm->GetAllocator();
  1063. if (aprs != NULL)
  1064. {
  1065. for (i = 0; i < cpropin; i++)
  1066. {
  1067. if (aprs[i].ulKind == PRSPEC_LPWSTR)
  1068. {
  1069. pma->Free(aprs[i].lpwstr);
  1070. aprs[i].ulKind = PRSPEC_PROPID;
  1071. }
  1072. }
  1073. }
  1074. if (asps != NULL)
  1075. {
  1076. for (i = 0; i < cpropin; i++)
  1077. {
  1078. if (asps[i].lpwstrName != NULL)
  1079. {
  1080. pma->Free(asps[i].lpwstrName);
  1081. asps[i].lpwstrName = NULL;
  1082. }
  1083. }
  1084. }
  1085. } // if (!NT_SUCCESS(Status))
  1086. #if DBG
  1087. if (NT_SUCCESS(Status))
  1088. {
  1089. if (aprs != NULL)
  1090. {
  1091. for (i = 0; i < cpropin; i++)
  1092. {
  1093. if (aprs[i].ulKind == PRSPEC_LPWSTR)
  1094. {
  1095. PROPASSERT(aprs[i].lpwstr != NULL);
  1096. PROPASSERT(ocslen(aprs[i].lpwstr) > 0);
  1097. }
  1098. }
  1099. }
  1100. if (asps != NULL)
  1101. {
  1102. for (i = 0; i < cpropin; i++)
  1103. {
  1104. if (asps[i].lpwstrName != NULL)
  1105. {
  1106. PROPASSERT(ocslen(asps[i].lpwstrName) > 0);
  1107. }
  1108. }
  1109. }
  1110. }
  1111. #endif // DBG
  1112. return(Status);
  1113. }
  1114. //+---------------------------------------------------------------------------
  1115. // Function: PrQueryPropertyNames, public
  1116. //
  1117. // Synopsis: Read property names for PROPIDs in a property set
  1118. //
  1119. // Arguments: [np] -- property set context
  1120. // [cprop] -- property count
  1121. // [apid] -- array of PROPIDs
  1122. // [aposz] -- array of pointers to WCHAR strings
  1123. //
  1124. // Returns: Status code
  1125. //---------------------------------------------------------------------------
  1126. NTSTATUS
  1127. PrQueryPropertyNames(
  1128. IN NTPROP np, // property set context
  1129. IN ULONG cprop, // property count
  1130. IN PROPID const *apid, // PROPID array
  1131. OUT OLECHAR *aposz[]) // OUT pointers to allocated strings
  1132. {
  1133. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1134. NTSTATUS Status = STATUS_SUCCESS;
  1135. NTSTATUS StatusQuery = STATUS_SUCCESS;
  1136. BOOL fLocked = FALSE;
  1137. IFDBG( HRESULT &hr = Status );
  1138. propITraceStatic( "PrQueryPropertyNames" );
  1139. propTraceParameters(( "np=%p, cprop=%d, apid=%p, aposz=%p)",
  1140. np, cprop, apid, aposz ));
  1141. RtlZeroMemory(aposz, cprop * sizeof(aposz[0]));
  1142. Status = ppsstm->Lock(FALSE);
  1143. if( !NT_SUCCESS(Status) ) goto Exit;
  1144. fLocked = TRUE;
  1145. ppsstm->ReOpen(&Status); // Reload header/size info
  1146. if( !NT_SUCCESS(Status) ) goto Exit;
  1147. ppsstm->Validate(&Status);
  1148. if( !NT_SUCCESS(Status) ) goto Exit;
  1149. // We'll save the Status from the following call. If there
  1150. // are no other errors, we'll return it to the caller (it
  1151. // might contain a useful success code).
  1152. ppsstm->QueryPropertyNames(cprop, apid, aposz, &StatusQuery);
  1153. if( !NT_SUCCESS(StatusQuery) )
  1154. {
  1155. Status = StatusQuery;
  1156. goto Exit;
  1157. }
  1158. ppsstm->Validate(&Status);
  1159. if( !NT_SUCCESS(Status) ) goto Exit;
  1160. // ----
  1161. // Exit
  1162. // ----
  1163. Exit:
  1164. if (fLocked)
  1165. Status = Unlock( ppsstm, Status );
  1166. if( NT_SUCCESS(Status) )
  1167. Status = StatusQuery;
  1168. return(Status);
  1169. } // PrQueryPropertyNames()
  1170. //+---------------------------------------------------------------------------
  1171. // Function: PrSetPropertyNames, public
  1172. //
  1173. // Synopsis: Write property names for PROPIDs in a property set
  1174. //
  1175. // Arguments: [np] -- property set context
  1176. // [cprop] -- property count
  1177. // [apid] -- array of PROPIDs
  1178. // [aposz] -- array of pointers to OLECHAR strings
  1179. //
  1180. // Returns: Status code
  1181. //---------------------------------------------------------------------------
  1182. NTSTATUS
  1183. PrSetPropertyNames(
  1184. IN NTPROP np, // property set context
  1185. IN ULONG cprop, // property count
  1186. IN PROPID const *apid, // PROPID array
  1187. IN OLECHAR const * const aposz[]) // pointers to property names
  1188. {
  1189. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1190. NTSTATUS Status = STATUS_SUCCESS;
  1191. BOOL fLocked = FALSE;
  1192. IFDBG( HRESULT &hr = Status );
  1193. propITraceStatic( "PrSetPropertyNames" );
  1194. propTraceParameters(( "np=%p, cprop=%d, apid=%p, aposz=%p",
  1195. np, cprop, apid, aposz ));
  1196. Status = ppsstm->Lock(TRUE);
  1197. if( !NT_SUCCESS(Status) ) goto Exit;
  1198. fLocked = TRUE;
  1199. ppsstm->ReOpen(&Status); // Reload header/size info
  1200. if( !NT_SUCCESS(Status) ) goto Exit;
  1201. ppsstm->Validate(&Status);
  1202. if( !NT_SUCCESS(Status) ) goto Exit;
  1203. ppsstm->SetPropertyNames(cprop, apid, aposz, &Status);
  1204. if( !NT_SUCCESS(Status) ) goto Exit;
  1205. ppsstm->Validate(&Status);
  1206. if( !NT_SUCCESS(Status) ) goto Exit;
  1207. // ----
  1208. // Exit
  1209. // ----
  1210. Exit:
  1211. if (fLocked)
  1212. Status = Unlock( ppsstm, Status );
  1213. return(Status);
  1214. } // PrSetPropertyNames()
  1215. //+---------------------------------------------------------------------------
  1216. // Function: PrSetPropertySetClassId, public
  1217. //
  1218. // Synopsis: Set the property set's ClassId
  1219. //
  1220. // Arguments: [np] -- property set context
  1221. // [pspss] -- pointer to STATPROPSETSTG
  1222. //
  1223. // Returns: Status code
  1224. //---------------------------------------------------------------------------
  1225. NTSTATUS
  1226. PrSetPropertySetClassId(
  1227. IN NTPROP np, // property set context
  1228. IN GUID const *pclsid) // new CLASSID of propset code
  1229. {
  1230. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1231. NTSTATUS Status = STATUS_SUCCESS;
  1232. BOOL fLocked = FALSE;
  1233. IFDBG( HRESULT &hr = Status );
  1234. propITraceStatic( "PrSetPropertySetClassId" );
  1235. propTraceParameters(( "np=%p, pclsid=%p", np, pclsid ));
  1236. Status = ppsstm->Lock(TRUE);
  1237. if( !NT_SUCCESS(Status) ) goto Exit;
  1238. fLocked = TRUE;
  1239. ppsstm->ReOpen(&Status); // Reload header/size info
  1240. if( !NT_SUCCESS(Status) ) goto Exit;
  1241. ppsstm->Validate(&Status);
  1242. if( !NT_SUCCESS(Status) ) goto Exit;
  1243. ppsstm->SetClassId(pclsid, &Status);
  1244. if( !NT_SUCCESS(Status) ) goto Exit;
  1245. ppsstm->Validate(&Status);
  1246. if( !NT_SUCCESS(Status) ) goto Exit;
  1247. // ----
  1248. // Exit
  1249. // ----
  1250. Exit:
  1251. if (fLocked)
  1252. Status = Unlock( ppsstm, Status );
  1253. return(Status);
  1254. } // PrSetPropertySetClassId()
  1255. //+---------------------------------------------------------------------------
  1256. // Function: PrQueryPropertySet, public
  1257. //
  1258. // Synopsis: Query the passed property set
  1259. //
  1260. // Arguments: [np] -- property set context
  1261. // [pspss] -- pointer to STATPROPSETSTG
  1262. //
  1263. // Returns: Status code
  1264. //---------------------------------------------------------------------------
  1265. NTSTATUS
  1266. PrQueryPropertySet(
  1267. IN NTPROP np, // property set context
  1268. OUT STATPROPSETSTG *pspss) // buffer for property set stat information
  1269. {
  1270. NTSTATUS Status = STATUS_SUCCESS;
  1271. BOOL fLocked = FALSE;
  1272. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1273. IFDBG( HRESULT &hr = Status );
  1274. propITraceStatic( "PrQueryPropertySet" );
  1275. propTraceParameters(( "np=%p, pspss=%p", np, pspss ));
  1276. RtlZeroMemory(pspss, sizeof(*pspss));
  1277. Status = ppsstm->Lock(FALSE);
  1278. if( !NT_SUCCESS(Status) ) goto Exit;
  1279. fLocked = TRUE;
  1280. ppsstm->ReOpen(&Status); // Reload header/size info
  1281. if( !NT_SUCCESS(Status) ) goto Exit;
  1282. ppsstm->Validate(&Status);
  1283. if( !NT_SUCCESS(Status) ) goto Exit;
  1284. ppsstm->QueryPropertySet(pspss, &Status);
  1285. if( !NT_SUCCESS(Status) ) goto Exit;
  1286. ppsstm->Validate(&Status);
  1287. if( !NT_SUCCESS(Status) ) goto Exit;
  1288. // ----
  1289. // Exit
  1290. // ----
  1291. Exit:
  1292. if (fLocked)
  1293. Status = Unlock( ppsstm, Status );
  1294. return(Status);
  1295. } // PrQueryPropertySet()
  1296. inline BOOLEAN
  1297. _Compare_VT_BOOL(VARIANT_BOOL bool1, VARIANT_BOOL bool2)
  1298. {
  1299. // Allow any non-zero value to match any non-zero value
  1300. return((bool1 == FALSE) == (bool2 == FALSE));
  1301. }
  1302. BOOLEAN
  1303. _Compare_VT_CF(CLIPDATA *pclipdata1, CLIPDATA *pclipdata2)
  1304. {
  1305. BOOLEAN fSame;
  1306. if (pclipdata1 != NULL && pclipdata2 != NULL)
  1307. {
  1308. fSame = ( pclipdata1->cbSize == pclipdata2->cbSize
  1309. &&
  1310. pclipdata1->ulClipFmt == pclipdata2->ulClipFmt );
  1311. if (fSame)
  1312. {
  1313. if (pclipdata1->pClipData != NULL && pclipdata2->pClipData != NULL)
  1314. {
  1315. fSame = memcmp(
  1316. pclipdata1->pClipData,
  1317. pclipdata2->pClipData,
  1318. CBPCLIPDATA(*pclipdata1)
  1319. ) == 0;
  1320. }
  1321. else
  1322. {
  1323. // They're the same if both are NULL, or if
  1324. // they have a zero length (if they have a zero
  1325. // length, either one may or may not be NULL, but they're
  1326. // still considered the same).
  1327. // Note that CBPCLIPDATA(*pclipdata1)==CBPCLIPDATA(*pclipdata2).
  1328. fSame = pclipdata1->pClipData == pclipdata2->pClipData
  1329. ||
  1330. CBPCLIPDATA(*pclipdata1) == 0;
  1331. }
  1332. }
  1333. }
  1334. else
  1335. {
  1336. fSame = pclipdata1 == pclipdata2;
  1337. }
  1338. return(fSame);
  1339. }
  1340. //+---------------------------------------------------------------------------
  1341. // Function: PrCompareVariants, public
  1342. //
  1343. // Synopsis: Compare two passed PROPVARIANTs -- case sensitive for strings
  1344. //
  1345. // Arguments: [CodePage] -- CodePage
  1346. // [pvar1] -- pointer to PROPVARIANT
  1347. // [pvar2] -- pointer to PROPVARIANT
  1348. //
  1349. // Returns: TRUE if identical, else FALSE
  1350. //---------------------------------------------------------------------------
  1351. #ifdef _MAC
  1352. EXTERN_C // The Mac linker doesn't seem to be able to export with C++ decorations
  1353. #endif
  1354. BOOLEAN
  1355. PrCompareVariants(
  1356. USHORT CodePage,
  1357. PROPVARIANT const *pvar1,
  1358. PROPVARIANT const *pvar2)
  1359. {
  1360. if (pvar1->vt != pvar2->vt)
  1361. {
  1362. return(FALSE);
  1363. }
  1364. BOOLEAN fSame;
  1365. ULONG i;
  1366. switch (pvar1->vt)
  1367. {
  1368. case VT_EMPTY:
  1369. case VT_NULL:
  1370. fSame = TRUE;
  1371. break;
  1372. case VT_I1:
  1373. case VT_UI1:
  1374. fSame = pvar1->bVal == pvar2->bVal;
  1375. break;
  1376. case VT_I2:
  1377. case VT_UI2:
  1378. fSame = pvar1->iVal == pvar2->iVal;
  1379. break;
  1380. case VT_BOOL:
  1381. fSame = _Compare_VT_BOOL(pvar1->boolVal, pvar2->boolVal);
  1382. break;
  1383. case VT_I4:
  1384. case VT_UI4:
  1385. case VT_R4:
  1386. case VT_ERROR:
  1387. fSame = pvar1->lVal == pvar2->lVal;
  1388. break;
  1389. case VT_I8:
  1390. case VT_UI8:
  1391. case VT_R8:
  1392. case VT_CY:
  1393. case VT_DATE:
  1394. case VT_FILETIME:
  1395. fSame = pvar1->hVal.HighPart == pvar2->hVal.HighPart
  1396. &&
  1397. pvar1->hVal.LowPart == pvar2->hVal.LowPart;
  1398. break;
  1399. case VT_CLSID:
  1400. fSame = memcmp(pvar1->puuid, pvar2->puuid, sizeof(CLSID)) == 0;
  1401. break;
  1402. case VT_BLOB:
  1403. case VT_BLOB_OBJECT:
  1404. fSame = ( pvar1->blob.cbSize == pvar2->blob.cbSize );
  1405. if (fSame)
  1406. {
  1407. fSame = memcmp(
  1408. pvar1->blob.pBlobData,
  1409. pvar2->blob.pBlobData,
  1410. pvar1->blob.cbSize) == 0;
  1411. }
  1412. break;
  1413. case VT_CF:
  1414. fSame = _Compare_VT_CF(pvar1->pclipdata, pvar2->pclipdata);
  1415. break;
  1416. case VT_BSTR:
  1417. if (pvar1->bstrVal != NULL && pvar2->bstrVal != NULL)
  1418. {
  1419. fSame = ( BSTRLEN(pvar1->bstrVal) == BSTRLEN(pvar2->bstrVal) );
  1420. if (fSame)
  1421. {
  1422. fSame = memcmp(
  1423. pvar1->bstrVal,
  1424. pvar2->bstrVal,
  1425. BSTRLEN(pvar1->bstrVal)) == 0;
  1426. }
  1427. }
  1428. else
  1429. {
  1430. fSame = pvar1->bstrVal == pvar2->bstrVal;
  1431. }
  1432. break;
  1433. case VT_LPSTR:
  1434. if (pvar1->pszVal != NULL && pvar2->pszVal != NULL)
  1435. {
  1436. fSame = strcmp(pvar1->pszVal, pvar2->pszVal) == 0;
  1437. }
  1438. else
  1439. {
  1440. fSame = pvar1->pszVal == pvar2->pszVal;
  1441. }
  1442. break;
  1443. case VT_STREAM:
  1444. case VT_STREAMED_OBJECT:
  1445. case VT_STORAGE:
  1446. case VT_STORED_OBJECT:
  1447. case VT_LPWSTR:
  1448. if (pvar1->pwszVal != NULL && pvar2->pwszVal != NULL)
  1449. {
  1450. fSame = Prop_wcscmp(pvar1->pwszVal, pvar2->pwszVal) == 0;
  1451. }
  1452. else
  1453. {
  1454. fSame = pvar1->pwszVal == pvar2->pwszVal;
  1455. }
  1456. break;
  1457. case VT_VECTOR | VT_I1:
  1458. case VT_VECTOR | VT_UI1:
  1459. fSame = ( pvar1->caub.cElems == pvar2->caub.cElems );
  1460. if (fSame)
  1461. {
  1462. fSame = memcmp(
  1463. pvar1->caub.pElems,
  1464. pvar2->caub.pElems,
  1465. pvar1->caub.cElems * sizeof(pvar1->caub.pElems[0])) == 0;
  1466. }
  1467. break;
  1468. case VT_VECTOR | VT_I2:
  1469. case VT_VECTOR | VT_UI2:
  1470. fSame = ( pvar1->cai.cElems == pvar2->cai.cElems );
  1471. if (fSame)
  1472. {
  1473. fSame = memcmp(
  1474. pvar1->cai.pElems,
  1475. pvar2->cai.pElems,
  1476. pvar1->cai.cElems * sizeof(pvar1->cai.pElems[0])) == 0;
  1477. }
  1478. break;
  1479. case VT_VECTOR | VT_BOOL:
  1480. fSame = ( pvar1->cabool.cElems == pvar2->cabool.cElems );
  1481. if (fSame)
  1482. {
  1483. for (i = 0; i < pvar1->cabool.cElems; i++)
  1484. {
  1485. fSame = _Compare_VT_BOOL(
  1486. pvar1->cabool.pElems[i],
  1487. pvar2->cabool.pElems[i]);
  1488. if (!fSame)
  1489. {
  1490. break;
  1491. }
  1492. }
  1493. }
  1494. break;
  1495. case VT_VECTOR | VT_I4:
  1496. case VT_VECTOR | VT_UI4:
  1497. case VT_VECTOR | VT_R4:
  1498. case VT_VECTOR | VT_ERROR:
  1499. fSame = ( pvar1->cal.cElems == pvar2->cal.cElems );
  1500. if (fSame)
  1501. {
  1502. fSame = memcmp(
  1503. pvar1->cal.pElems,
  1504. pvar2->cal.pElems,
  1505. pvar1->cal.cElems * sizeof(pvar1->cal.pElems[0])) == 0;
  1506. }
  1507. break;
  1508. case VT_VECTOR | VT_I8:
  1509. case VT_VECTOR | VT_UI8:
  1510. case VT_VECTOR | VT_R8:
  1511. case VT_VECTOR | VT_CY:
  1512. case VT_VECTOR | VT_DATE:
  1513. case VT_VECTOR | VT_FILETIME:
  1514. fSame = ( pvar1->cah.cElems == pvar2->cah.cElems );
  1515. if (fSame)
  1516. {
  1517. fSame = memcmp(
  1518. pvar1->cah.pElems,
  1519. pvar2->cah.pElems,
  1520. pvar1->cah.cElems *
  1521. sizeof(pvar1->cah.pElems[0])) == 0;
  1522. }
  1523. break;
  1524. case VT_VECTOR | VT_CLSID:
  1525. fSame = ( pvar1->cauuid.cElems == pvar2->cauuid.cElems );
  1526. if (fSame)
  1527. {
  1528. fSame = memcmp(
  1529. pvar1->cauuid.pElems,
  1530. pvar2->cauuid.pElems,
  1531. pvar1->cauuid.cElems *
  1532. sizeof(pvar1->cauuid.pElems[0])) == 0;
  1533. }
  1534. break;
  1535. case VT_VECTOR | VT_CF:
  1536. fSame = ( pvar1->caclipdata.cElems == pvar2->caclipdata.cElems );
  1537. if (fSame)
  1538. {
  1539. for (i = 0; i < pvar1->caclipdata.cElems; i++)
  1540. {
  1541. fSame = _Compare_VT_CF(
  1542. &pvar1->caclipdata.pElems[i],
  1543. &pvar2->caclipdata.pElems[i]);
  1544. if (!fSame)
  1545. {
  1546. break;
  1547. }
  1548. }
  1549. }
  1550. break;
  1551. case VT_VECTOR | VT_BSTR:
  1552. fSame = ( pvar1->cabstr.cElems == pvar2->cabstr.cElems );
  1553. if (fSame)
  1554. {
  1555. for (i = 0; i < pvar1->cabstr.cElems; i++)
  1556. {
  1557. if (pvar1->cabstr.pElems[i] != NULL &&
  1558. pvar2->cabstr.pElems[i] != NULL)
  1559. {
  1560. fSame = ( BSTRLEN(pvar1->cabstr.pElems[i])
  1561. ==
  1562. BSTRLEN(pvar2->cabstr.pElems[i]) );
  1563. if (fSame)
  1564. {
  1565. fSame = memcmp(
  1566. pvar1->cabstr.pElems[i],
  1567. pvar2->cabstr.pElems[i],
  1568. BSTRLEN(pvar1->cabstr.pElems[i])) == 0;
  1569. }
  1570. }
  1571. else
  1572. {
  1573. fSame = pvar1->cabstr.pElems[i] == pvar2->cabstr.pElems[i];
  1574. }
  1575. if (!fSame)
  1576. {
  1577. break;
  1578. }
  1579. }
  1580. }
  1581. break;
  1582. case VT_VECTOR | VT_LPSTR:
  1583. fSame = ( pvar1->calpstr.cElems == pvar2->calpstr.cElems );
  1584. if (fSame)
  1585. {
  1586. for (i = 0; i < pvar1->calpstr.cElems; i++)
  1587. {
  1588. if (pvar1->calpstr.pElems[i] != NULL &&
  1589. pvar2->calpstr.pElems[i] != NULL)
  1590. {
  1591. fSame = strcmp(
  1592. pvar1->calpstr.pElems[i],
  1593. pvar2->calpstr.pElems[i]) == 0;
  1594. }
  1595. else
  1596. {
  1597. fSame = pvar1->calpstr.pElems[i] ==
  1598. pvar2->calpstr.pElems[i];
  1599. }
  1600. if (!fSame)
  1601. {
  1602. break;
  1603. }
  1604. }
  1605. }
  1606. break;
  1607. case VT_VECTOR | VT_LPWSTR:
  1608. fSame = ( pvar1->calpwstr.cElems == pvar2->calpwstr.cElems );
  1609. if (fSame)
  1610. {
  1611. for (i = 0; i < pvar1->calpwstr.cElems; i++)
  1612. {
  1613. if (pvar1->calpwstr.pElems[i] != NULL &&
  1614. pvar2->calpwstr.pElems[i] != NULL)
  1615. {
  1616. fSame = Prop_wcscmp(
  1617. pvar1->calpwstr.pElems[i],
  1618. pvar2->calpwstr.pElems[i]) == 0;
  1619. }
  1620. else
  1621. {
  1622. fSame = pvar1->calpwstr.pElems[i] ==
  1623. pvar2->calpwstr.pElems[i];
  1624. }
  1625. if (!fSame)
  1626. {
  1627. break;
  1628. }
  1629. }
  1630. }
  1631. break;
  1632. case VT_VECTOR | VT_VARIANT:
  1633. fSame = ( pvar1->capropvar.cElems == pvar2->capropvar.cElems );
  1634. if (fSame)
  1635. {
  1636. for (i = 0; i < pvar1->capropvar.cElems; i++)
  1637. {
  1638. fSame = PrCompareVariants(
  1639. CodePage,
  1640. &pvar1->capropvar.pElems[i],
  1641. &pvar2->capropvar.pElems[i]);
  1642. if (!fSame)
  1643. {
  1644. break;
  1645. }
  1646. }
  1647. }
  1648. break;
  1649. default:
  1650. PROPASSERT(!"Invalid type for PROPVARIANT Comparison");
  1651. fSame = FALSE;
  1652. break;
  1653. }
  1654. return(fSame);
  1655. }